diff --git a/.gitignore b/.gitignore index 328e239ff..fb459f849 100644 --- a/.gitignore +++ b/.gitignore @@ -14,20 +14,25 @@ src/src.kdev4 *.[cr]nx # data directories in examples -examples/*/ +examples/* examples/*.gz examples/*.bz2 # to be fixed in future release examples/DE.430 #symbolic links to yaml files (as yml) examples/*.yml -#symbolic link to executable +#symbolic link to executables examples/pea +examples/ginan # pod output records examples/*.out +examples/examples.zip +examples/GinanYamlInspector.html + +Docs/ # ignore cmake build and ide files -src/*.kdev4 +*.kdev4 src/.kdev/ src/build/ bin/ @@ -67,10 +72,21 @@ docs/html/ docs/DoxygenLayout.xml docs/Doxyfile +Docs/codeDocs/* + +Docs/*.html + +*.kate-swp + + + *.swp # Node artifact files node_modules/ dist/ +package-lock.json +package.json + # Compiled Java class files *.class @@ -119,7 +135,7 @@ Thumbs.db # vscode settings .vscode/ - +build/ # visual studio file/settings src/CMakeSettings.json src/CMakeFiles/ @@ -129,3 +145,7 @@ src/CMakeFiles/ src/cpp/pea/peaCommitVersion.h src/build/ src/cmake-* +src/build* + +# folder for test files (shouldn't be uploaded) +scratch diff --git a/CHANGELOG.md b/CHANGELOG.md index 70ee2562f..a97339a37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +# [2.0.0] 2023-05-18 +### Added +### Changed +Many changes for v2.0, will be fully documented with v2.1 ... +### Fixed +### Deprecated +### Removed +### Security + # [1.5.4] 2023-05-07 ### Added New dependency - Ginan relies on the python gnssanalysis tools (installable by pip) for running most scripts, although it is not required to run the main products themselves. diff --git a/README.md b/README.md index abcccd17d..9300ce164 100755 --- a/README.md +++ b/README.md @@ -5,10 +5,11 @@ : Note - this file is executable. \ : You can run it by saving the raw markdown to disk, then `` chmod +x README.md``, then ``./README.md`` \ : It will execute all of the code blocks that finish with the `` :<<'```executable' `` tag. \ -: This script will install all dependencies, clone the Ginan repo into the current directory and build the Ginan toolkit. +: This script will install all dependencies, and clone the Ginan repo into the current directory \(if required\) and build the Ginan toolkit. \ +: To check out the stable v1 branch from Github, append -b ginan-v1 to the clone command below to get the v1 branch source. -#### `Ginan v1.5.4 release` +#### `Ginan v2.0-beta release` ## Overview @@ -46,17 +47,23 @@ The software consists of three main components: Ginan is supported on the following platforms -* Linux: tested on Ubuntu 18.04 and 20.04 +* Linux: tested on Ubuntu 18.04 and 20.04 and 22.04 * MacOS: tested on 10.15 (x86) * Windows: via docker or WSL on Windows 10 and above *** +NB If you are using Ubuntu 22.04 and gcc11, you will need to make the the following adjustments (applies to WSL as well): +* Boost 1.74.0 +* Mongo-c-driver 1.21.2 +* Mongocxx 3.7.0 +* manual adjustment of CMakeLists.txt to reflect new boost version +*** ## Using Ginan with Docker You can quickly download a ready-to-run Ginan environment using docker by running: - docker run -it -v /data:/data gnssanalysis/ginan:v1.5.4 bash + docker run -it -v /data:/data gnssanalysis/ginan:v2.0-beta bash This command connects the `/data` directory on the host (your pc), with the `/data` directory in the container, to allow file access between the two systems, and opens a command line (`bash`) for executing commands. @@ -96,7 +103,7 @@ sudo apt upgrade -y sudo apt install -y git gobjc gobjc++ gfortran libopenblas-dev openssl curl net-tools openssh-server cmake make libssl1.0-dev wget sudo python3 software-properties-common -pip3 install wheel pandas boto3 unlzw tdqm scipy +sudo -H pip3 install wheel pandas boto3 unlzw tdqm scipy gnssanalysis :<<'```executable' ``` @@ -246,7 +253,6 @@ sudo rm -rf mongo-c-driver-1.17.1 mongo-c-driver-1.17.1.tar.gz mongo-cxx-drive :<<'```executable' ``` - ### MongoDB (PEA, optional) Using the mongo database is optional, but is needed for use of the realtime plotting and statistics available through the `GinanEDA` @@ -313,16 +319,23 @@ sudo pip install gnssanalysis You can download Ginan source from github using git clone: + ```executable +if [ ! -d "../ginan" -o ! -f CHANGELOG.md ] +then cd $dir + git clone https://github.com/GeoscienceAustralia/ginan.git cd ginan +else +echo "already in a checkout directory, no need to download again" +fi :<<'```executable' ``` -Then download all of the example data using the python script provided: +Then download all of the example data using the python script provided (requires `gnssanalysis`): ```executable python3 scripts/download_examples.py diff --git a/src/cpp/orbprop/forceModels.cpp b/archived/forceModels.cpp similarity index 52% rename from src/cpp/orbprop/forceModels.cpp rename to archived/forceModels.cpp index 041cef9b9..31086c4a8 100644 --- a/src/cpp/orbprop/forceModels.cpp +++ b/archived/forceModels.cpp @@ -9,7 +9,6 @@ using namespace boost::numeric::odeint; #include "eigenIncluder.hpp" #include "forceModels.hpp" -#include "streamTrace.hpp" #include "instrument.hpp" #include "navigation.hpp" #include "satRefSys.hpp" @@ -18,8 +17,10 @@ using namespace boost::numeric::odeint; #include "gravity.hpp" #include "common.hpp" #include "jplEph.hpp" +#include "trace.hpp" #include "tides.hpp" #include "enums.h" +#include "coordinates.hpp" typedef Eigen::Vector VectorXSTMS; //todo aaron, delete this @@ -27,33 +28,6 @@ map orbitPropagatorMap; GravityModel OrbitPropagator::gravityModel; -/* Frac: Gives the fractional part of a number -*/ -double Frac (double x) -{ - return x - floor(x); -} - -/* Computes the Sun's geocentric position using a low precision analytical series -*/ -Vector3d SunPos( - double mjdTT) ///< Terrestrial time: modified Julian date -{ - /* Constants - */ - const double eps = 23.43929111 * D2R; // Obliquity of J2000 ecliptic - const double T = (mjdTT - mjdJ2000) / 36525.0; // Julian cent. since J2000 - - /* Mean anomaly, ecliptic longitude and radius - */ - double M = PI2 * Frac ( 0.9931267 + 99.9973583 * T); // [rad] - double L = PI2 * Frac ( 0.7859444 + M/PI2 + ( 6892 * sin(M) + 72 * sin(2 * M) ) / 1296e3 ); // [rad] - double R = 149.619e9 - 2.499e9 * cos(M) - 0.021e9 * cos(2 * M); // [m] - - /* Solar position vector [m] with respect to the mean equator and equinox of J2000 (EME2000, ICRF) - */ - return R_x(-eps) * R * Vector3d(cos(L), sin(L), 0); -} /* Computes the fractional illumination of a spacecraft in the vicinity of the Earth assuming a cylindrical shadow model * @@ -214,46 +188,8 @@ void OrbitPropagator::update( thirdBodyPositionMap[body] = thirdBodyPos; } - - //update reference frame matrices - eci2ecef_sofa(mjdUTC, iers, mECI2ECEF, mdECI2ECEF); - - //update egm coefficients for tides - gravityModel.correctEgmCoefficients(std::cout, mjdUTC, erpv, mECI2ECEF); } -Vector3d OrbitVEQPropagator::calculateAccelNGradient( - Trace& trace, ///< Trace to output to (similar to cout) - const Vector3d& rSat, ///< Inertial position of satellite (m) - const Vector3d& vSat, ///< Inertial velocity of satellite (m/s) - Matrix3d& mGradient, ///< Gradient (G=da/dr) in the ICRF/J2000 system - Vector3d& dadCr, ///< Partials of acceleration w.r.t. to the solar radiation coefficient - const Matrix3d& mECI2ECEF) ///< Transformation matrix from ECI coordinate to ECEF -{ -// bool bVarEq = true; -// Vector3d earthGravityAcc = gravityModel.centralBodyGravityAcc(trace, mMJDUTC, mERPv, rSat, mECI2ECEF, bVarEq); -// Vector3d drSat; -// const double dinc = 1; // Position increment [m] -// Vector3d daSat; -// -// /* Gradient -// */ -// for (int i = 0; i < 3; i++) -// { -// drSat = Vector3d::Zero(); -// drSat(i) = dinc; // Set offset in i-th component of the position vector -// daSat = gravityModel.centralBodyGravityAcc (trace, mMJDUTC, mERPv, rSat + drSat, mECI2ECEF, bVarEq) - earthGravityAcc; // Acceleration difference -// mGradient.col(i) = daSat / dinc; // Derivative with respect to i-th component -// } -// -// /* Radiation pressure coefficient partials -// */ -// double mjdTT = mIERS.TT_UTC(mMJDUTC) / 86400.0 + mMJDUTC; -// solarRadPressure.mSRPPara.srpCoef = 1; -// dadCr = solarRadPressure.directSolarRadiationAcc(trace, mjdTT, rSat); - Vector3d acc; - return acc; -} /** Propagate orbits by ODE functor. * Used by RK - input is a 6 element inertial state and time, and output is the derivative of the state at the provided time. * This function requires the update function to be called first to set planetary ephemerides, erp values, etc. @@ -273,30 +209,7 @@ void OrbitPropagator::operator ()( double mjdUTC = mjdUTCinSec / 86400; - // double erpv[4] = {}; - // geterp_from_utc(&nav.erp, mjdUTC, erpv); - // double leapSec = nav.leaps; - // double dUT1_UTC = erpv[2]; - // double dUTC_TAI = -(19 + leapSec); - // double xp = erpv[0]; - // double yp = erpv[1]; - // double lod = erpv[3]; - // clIERS iersInstance; - // iersInstance.Set(dUT1_UTC, dUTC_TAI, xp, yp, lod); - // double mjdTT = mjdUTC + iersInstance.TT_UTC(mjdUTC) / 86400; - - - // Matrix3d mECI2ECEF = Matrix3d::Identity(); - // Matrix3d mdECI2ECEF = Matrix3d::Identity(); - // eci2ecef_sofa(mjdUTC, iersInstance, mECI2ECEF, mdECI2ECEF); - // std::cout << "mECI2ECEF: " << mjdUTC << " " << std::setw(14) << mECI2ECEF << std::endl; - // Vector3d aSat = calculateAcceleration(std::cout, mjdTT, rSat, vSat, mECI2ECEF, egm.cmn, egm.smn, 12, 12); - // std::cout << "Accelerations: " << mjdUTC << " " << std::setw(14) << aSat.transpose() << std::endl; - - - // std::cout << "mECI2ECEF: " << orbitProp.mMJDUTC << " " << std::setw(14) << mECI2ECEF << std::endl; - //calculate acceleration components Vector3d aSat = Vector3d::Zero(); @@ -364,7 +277,7 @@ void OrbitPropagator::operator ()( dInertialState.tail(3) = aSat; - std::cout << "\n" << (aSat.dot(rSat.normalized())); + // std::cout << "\n" << (aSat.dot(rSat.normalized())); } /** Observer, prints time and state when called (during integration) @@ -379,98 +292,14 @@ void obsvrSatMotion( // << std::setw(14) << x[3] << std::setw(14) << x[4] << std::setw(14) << x[5] << std::setw(14) << std::endl; } -/** ODE of variational equation to be solved, i.e. the derivative of the state vector and the state transition matrix -* -*/ -// struct VarEqPropagator -// { -// void operator()( -// const VectorXSTMS& rvPhiS, -// VectorXSTMS& drvPhiSdt, -// const double mjdUTCinSec) -// { -// double mjdUTC = mjdUTCinSec / 86400; // Time -// -// Vector3d rSat = rvPhiS.segment(0, 3); // Position components -// Vector3d vSat = rvPhiS.segment(3, 3); // Velocity components -// -// MatrixXd Phi = MatrixXd::Identity(6, 6); // State transition matrix -// // for (int j = 0; j < 6; j++) -// // { -// // Phi.col(j) = rvPhiS.segment(6 * (j + 1), 6); -// // } -// -// MatrixXd S = MatrixXd::Zero(6, 1); // Sensitivity matrix -// // for (int j = 0; j < 1; j++) -// // { -// // S.col(j) = rvPhiS.segment(6 * (j + 7), 6); -// // } -// -// Matrix3d mECI2ECEF = Matrix3d::Identity(); -// Matrix3d mdECI2ECEF = Matrix3d::Identity(); -// updPropagator(mjdUTC); //time epoch inside the integrator -// eci2ecef_sofa(mjdUTC, mIERS, mECI2ECEF, mdECI2ECEF); -// -// Matrix3d mGradient; -// Vector3d dadCr; -// Vector3d aSat = calculateAccelNGradient(std::cout, rSat, vSat, mGradient, dadCr, mECI2ECEF); -// -// /* Time derivative of state transition matrix -// * -// */ -// MatrixXd dfdy = MatrixXd::Zero(6, 6); -// for (int i = 0; i < 3; i++) -// for (int j = 0; j < 3; j++) -// { -// dfdy(i, j ) = 0; // dv/dr(i, j) -// dfdy(i + 3, j ) = mGradient(i, j); // da/dr(i, j) -// dfdy(i, j + 3) = ( i == j ? 1 : 0 ); // dv/dv(i, j) -// dfdy(i + 3, j + 3) = 0; // da/dv(i, j) -// } -// MatrixXd dPhi = dfdy * Phi; // Time derivative of state transition matrix -// -// -// /* Time derivative of sensitivity matrix -// * -// */ -// MatrixXd dfdp(6, 1); -// for (int i = 0; i < 3; i++) -// { -// dfdp(i ) = 0; // dv/dCr(i) -// dfdp(i + 3) = dadCr(i); // da/dCr(i) -// } -// -// MatrixXd dS = MatrixXd::Zero(6, 1); -// dS = dfdy * S + dfdp; -// -// /* Derivative of combined state vector and state transition matrix -// * -// */ -// for (int i = 0; i < 3; i++) -// { -// drvPhiSdt(i ) = vSat(i); // dr/dt(i) -// drvPhiSdt(i + 3) = aSat(i); // dv/dt(i) -// } -// -// for (int i = 0; i < 6; i++) -// for (int j = 0; j < 6; j++) -// { -// drvPhiSdt(6 * (j + 1) + i ) = dPhi(i, j); // dPhi/dt(i,j) -// } -// -// for (int i = 0; i < 6; i++) -// for (int j = 6; j < 7; j++) -// { -// drvPhiSdt(6 * (j + 1) + i) = dS(i, j - 6); // dS/dt(i,j) -// } -// } -// }; void updateOrbits( Trace& trace, KFState& kfState, GTime time) { + auto& dd = orbitPropagatorMap ; + { //get current inertial states from the kfState for (auto& [kfKey, index] : kfState.kfIndexMap) @@ -502,24 +331,28 @@ void updateOrbits( } } + + + // New function to update; + for (auto& [satId, orbitPropagator] : orbitPropagatorMap) { SatSys Sat; Sat.fromHash(satId); - double dt = time - kfState.time; //time indicates the current epoch, kfState.time indicates the last epoch + orbitPropagator.dt = time - kfState.time; //time indicates the current epoch, kfState.time indicates the last epoch double t0 = gpst2mjd(kfState.time) * 86400; double t1 = gpst2mjd(time) * 86400; - if (dt == 0) + if (orbitPropagator.dt == 0) { return; } // orbitPropagator.stateTime = time; - VectorXd oldState = orbitPropagator.inertialState; + orbitPropagator.oldState = orbitPropagator.inertialState; double t_mid = (t0 + t1) / 2 / 86400; @@ -539,14 +372,12 @@ void updateOrbits( if (acsConfig.forceModels.ode_integrator == +E_Integrator::RKF78) { typedef runge_kutta_fehlberg78 rkf78; // Error stepper, used to create the controlled stepper -// typedef controlled_runge_kutta ctrl_rkf78; // Controlled stepper: it's built on an error stepper and allows us to have the output at each internally defined (refined) timestep, via integrate_adaptive call double errAbs = 1.0e-16; // Error bounds double errRel = 1.0e-13; - //integrate_adaptive(ctrl_rkf78(), OrbitPropagator(), rvECI, t0, t1, dt); auto controller = make_controlled(errAbs, errRel, rkf78()); - integrate_adaptive(controller, orbitPropagator, orbitPropagator.inertialState, t0, t1, dt); + integrate_adaptive(controller, orbitPropagator, orbitPropagator.inertialState, t0, t1, orbitPropagator.dt); } @@ -554,88 +385,26 @@ void updateOrbits( std::cout << "ICRF coordinates after the orbital propagation step: " << std::setprecision(14) << orbitPropagator.inertialState.transpose() << std::endl; - // VectorXSTMS rvPhiS = kfState.xSTMSM; - - // if (0) - // { - // // typedef runge_kutta4 rk4; - // // integrate_const(rk4(), odeVarEquation, rvPhiS, t0, t1, dt); - // integrate(VarEqPropagator(), rvPhiS, t0, t1, dt); - // // typedef runge_kutta_dopri5 rk5; - // // typedef controlled_runge_kutta ctrl_rk5; - // // double errAbs = 1.0e-10; // Error bounds - // // double errRel = 1.0e-8; - // // integrate_adaptive(ctrl_rk5(), odeVarEquation, rvPhiS, t0, t1, dt); - // - // std::cout << "ICRF coordinates before the variatioanal equation propagation: " << std::setprecision(14) << rvPhiS.head(3).transpose() << std::endl; - // kfState.xSTMSM = rvPhiS; - // } - - // kfState.x = rvECI; - // kfState.time = time; - - - // ECI to ECEF transformation - - // double erpv[4] = {}; - // geterp(&nav.erp, time + dt, erpv); - // double mjdUTC = gpst2mjd(time + dt); - // double leapSec = nav.leaps; - // double dUT1_UTC = erpv[2]; - // double dUTC_TAI = -(19 + orbitProp.mLeapSec); - // double xp = erpv[0]; - // double yp = erpv[1]; - // double lod = erpv[3]; - // clIERS iersInstance; - // iersInstance.Set(dUT1_UTC, dUTC_TAI, xp, yp, lod); - // double mjdTT = mjdUTC + iersInstance.TT_UTC(mjdUTC) / 86400; - // Matrix3d mECI2ECEF = Matrix3d::Identity(); - // Matrix3d mdECI2ECEF = Matrix3d::Identity(); - // Vector6d rvECEF; - // eci2ecefVec_sofa(mjdUTC, iersInstance, rvECI, rvECEF); - // std::cout << "ITRF coordinates: " << std::endl << std::setprecision(14) << rvECEF.transpose() << std::endl; - - - // Matrix3d mECI2ECEF = Matrix3d::Identity(); - // Matrix3d mdECI2ECEF = Matrix3d::Identity(); + + orbitPropagator.update(gpst2mjd(time));//time epoch after the orbital propagation; - + + } + + + + for (auto& [satId, orbitPropagator] : orbitPropagatorMap) + { + SatSys Sat; + Sat.fromHash(satId); + Vector3d rECI = orbitPropagator.inertialState.head(3); Vector3d vECI = orbitPropagator.inertialState.tail(3); -// std::cout -// << "ICRF coordinates after the orbital propagation step: " -// << std::setprecision(14) << rECI.transpose() << " " << vECI.transpose() << std::endl; - - Vector3d rECEF2; - Vector3d vECEF2; - eci2ecef_sofa(orbitPropagator.mMJDUTC, orbitPropagator.iers, rECI, vECI, rECEF2, vECEF2); -// std::cout -// << "ITRF coordinates after the orbital propagation step: " -// << std::setprecision(14) << rECEF2.transpose() << " " << vECEF2.transpose() << std::endl; - -// std::ofstream fileOPResults("./ex01/OPResults.txt", std::ios_base::app | std::ios_base::in); -// if (!fileOPResults) -// { -// std::cout << "Error openinng results file!\n"; -// return; -// } - -// fileOPResults << std::setprecision(6) << std::fixed; - - - // fileOPResults << setw(16) << orbitProp.mMJDUTC << setw(16) << rvECI.transpose() << setw(16) << rvECEF2.transpose() << endl; -// fileOPResults << std::setw(16) << orbitPropagator.mMJDUTC << " " << rECEF2.transpose() << vECEF2.transpose() << std::endl; - - //get the change in state ready for use in the kalman filter's state transition -// orbitPropagator.stateDelta = orbitPropagator.inertialState - oldState; - - //get the noise in the state delta according to uncertainty in the inputs, and propagation uncertainty for use in the filters' covariance transition -// orbitPropagator.stateDeltaNoise = Matrix6d::Zero(); Matrix6d stateTransition = Matrix6d::Identity(); - stateTransition.topRightCorner(3,3) = Matrix3d::Identity() * dt; + stateTransition.topRightCorner(3,3) = Matrix3d::Identity() * orbitPropagator.dt; - Vector6d transitionedState = stateTransition * oldState; + Vector6d transitionedState = stateTransition * orbitPropagator.oldState; Vector6d missingDynamics = orbitPropagator.inertialState - transitionedState; diff --git a/src/cpp/orbprop/forceModels.hpp b/archived/forceModels.hpp similarity index 98% rename from src/cpp/orbprop/forceModels.hpp rename to archived/forceModels.hpp index f43aff132..b7a6a6911 100644 --- a/src/cpp/orbprop/forceModels.hpp +++ b/archived/forceModels.hpp @@ -9,13 +9,13 @@ using std::string; using std::map; #include "eigenIncluder.hpp" -#include "streamTrace.hpp" #include "satRefSys.hpp" #include "acsConfig.hpp" #include "gravity.hpp" #include "algebra.hpp" #include "jplEph.hpp" #include "common.hpp" +#include "trace.hpp" #include "enums.h" struct SRPPara @@ -81,6 +81,9 @@ struct OrbitPropagator double mMJDUTC; ///< UTC modified Julian date Vector6d inertialState; + VectorXd oldState; + + double dt; // Vector6d stateDelta; // Matrix6d stateDeltaNoise; diff --git a/src/cpp/orbprop/gravity.cpp b/archived/gravity.cpp similarity index 99% rename from src/cpp/orbprop/gravity.cpp rename to archived/gravity.cpp index 9f6ad6a92..9d2af6a28 100644 --- a/src/cpp/orbprop/gravity.cpp +++ b/archived/gravity.cpp @@ -9,7 +9,7 @@ #include "gravity.hpp" #include "jplEph.hpp" #include "common.hpp" -#include "sofa.hpp" +#include "sofa.h" Vector3d CalcPolarAngles( diff --git a/src/cpp/orbprop/gravity.hpp b/archived/gravity.hpp similarity index 99% rename from src/cpp/orbprop/gravity.hpp rename to archived/gravity.hpp index 78f7f42ec..d7944418c 100644 --- a/src/cpp/orbprop/gravity.hpp +++ b/archived/gravity.hpp @@ -2,8 +2,8 @@ #define __GRAVITY_HPP__ #include "eigenIncluder.hpp" -#include "streamTrace.hpp" #include "jplEph.hpp" +#include "trace.hpp" #include "enums.h" #include "erp.hpp" diff --git a/archived/mainPod.cpp b/archived/mainPod.cpp new file mode 100644 index 000000000..ad47c9d01 --- /dev/null +++ b/archived/mainPod.cpp @@ -0,0 +1,177 @@ +// +// Created by Sébastien Allgeyer on 11/3/22. +// +#include +#include +#include +#include +#include // odeint function definitions + +using namespace boost::numeric::odeint; + + +#include "mainPod.hpp" +#include "orbit.hpp" +#include "math_tools.hpp" +#include "coordinates.hpp" +#include "jpl_eph.hpp" +#include "jplEph.hpp" +#include "constants.hpp" +#include "iers2010.hpp" + +atomic mainPod::pInstance {nullptr}; +mutex mainPod::m_; + +mainPod* mainPod::Instance(int argc, char* argv[]) { + if (pInstance == nullptr){ + lock_guard lock(m_); + if (pInstance == nullptr){ + pInstance = new mainPod(argc, argv); + } + } + return pInstance; +} + +void mainPod::init(int argv, char **argc) { + // orbit_data.egm = StaticField("EGM2008.gfc", 15); + orbit_data.egm = StaticField("GOCO05s.gfc",15); + orbit_data.tide = OceanTide("fes2004_Cnm-Snm.dat", 15); + orbit_data.startTime = GTime(boost::posix_time::time_from_string("2007-04-12 00:00:00")); + orbit_data.jplEph_ptr = (struct jpl_eph_data*)jpl_init_ephemeris("DE436.1950.2050", nullptr, nullptr); + readerp("igs96p02.erp", orbit_data.erpData); + currentTime = orbit_data.startTime; + currentTime_d = gpst2mjd(currentTime)*86400.0; + satellite["G01"] = stateSV(); + satellite["G02"] = stateSV(); + //From sp3 test file. + satellite["G01"].posI << 1120.484500, 15079.297000, 22047.746500 ; + satellite["G01"].velI << -37784.29000, -5001.870000 , 5331.295000 ; + + satellite["G02"].posI << -4632.723000, -25495.815500 , 6219.951000; + satellite["G02"].velI << 24185.510000, 3236.255000, 29921.925000; + + + Matrix3d U, dU; + ERPValues erps; + geterp(orbit_data.erpData, currentTime, erps); + eci2ecef_sofa(gpst2mjd(currentTime), erps ,U, dU); + BOOST_LOG_TRIVIAL(debug) << "\n"<< U << "\n" << dU ; + eci2ecef_sofa_old(gpst2mjd(currentTime), erps ,U, dU); + BOOST_LOG_TRIVIAL(debug) << "\n\n" << U << "\n" << dU ; + // exit(0); + + // BOOST_LOG_TRIVIAL(info) << "inittial pos"; + for (auto & [name, sat]: satellite) { + sat.posI *= 1000.0 ; // km -> m + sat.velI /= 10.0; // dm/s-> m/s + sat.posVelI.head(3) = sat.posI; + sat.posVelI.tail(3) = sat.velI; + // BOOST_LOG_TRIVIAL(info) << name << " " << sat.posVelI.transpose(); + sat.posE = U * sat.posI; + sat.velE = U * sat.velI + dU * sat.posI; + } + + +} + + +void mainPod::oncePerEpoch() +{ + /** + * Generate the eci 2 ecef + * */ + //Eigen::Matrix3d U, dU; + //eci2ecef_sofa(gpst2mjd(currentTime), U,dU); + + /** + * Generate the position of the celestial bodies + * This is the first step as the positin of Earth and Moon are required for the solidEarth tides. + */ + planets.clear(); + for (int i = 0; i < E_ThirdBody::_size(); i++) + { + E_ThirdBody body = E_ThirdBody::_values()[i]; + string bodyName = E_ThirdBody::_names()[i]; + Vector3d pos; + Vector3d vel; + jplEphPos(orbit_data.jplEph_ptr, gpst2mjd(currentTime) +(33+32.186)/86400.0+ JD2MJD, body, pos, &vel); + Vector6d posvel; + posvel.head(3) = pos; + posvel.tail(3) = vel; + planets[body] = posvel; + } + + + /** + * Generate the spherical harmonic field + */ + + +} + +void mainPod::oncePerEpochPerSV() +{ + /** + * Acceleration from the spherical harmonics + */ + + /** + * Acceleration from the celestial bodies + */ + + /** + * Solar radiation pressure + */ + + /** + * Relativistic effects + */ + +} +void mainPod::run() { +// typedef runge_kutta_fehlberg78 rkf78; +// typedef controlled_runge_kutta ctrl_rkf78; + +// double errAbs = 1.0e-16; +// double errRel = 1.0e-13; + +// auto controller = make_controlled(errAbs, errRel, rkf78() ); + + runge_kutta4< Vector6d > stepper; + +// BOOST_LOG_TRIVIAL(info) << "time step MJD " << gpst2mjd(currentTime) << " ... " << gpst2mjd(orbit_data.startTime); +// currentTime = currentTime + 86400.0; +// BOOST_LOG_TRIVIAL(info) << "time step MJD " << gpst2mjd(currentTime) << " ... " << gpst2mjd(orbit_data.startTime); + // Get satellite independant values + oncePerEpoch(); + for (auto & [name, sat]: satellite) + { + Vector6d old = sat.posVelI; + double dt = 5.0; + stepper.do_step(sat, sat.posVelI, currentTime_d, dt); + // BOOST_LOG_TRIVIAL(debug) << "CHANGES "<< (old.head(3)-sat.posVelI.head(3)).norm() ; + sat.posI = sat.posVelI.head(3); + sat.velI = sat.posVelI.tail(3); + } +// oncePerEpochPerSV(); + currentTime += 5.0; + currentTime_d += 5.0; + Matrix3d U, dU; + ERPValues erps; + geterp(orbit_data.erpData, currentTime, erps); + // BOOST_LOG_TRIVIAL(debug) << "Erps " << erps.xp; + eci2ecef_sofa(gpst2mjd(currentTime), erps ,U, dU); + // BOOST_LOG_TRIVIAL(debug) << (U.transpose() - U.inverse()).norm() ; + // BOOST_LOG_TRIVIAL(debug) << (U.transpose().array() - U.inverse().array())/U.transpose().array() ; + + for (auto & [name, sat]: satellite) + { + sat.posE = U * sat.posI; + sat.velE = U * sat.velI + dU * sat.posI; + // BOOST_LOG_TRIVIAL(info) << name << " ** " << sat.posE.transpose() << " -- " << sat.posI.transpose(); + } + + + + +} \ No newline at end of file diff --git a/archived/mainPod.hpp b/archived/mainPod.hpp new file mode 100644 index 000000000..f0e9cbf48 --- /dev/null +++ b/archived/mainPod.hpp @@ -0,0 +1,43 @@ +// +// Created by Sébastien Allgeyer on 11/3/22. +// + +#ifndef CODE_TESTING_MAINPOD_HPP +#define CODE_TESTING_MAINPOD_HPP + +#include +#include +#include "orbit.hpp" +#include "gTime.hpp" +#include "enums.h" +#include "eigenIncluder.hpp" +#include "stateSV.hpp" + +using namespace std; + +const E_ThirdBody orbiting = E_ThirdBody::EARTH; + +struct mainPod { +public: + static mainPod* Instance(int argc, char * argv[]); + static mainPod* Instance(){ return pInstance;}; + orb_t orbit_data; + void run(); + std::map planets; + std::map satellite; + GTime currentTime; + double currentTime_d; + +private: + mainPod(int argc, char * argv[]) {init( argc, argv);}; + void init(int argc, char* argv[]); + static atomic pInstance; + static mutex m_; + void oncePerEpoch(); + void oncePerEpochPerSV(); + + +}; + + +#endif //CODE_TESTING_MAINPOD_HPP diff --git a/src/cpp/common/ntripSourceTable.cpp b/archived/ntripSourceTable.cpp similarity index 100% rename from src/cpp/common/ntripSourceTable.cpp rename to archived/ntripSourceTable.cpp diff --git a/src/cpp/common/ntripSourceTable.hpp b/archived/ntripSourceTable.hpp similarity index 100% rename from src/cpp/common/ntripSourceTable.hpp rename to archived/ntripSourceTable.hpp diff --git a/archived/oceanTide.cpp b/archived/oceanTide.cpp new file mode 100644 index 000000000..e4f8d31b9 --- /dev/null +++ b/archived/oceanTide.cpp @@ -0,0 +1,157 @@ +/** + * @file oceanTide.cpp + * @author Sébastien Allgeyer (sallgeyer@frontiersi.com.au) + * @brief + * @version 0.1 + * @date 2022-03-23 + * @ingroup orbprop + * + * @copyright Copyright (c) 2022 + * + */ + +#include "oceanTide.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sofa.h" + +OceanTide::OceanTide(std::string filename_, int degmax_): filename(filename_), degMax(degmax_) +{ + readocetide(); + summary(); +}; + +void OceanTide::readocetide() { + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " Reading OCE" << __PRETTY_FUNCTION__ ; + std::ifstream infile(filename); + std::string wave_, doodson_, line; + int n_,m_; + double cnmp_, snmp_, cnmm_, snmm_; + /// Quick and dirty skip the 4 lines of header (@todo need to do better) + for (int i=0; i<4; i++) + std::getline(infile, line); + while (std::getline(infile, line)) + { +// std::cout << line << std::endl; + std::istringstream iss(line); + iss >> doodson_ >> wave_ >> n_ >> m_ >> cnmp_ >> snmp_ >> cnmm_ >> snmm_; + // cout << doodson_ << wave_ << "\n"; + if (n_ <= degMax) { + bool isnew = true; +// std::cout << wave_ << std::endl; + for (auto & wave: TidalWaves) { + // BOOST_LOG_TRIVIAL(debug) << wave.WaveName.compare(wave_) << " " << wave.WaveName << " .vs. " << wave_ ; + if (wave.WaveName.compare(wave_) == 0) { + wave.CnmP(n_, m_) = cnmp_; + wave.SnmP(n_, m_) = snmp_; + wave.CnmM(n_, m_) = cnmm_; + wave.SnmM(n_, m_) = snmm_; + isnew = false; + } + + } + if (isnew) { + TidalWaves.push_back(TidalWave(wave_, doodson_, degMax)); + TidalWaves.back().CnmP(n_, m_) = cnmp_; + TidalWaves.back().CnmM(n_, m_) = cnmm_; + TidalWaves.back().SnmP(n_, m_) = snmp_; + TidalWaves.back().SnmM(n_, m_) = snmm_; + } + } + } + +} + +void OceanTide::summary() { + BOOST_LOG_TRIVIAL(debug) << "write summary here"; +} + + +TidalWave::TidalWave(std::string name, std::string darw, int degmax) : WaveName(name) +{ + BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " Creating new wave " << WaveName << " degmax " << degmax; + size_t dot = darw.find("."); + Doodson = Eigen::Array::Zero(6); + Doodson(5) = std::stoi(darw.substr(dot+3, 1)); + Doodson(4) = std::stoi(darw.substr(dot+2, 1)); + Doodson(3) = std::stoi(darw.substr(dot+1, 1)); + if (darw.length()>=5) + Doodson(2) = std::stoi(darw.substr(dot-1, 1)); + if (darw.length()>=6) + Doodson(1) = std::stoi(darw.substr(dot-2, 1)); + if (darw.length()>=7) + Doodson(0) = std::stoi(darw.substr(dot-3, 1)); + for (int i=1; i<6; i++) + Doodson(i) -= 5; + BOOST_LOG_TRIVIAL(debug) << "\t" << Doodson.transpose(); + + CnmM = Eigen::MatrixXd::Zero(degmax+1, degmax+1); + CnmP = Eigen::MatrixXd::Zero(degmax+1, degmax+1); + SnmM = Eigen::MatrixXd::Zero(degmax+1, degmax+1); + SnmP = Eigen::MatrixXd::Zero(degmax+1, degmax+1); + +} + +/** + * @brief Generates the Beta angles from the given a modified julian day. + * @todo implement the ut1_utc. + */ +void OceanTide::setBeta(double mjd)//, double ut1_utc) +{ + + double jd = mjd + 2400000.5; + double teph = ( jd - 2451545.0 ) / 36525.0; + Eigen::Array fundArguments; + fundArguments(0) = iauFal03(teph); + fundArguments(1) = iauFalp03(teph); + fundArguments(2) = iauFaf03(teph); + fundArguments(3) = iauFad03(teph); + fundArguments(4) = iauFaom03(teph); + + //theta + double uta, utb, tta, ttb; + uta = 2400000.5; + tta = 2400000.5; + int iy, im, id; + double fd; + int err; + err = iauJd2cal(2400000.5, mjd, &iy, &im, &id, &fd); + double tai_utc; + err = iauDat(iy, im, id, fd, &tai_utc); + ttb = mjd; + double mjd_utc = mjd + 32.184 + tai_utc; + utb = mjd_utc ; //+ ut1_utc / 86400.0; //Should have the ut1 utc value, probably too small + double gmst00 = iauGmst00(uta, utb, tta, ttb); + Beta(0) = gmst00 + M_PI - fundArguments(2) - fundArguments(4); + Beta(1) = fundArguments(2) + fundArguments(4); + Beta(2) = Beta(1) - fundArguments(3); + Beta(3) = Beta(1) - fundArguments(0); + Beta(4) = -1 * fundArguments(4); + Beta(5) = Beta(1) - fundArguments(3) - fundArguments(1); + +} + +void OceanTide::getSPH(Eigen::Array dood, MatrixXd & Cnm, MatrixXd & Snm) +{ + for (auto & wave : TidalWaves ) + { + double thetaf = (dood * wave.Doodson).sum(); + Cnm += ((wave.CnmP + wave.CnmM) * cos(thetaf) + (wave.SnmP + wave.SnmM) * sin(thetaf))*1e-11; + Snm += ((wave.SnmP - wave.SnmM) * cos(thetaf) - (wave.CnmP - wave.CnmM) * sin(thetaf))*1e-11; + // BOOST_LOG_TRIVIAL(debug) << "doods " << dood; + // BOOST_LOG_TRIVIAL(debug) << "mult " << wave.Doodson; + // BOOST_LOG_TRIVIAL(debug) << wave.CnmP ; + // BOOST_LOG_TRIVIAL(debug) << "thetaf" << thetaf; + // BOOST_LOG_TRIVIAL(debug) << "\n" << Cnm << "\n" << Snm ; + // exit(0); + } + Snm.col(0) *= 0.0; + Snm.row(0) *= 0.0; +} diff --git a/archived/oceanTide.hpp b/archived/oceanTide.hpp new file mode 100644 index 000000000..22e92a2ba --- /dev/null +++ b/archived/oceanTide.hpp @@ -0,0 +1,48 @@ +// +// Created by Sébastien Allgeyer on 28/2/22. +// + +#ifndef GINAN_OCEANTIDE_HPP +#define GINAN_OCEANTIDE_HPP + +#include +#include +// #include +// #include +#include "eigenIncluder.hpp" + +struct TidalWave{ + TidalWave(); + TidalWave( + std::string name, + std::string doodson, + int degmax + ); + std::string WaveName; + Eigen::MatrixXd CnmP; + Eigen::MatrixXd CnmM; + Eigen::MatrixXd SnmP; + Eigen::MatrixXd SnmM; + Eigen::ArrayXd coeff; + Eigen::Array Doodson; + +}; + +struct OceanTide { + OceanTide(){}; + OceanTide( + std::string filename_, + int degmax_ ); + void readocetide(); + void summary(); + void setBeta(double); + std::string filename; + int degMax; + std::vector TidalWaves; + Eigen::Array Beta; + void getSPH(Eigen::Array beta, MatrixXd & Cnm, MatrixXd & Snm); + +}; + + +#endif //GINAN_OCEANTIDE_HPP diff --git a/archived/orbit.hpp b/archived/orbit.hpp new file mode 100644 index 000000000..f6bbd7210 --- /dev/null +++ b/archived/orbit.hpp @@ -0,0 +1,28 @@ +// +// Created by Sébastien Allgeyer on 24/2/22. +// + +#ifndef GINAN_ORBIT_HPP +#define GINAN_ORBIT_HPP + +#include "staticField.hpp" +#include "oceanTide.hpp" +#include "gTime.hpp" +#include "erp.hpp" +/** structure of data to be loaded just once. + * + */ +struct orb_t { + StaticField egm; + OceanTide tide; + struct jpl_eph_data *jplEph_ptr = nullptr; + GTime startTime; + ERP erpData; + +}; + +extern orb_t orbit_data; + + + +#endif //GINAN_ORBIT_HPP diff --git a/archived/peaUploader/uploadMain.cpp b/archived/peaUploader/uploadMain.cpp index 88b165319..d6ec549ee 100644 --- a/archived/peaUploader/uploadMain.cpp +++ b/archived/peaUploader/uploadMain.cpp @@ -70,11 +70,10 @@ void configureUploadingStreams() auto& [label, outStream_ptr] = *it; auto& outStream = *outStream_ptr; - outStream.streamConfig.rtcmMessagesTypes = outStreamData.rtcmMessagesTypes; + outStream.streamConfig.rtcmMsgOptsMap = outStreamData.rtcmMsgOptsMap; outStream.streamConfig.itrf_datum = outStreamData.itrf_datum; outStream.streamConfig.provider_id = outStreamData.provider_id; outStream.streamConfig.solution_id = outStreamData.solution_id; - outStream.streamConfig.update_interval = outStreamData.update_interval; outStream.streamConfig.master_iod = outStreamData.master_iod; } diff --git a/src/cpp/rtklib/readtrop.cpp b/archived/readtrop.cpp similarity index 91% rename from src/cpp/rtklib/readtrop.cpp rename to archived/readtrop.cpp index 4190f300b..7496adbb4 100644 --- a/src/cpp/rtklib/readtrop.cpp +++ b/archived/readtrop.cpp @@ -300,28 +300,3 @@ int readtrop(FILE* fp, mgex_trop* mtrop) return 1; } -#if (0) -int readtropmain() -{ - FILE* fptrop; - mgex_trop* mtrop; - - mtrop = (mgex_trop*)malloc(sizeof(mgex_trop)); - - if (!(fptrop = fopen("/opt/data/COD18540.TRO", "r"))) - { - printf("No file/n"); - } - - if (!(inittrop(mtrop))) - return 0; - - if (fptrop) - readtrop(fptrop, mtrop); - - freetrop(mtrop); - free(mtrop); - fclose(fptrop); - return 0; -} -#endif diff --git a/src/cpp/orbprop/satRefSys.hpp b/archived/satRefSys.hpp similarity index 100% rename from src/cpp/orbprop/satRefSys.hpp rename to archived/satRefSys.hpp diff --git a/archived/stateSV.cpp b/archived/stateSV.cpp new file mode 100644 index 000000000..69fc96bd8 --- /dev/null +++ b/archived/stateSV.cpp @@ -0,0 +1,152 @@ +// +// Created by Sébastien Allgeyer on 15/3/22. +// + +#include "stateSV.hpp" +#include "mainPod.hpp" +#include "jplEph.hpp" +#include "math_tools.hpp" +#include "coordinates.hpp" +#include "erp.hpp" +#include "iers2010.hpp" +#include +#include +#include +#include + +#include + +stateSV::stateSV() { + name="blah"; +}; + +void stateSV::computeAcceleration(Vector6d & init, const double mjd) +{ + IERS2010 iers; + Vector3d acc = Vector3d::Zero(); + Vector3d rSat = init.head(3); + Vector3d vSat = init.tail(3); + + Matrix3d eci2ecf, deci2ecf; + ERPValues erps ; + geterp(mainPod::Instance()->orbit_data.erpData, mjd/86400.0, erps); + eci2ecef_sofa(mjd/86400.0, erps, eci2ecf, deci2ecf); + + if(true) + { + for (auto & [name, vecPosition] : mainPod::Instance()->planets){ + if (name != orbiting) + { + Vector3d acc_ = accelSourcePoint(rSat, vecPosition.head(3), GM_values[name]); + acc += acc_ + BOOST_LOG_TRIVIAL(debug) << name << " " << acc_; + } + } + accI = acc; + } + + //central body force + if(false) + { + accI += accelCentralForce(rSat, mainPod::Instance()->orbit_data.egm.earthGravityConstant); + } + + + //Acceleration due to the spherical field. + if(true) + { + + MatrixXd Cnm, Snm; + Cnm = mainPod::Instance()->orbit_data.egm.gfctC; + Snm = mainPod::Instance()->orbit_data.egm.gfctS; + + Eigen::Array dood_arr = iers.doodson((mjd+33+32.184)/86400.0, erps.ut1_utc); + + if (false) + { + MatrixXd Cnm_solid = MatrixXd::Zero(5,5); /* correction for solid earth tide*/ + MatrixXd Snm_solid = MatrixXd::Zero(5,5); + iers.SolidEarthTide1(eci2ecf*mainPod::Instance()->planets[E_ThirdBody::SUN].head(3), eci2ecf*mainPod::Instance()->planets[E_ThirdBody::MOON].head(3), + Cnm_solid, Snm_solid); + iers.SolidEarthTide2((mjd+33+32.184)/86400.0, erps.ut1_utc, Cnm_solid, Snm_solid); + Cnm.block(0,0,5,5) += Cnm_solid; + Snm.block(0,0,5,5) += Snm_solid; + } + + // ocean tide + if(false) + { + Eigen::Array dood_arr = iers.doodson((mjd+33+32.184)/86400.0, erps.ut1_utc); + MatrixXd Cnm_ocean = MatrixXd::Zero(Cnm.cols(), Cnm.cols()); /* correction for solid earth tide*/ + MatrixXd Snm_ocean = MatrixXd::Zero(Cnm.cols(), Cnm.rows()); + mainPod::Instance()->orbit_data.tide.getSPH(dood_arr, Cnm_ocean, Snm_ocean); + Cnm = Cnm + Cnm_ocean; + Snm = Snm + Snm_ocean; + } + + //pole tides + if(false) + { + iers.PoleOceanTide(mjd/86400, erps.xp, erps.yp, Cnm, Snm); + iers.PoleSolidEarthTide(mjd/86400, erps.xp, erps.yp, Cnm, Snm); + } + + + posE = eci2ecf * rSat; + velE = eci2ecf * vSat + deci2ecf * rSat; + acc = accelSPH(posE, + Cnm, Snm, + mainPod::Instance()->orbit_data.egm.degMax, + mainPod::Instance()->orbit_data.egm.earthGravityConstant ); + accI += eci2ecf.transpose()*acc; + BOOST_LOG_TRIVIAL(debug) << " SPH " << + } + + // Relativistic effects; + if (true) + { + Vector3d acc_rel; + iers.relativity(init, mainPod::Instance()->planets[E_ThirdBody::SUN], eci2ecf, deci2ecf, acc_rel); + accI += acc_rel; + // BOOST_LOG_TRIVIAL(debug) << acc_rel.transpose(); + + } + + //Indirect J2. + if(true) + { + /** + * @brief "The indirect J2 effect". Only for Sun and Moon + * @ref GOCE standards GO-TN-HPF-GS-0111 + * + */ + Vector3d accJ2 = Vector3d::Zero(); + for (auto body : { E_ThirdBody::SUN, E_ThirdBody::MOON}) + { + double GM_Body; + double rho; + Vector3d pos_ecef = eci2ecf * mainPod::Instance()->planets[body].head(3); + double dist = pos_ecef.norm(); + double term = (GM_values[body] / pow(dist,3)) * pow(RE_WGS84 / dist, 2); + Vector3d vec = term * (5.0 * pow(pos_ecef.z()/dist,2) - 1.0) * pos_ecef; + vec.z() = term * (5.0 * pow(pos_ecef.z()/dist,2) - 3.0) * pos_ecef.z(); + + accJ2 += -1.0 * ( ( 3.0 * sqrt(5.0) ) / 2.0 ) * mainPod::Instance()->orbit_data.egm.gfctC(2,0) * (vec); + } + accI += eci2ecf.transpose() * accJ2; + + } + + +}; + + +void stateSV::operator()(Vector6d & init, Vector6d &update, const double mjd) +{ + Vector3d rSat = init.head(3); + Vector3d vSat = init.tail(3); + computeAcceleration(init, mjd); + update.head(3) = vSat; + update.tail(3) = accI; +}; + diff --git a/archived/stateSV.hpp b/archived/stateSV.hpp new file mode 100644 index 000000000..b57fc702a --- /dev/null +++ b/archived/stateSV.hpp @@ -0,0 +1,31 @@ +// +// Created by Sébastien Allgeyer on 15/3/22. +// + +#ifndef CODE_TESTING_STATESV_HPP +#define CODE_TESTING_STATESV_HPP + +#include "eigenIncluder.hpp" +#include +#include + +struct stateSV { + stateSV(); + Vector3d posI; + Vector3d velI; + Vector3d accI; + Vector6d posVelI; + + Vector3d posE; + Vector3d velE; + std::string name; + + void operator()(Vector6d & init, Vector6d &update, const double mjdinsec); + + void computeAcceleration(Vector6d & init, const double mjdinsec); +// void set_in +}; + + + +#endif //CODE_TESTING_STATESV_HPP diff --git a/archived/staticField.cpp b/archived/staticField.cpp new file mode 100644 index 000000000..46e579bf2 --- /dev/null +++ b/archived/staticField.cpp @@ -0,0 +1,117 @@ +// +// Created by Sébastien Allgeyer on 24/2/22. +// + +#include "staticField.hpp" +#include +#include +#include +#include + +#include +#include +#include + +StaticField::StaticField(std::string filename_, int degmax_): filename(filename_), degMax(degmax_) +{ + readegm(); + summary(); +} + + +/** + * Read the static gravity field + * @todo include the time variable component of the gravity field. +*/ +void StaticField::readegm() +{ + std::ifstream infile(filename); + int n,m; + double C, S, sigC, sigS, t0_; + std::string key, line; + bool header = true; + gfct = Eigen::MatrixXd::Zero(degMax+1, degMax+1); + gfctC = Eigen::MatrixXd::Zero(degMax+1, degMax+1); + gfctS = Eigen::MatrixXd::Zero(degMax+1, degMax+1); + + while (std::getline(infile, line)) + { + std::istringstream iss(line); + if (header) + { + if (line.compare(0,11,"end_of_head")==0) + { + header = false; + } + else + { + if (line.length() != 0) + { + std::vector split; + boost::algorithm::split(split,line,boost::algorithm::is_any_of(" "),boost::token_compress_on); + if (split[0].compare("modelname") == 0) + modelName = split[1]; + else if (split[0].compare("earth_gravity_constant") == 0) + earthGravityConstant = stod(split[1]); + else if (split[0].compare("radius") == 0) + earthRadius = stod(split[1]); + else if (split[0].compare("max_degree") == 0) + maxDegree = stoi(split[1]); + else if (split[0].compare("tide_system")==0) + { + if (split[1].compare("tide_free") == 0) + tideFree = true; + else + tideFree = false; + } + } + } + } + else + { + iss >> key >> n >> m >> C >> S >> sigC >> sigS ; + if (n <= degMax ) + { + if (key.compare(0,3, "gfc") == 0 ) + { + gfctC(n,m) = C; + gfct (n,m) = C; + if ( m > 0 ) { + gfctS(n, m) = S; + gfct (m-1,n) = S; + } + } + } + else + { + break; + } + } + } + + gfctC(2,0) -= -4.1736e-9; + // gfctC(2,0) -= -4.1736e-9; + // gfctC(2,0) = -0.48416948e-3 - 4.1736e-9 + 11.6e-12 * 7.0; + // gfctC(3,0) = 0.9571612e-6 + 4.9e-12 * 7.0; + // gfctC(4,0) = 0.5399659e-6 + 4.7e-12 * 7.0; + // xp, yp are the mean pole. MAS to RAD + // double xp = (23.513 + 7.6141 * 7 ) * 4.8481368E-9; + // double yp = (358.891 - 0.6287 * 7) * 4.8481368E-9; + // gfctC(2,1) = sqrt(3) * xp * gfctC(2,0) - xp * gfctC(2,2) + yp * gfctS(2,2); + // gfctS(2,1) = - sqrt(3) * xp * gfctC(2,0) - yp * gfctC(2,2) - xp * gfctS(2,2); + +// BOOST_LOG_TRIVIAL(debug) << "\n== coeff ==\n" << gfctC << "\n\n" << gfctS<< "\n\n" << gfct ; +} + + +void StaticField::summary() { + BOOST_LOG_TRIVIAL(info) << "read file : " << filename; + BOOST_LOG_TRIVIAL(info) << " - modelName " << modelName; + BOOST_LOG_TRIVIAL(info) << " - max degree model " << maxDegree; + if (maxDegree >= degMax ) + BOOST_LOG_TRIVIAL(info) << " => read only the first " << degMax << " degrees"; + else + BOOST_LOG_TRIVIAL(warning) << " => Maximum degree requested is higher than the model " << degMax << ">" << maxDegree ; + BOOST_LOG_TRIVIAL(info) << " - is tide_free " << tideFree ; + +} \ No newline at end of file diff --git a/archived/staticField.hpp b/archived/staticField.hpp new file mode 100644 index 000000000..8c7aa3048 --- /dev/null +++ b/archived/staticField.hpp @@ -0,0 +1,39 @@ +// +// Created by Sébastien Allgeyer on 24/2/22. +// + +#ifndef GINAN_STATICFIELD_H +#define GINAN_STATICFIELD_H + +#include + +using std::string; + +#include +#include + +/** Structure for variable and function related to the static gravity field + * @todo time variable static gravity field + */ +struct StaticField { + StaticField(){}; + StaticField( + std::string filename_, + int degmax_ ); + void readegm(); + void summary(); + string filename; + Eigen::MatrixXd gfct; + Eigen::MatrixXd gfctC; + Eigen::MatrixXd gfctS; + int degMax; + string modelName; + double earthGravityConstant; + double earthRadius; + int maxDegree; + bool tideFree; + string norm; +}; + + +#endif //GINAN_STATICFIELD_H diff --git a/src/cpp/orbprop/test_egm.cpp b/archived/test_egm.cpp similarity index 100% rename from src/cpp/orbprop/test_egm.cpp rename to archived/test_egm.cpp diff --git a/docker/Dockerfile b/docker/Dockerfile index d1b39f515..b739d4254 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,5 +1,4 @@ FROM gnssanalysis/ginan-env:latest - ENV HOME /root RUN mkdir -p /ginan ADD . /ginan @@ -7,11 +6,12 @@ WORKDIR /ginan ARG TARGET RUN mkdir -p src/build \ && cd src/build \ - && cmake -DENABLE_OPTIMISATION=TRUE -DENABLE_PARALLELISATION=TRUE -DENABLE_MONGODB=TRUE .. \ - && make -j 3 $TARGET \ + && cmake -DENABLE_OPTIMISATION=TRUE -DENABLE_PARALLELISATION=TRUE .. \ + && make -j 2 $TARGET \ && cd ../.. \ && rm -rf src/build ENV PATH "/ginan/bin:${PATH}" -RUN cd /ginan/scripts && pip install . -#COPY ./docker/.bashrc /root/.bashrc +# Here to update gnssanalysis for the pipeline if needed. +RUN pip3 install gnssanalysis==0.0.26 + diff --git a/docker/run-aux.sh b/docker/run-aux.sh old mode 100644 new mode 100755 index 06d22d1cf..f95a1044f --- a/docker/run-aux.sh +++ b/docker/run-aux.sh @@ -4,15 +4,60 @@ function results2s3() { # needs dir and tag tar cfz run-results-$1.tar.gz $1; - aws s3 cp run-results-$1.tar.gz s3://ginan-pipeline-results/$TAG/ + aws s3 cp run-results-$1.tar.gz s3://ginan-pipeline-results/$TAG/ --quiet } shopt -s extglob +shopt -s nullglob function diffex() { for file in $@; do - ../scripts/diffutil.py -i $file -o solutions/$file -a $ATOL - ../scripts/diffutil.py -i $file -o solutions/$file + echo $file + if [ ${file: -3} = 'snx' ] + then + diffutil -i $file solutions/$file -a $ATOL --passthrough + diffutil -i $file solutions/$file --passthrough + else + diffutil -i $file solutions/$file -a $ATOL + diffutil -i $file solutions/$file + fi done -} \ No newline at end of file +} + + +runAllAndDiffOnFailure() { + +PROG=$1; shift #now remove this parameter from the list so we can iterate over the rest + +set +e +declare -i FAIL=0 + +for file; + do + echo %%%%%%%%%% Running $PROG on $file + $PROG $file; + if [ "$?" -eq "0" ]; + then + echo %%%%%%%%%% OKIE DOKIE; + else + echo %%%%%%%%%% Failure running $PROG on $file: + echo %%%%%%%%%% Diffing $file and solutions/$file: + echo %%%%%%%%%% + diff -W 300 -y -w --suppress-common-lines solutions/$file $file | head -n 600; + echo %%%%%%%%%% + echo %%%%%%%%%% ....... + echo %%%%%%%%%% + FAIL+=1; + fi +done + +set -e +if [ "$FAIL" -eq "0" ]; +then + echo %%%%%%%%%% All tests passed; +else + echo %%%%%%%%%% $FAIL tests failed: + false; +fi +} diff --git a/docker/run-tests-long.sh b/docker/run-tests-long.sh index 36421650b..661af5d5e 100755 --- a/docker/run-tests-long.sh +++ b/docker/run-tests-long.sh @@ -2,150 +2,40 @@ set -euo pipefail -#required env var $GINAN to be set to the checkout root -export PATH="$PATH:$GINAN/bin" - -S3_PREFIX=s3://peanpod/pea/long-tests/ex31/$(date --iso-8601=seconds)/ - -# ginan source tree is at /ginan -echo "*** Downloading examples ***" -cd $GINAN -python scripts/download_examples.py - -cd $GINAN/examples -mkdir -p ex31 ex31/pod_fit ex31/pea ex31/pod_ic - -echo "*** Run POD (fit) ***" -pod -y ex31_pod_fit_gps.yaml | tee pod.out -mv pod.out ex31/pod_fit - -if aws s3 ls > /dev/null 2>&1; then aws s3 sync ex31/ $S3_PREFIX; fi - -cd ex31/pod_fit -$GINAN/scripts/rms_bar_plot.py -i gag20624_igs20624_orbdiff_rtn.out -d . -c G >pod_G.rms -$GINAN/scripts/compare_pod_rms.py -ro pod.out -rr pod_G.rms -so ../../solutions/ex31/pod_fit/pod.out -sr ../../solutions/ex31/pod_fit/pod_G.rms -em 0.0002 - -if aws s3 ls > /dev/null 2>&1; then aws s3 sync ex31/ $S3_PREFIX; fi - -cd $GINAN/examples -echo "*** Run PEA to update estimated parameters ***" -pea --config ex31_pea_pp_netw_gnss_orb_ar.yaml - -if aws s3 ls > /dev/null 2>&1; then aws s3 sync ex31/ $S3_PREFIX; fi - -python $GINAN/scripts/diffsnx.py -i ex31/pea/ex31.snx -o solutions/ex31/pea/ex31.snx -for trace in `ls ex31/pea/*.TRACE`; do - tracebase="$(basename $trace)"; - python $GINAN/scripts/difftrace.py -i $trace -o "solutions/ex31/pea/$tracebase"; -done - -if aws s3 ls > /dev/null 2>&1; then aws s3 sync ex31/ $S3_PREFIX; fi - -echo "*** rerun pod from the ic file generated by pea" -pod -y ex31_pod_ic_gps.yaml | tee pod.out -mv pod.out ex31/pod_ic -cd ex31/pod_ic -$GINAN/scripts/rms_bar_plot.py -i gag20624_igs20624_orbdiff_rtn.out -d . -c G >pod_G.rms -$GINAN/scripts/compare_pod_rms.py -ro pod.out -rr pod_G.rms -so ../../solutions/ex31/pod_icint/pod.out -sr ../../solutions/ex31/pod_icint/pod_G.rms -em 0.0002 - -if aws s3 ls > /dev/null 2>&1; then aws s3 sync ex31/ $S3_PREFIX; fi -exit 0 - -# the following is old and does not work -# Store the result files in a S3 bucket -echo "*** Store Results in S3" -ls -1 /ginan/examples/ex31/pea/* | xargs -L1 -I% aws s3 cp % s3://peanpod/pea/long-tests/${bitbucket_branch}/network-orbit/ - - -# copy the clock file for processing in PPP later -#cp /data/acs/pea/output/EX03/EX03.clk /data/acs/pea/proc/exs/products/gag20624.clk -# copy the smoothed clock file for processing in PPP later: -cp /data/acs/pea/output/EX03/EX03.clk_smoothed /data/acs/pea/proc/exs/products/gag20624.clk - -#============================================================================== -# Create an SP3 file from the POD -# copy the config files needed by POD and the results files into a seperate work -# directory /data/acs/pea/output/ex03-check -#============================================================================== -mkdir -p /data/acs/pea/output/ex03-check && cd /data/acs/pea/output/ex03-check -# TODO: check which file in and where I am copying: -cp /data/acs/pea/proc/exs/products/igs20624.sp3 ./ -cp /data/acs/pea/proc/exs/products/orb_partials/gag20624_orbits_partials.out.ecom2_pea ./ -cp /data/acs/pea/aws/long-tests/config/POD.in ./ -cp /data/acs/pea/aws/long-tests/config/EQM.in ./ -cp /data/acs/pea/aws/long-tests/config/VEQ.in ./ -cp /data/acs/pod/tables/* ./ - -echo "*** Running the POD" -echo `date` -# run the pod to produce the SP3 file based on the pod partials -pod -echo "*** Checking whether POD runs with this command" -# copy the sp3 file to s3 and for processing by the pea later -aws s3 cp gag20624.sp3 s3://peanpod/pea/long-tests/${bitbucket_branch}/network-orbit/ -cp gag20624.sp3 /data/acs/pea/proc/exs/products/ - -echo "*** Copying to s3" -# copy the orbex back to s3 -aws s3 cp gag20624.obx s3://peanpod/pea/long-tests/${bitbucket_branch}/network-orbit/ - -echo "*** Setting up conda" -# Set up the python environment for plotting -eval "$(command conda 'shell.bash' 'hook' 2> /dev/null)" -conda activate gn37 - -# ============================================================================= -# run the plotting scripts .. -# ============================================================================= -echo "*** Running plot scripts" -python3 /data/acs/pod/scripts/res_plot.py -i gag20624_igs20624_orbdiff_rtn.out -d . -c G -aws s3 cp gag20624_igs20624_orbdiff_rtn.out s3://peanpod/pea/long-tests/${bitbucket_branch}/network-orbit/ -aws s3 cp orbres_gag20624_igs20624.out_G.png s3://peanpod/pea/long-tests/${bitbucket_branch}/network-orbit/ - -# copy the png file orbres_gag20624_igs20624.out_G.png to s3, or send via email -python3 /data/acs/pod/scripts/rms_bar_plot.py -i gag20624_igs20624_orbdiff_rtn.out -d . -c G >& pod.rms -aws s3 cp gag20624_igs20624_orbdiff_rtn.out s3://peanpod/pea/long-tests/${bitbucket_branch}/network-orbit/ -aws s3 cp pod.rms s3://peanpod/pea/long-tests/${bitbucket_branch}/network-orbit/ - -# TODO: Should store the results from master and download them to here for comparison -#diff pod.out ./solution/pod.out -#diff pod.rms ./solution/pod.rms -#diff gag20624.sp3 ./solution/gag20624.sp3 - -echo "*** Running PEA - PPP solutions using the new orbit and clocks" -cd /data/acs/pea/aws/long-tests -./runLongTest_EX01_IF_PPP_PEA_PRODUCTS_SMOOTHED.sh - -# copy results back to S3 -cd /data/acs/pea/output/exs/LONG_EX01_IF_PEA_PRODUCTS_SMOOTHED/ -ls -1 /data/acs/pea/output/exs/LONG_EX01_IF_PEA_PRODUCTS_SMOOTHED/* | xargs -L1 -I% aws s3 cp % s3://peanpod/pea/long-tests/${bitbucket_branch}/ppp-pea-products-smoothed/ - -# Compare the PPP solutions to the IGS solutions -ls -1 *.TRACE | xargs -L1 -I% python /data/acs/pea/python/source/trace_plot.py -y_lims /-0.1,0.1 -PPP_diff /data/acs/pea/proc/exs/products/igs19P2062.snx /data/acs/pea/output/exs/LONG_EX01_IF_PEA_PRODUCTS_SMOOTHED/% ./ - -echo "*** Running PEA - PPP solutions using the IGS orbit and clocks" -cd /data/acs/pea/aws/long-tests -./runLongTest_EX01_IF_PPP.sh - -# copy results back to S3 -cd /data/acs/pea/output/exs/LONG_EX01_IF_IGS_PRODUCTS/ -ls -1 /data/acs/pea/output/exs/LONG_EX01_IF_IGS_PRODUCTS/* | xargs -L1 -I% aws s3 cp % s3://peanpod/pea/long-tests/${bitbucket_branch}/ppp-pea-products-smoothed/ - -# Compare the PPP solutions to the IGS solutions -ls -1 *.TRACE | xargs -L1 -I% python /data/acs/pea/python/source/trace_plot.py -y_lims /-0.1,0.1 -PPP_diff /data/acs/pea/proc/exs/products/igs19P2062.snx /data/acs/pea/output/exs/LONG_EX01_IF_PARALLEL_PEA/% ./ - -#============================================================================== -# Other tests to add -# 1) Single frequency PPP -# 2) Multi-gnss solutions -# 3) Ionosphere solutions -#============================================================================== -#echo "getting spot request name" -#echo $(aws ec2 describe-spot-instance-requests --filters Name=instance-id,Values="$(wget -q -O - http://169.254.169.254/latest/meta-data/instance-id)" --region ap-southeast-2 | jq '.SpotInstanceRequests[0].SpotInstanceRequestId' --raw-output) - -#aws ec2 cancel-spot-instance-requests --spot-instance-request-ids $(aws ec2 describe-spot-instance-requests --filters Name=instance-id,Values="$(wget -q -O - http://169.254.169.254/latest/meta-data/instance-id)" --region ap-southeast-2 | jq '.SpotInstanceRequests[0].SpotInstanceRequestId' --raw-output) --region ap-southeast-2 - -echo "*** Publishing build log" -aws sns publish --topic-arn "arn:aws:sns:ap-southeast-2:604917042985:acs-release-testing" --message file:///data/build.log --region ap-southeast-2 - -#sudo shutdown -h now +# download example tests +source /ginan/docker/tags +source /ginan/docker/run-aux.sh + +# start mongo DB +#/bin/systemctl start /usr/bin/mongod +#@/bin/systemctl status /usr/bin/mongod +mkdir /ginan/db +/usr/bin/mongod --dbpath /ginan/db --bind_ip 127.0.0.1 & +sleep 5 + +/ginan/scripts/download_examples.py -d -p # tag is ignored for products and data tarballs + +# run example tests +TEST_NUM=$1 + +cd /ginan/examples + +ATOL=1E-4 + +case $TEST_NUM in + 1) + pod -y ex31_pod_fit_gps.yaml | tee pod.out + mv pod.out ex31/pod_fit + pea -y ex31_pea_pp_netw_gnss_orb_ar.yaml | tee pea.out + mv pea.out ex31/pea + pod -y ex31_pod_ic_gps.yaml | tee pod.out + mv pod.out ex31/pod_ic + DIR="ex31" + results2s3 $DIR + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $PEAPOD + runAllAndDiffOnFailure diffex $DIR/pod_fit/{*.sp3,pod.out} + runAllAndDiffOnFailure diffex $DIR/pea/{*etwork*.TRACE,*.snx,*.clk*} # todo: add *.erp + runAllAndDiffOnFailure diffex $DIR/pod_ic/{*.sp3,pod.out} + ;; +esac diff --git a/docker/run-tests-other.sh b/docker/run-tests-other.sh new file mode 100755 index 000000000..a809b5430 --- /dev/null +++ b/docker/run-tests-other.sh @@ -0,0 +1,110 @@ +#!/bin/bash +set -euo pipefail +GINAN=/ginan +PATH=$GINAN/bin:$PATH + + +# download example tests +source $GINAN/docker/tags +source $GINAN/docker/run-aux.sh + +# /ginan/scripts/download_examples.py -d -p # tag is ignored for products and data tarballs +$GINAN/scripts/download_examples.py -d -p -l # tag is ignored for products and data tarballs + +#ensure mongo is running +mkdir -p $GINAN/db +/usr/bin/mongod --dbpath $GINAN/db --bind_ip 127.0.0.1 & +sleep 5 + +# run example tests +TEST_NUM=$1 + +cd $GINAN/examples + +ATOL=1E-4 +# to add new examples one needs to add a dictionary to EX_GLOB_DICT so download_examples.py knows which files to push, otherwise it will fail. Also, make sure that example dir name starts with `ex` and has no more than 3 chars following (at least for now). If a group of examples is being created, e.g. ex9* - add an example type to get_example_type and a respective tag to the `tags` file. + +case $TEST_NUM in + 1) + DIR="ex51" + mkdir -p $DIR + make_otl_blq --config ex51_otl_fes2014b_gb.yaml --code 'ALIC 50137M0014' --location 133.8855 -23.6701 --output $DIR/alic.blq + make_otl_blq --config ex51_otl_fes2014b_gb.yaml --code 'BRO1 50176M003' --location 122.2090 -18.0039 --output $DIR/bro1.blq + + export OMP_NUM_THREADS=2 #gets killed in the pipeline if not overridden + make_otl_blq --config ex51_otl_fes2014b_gb.yaml --input loading/sites_coastal50.csv --output $DIR/coastal50.blq + make_otl_blq --config ex51_otl_fes2014b_prem.yaml --input loading/sites_coastal50.csv --output $DIR/coastal50_PREM.blq + + results2s3 $DIR + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $OTHER + ATOL=1.3E-2 # BRST has diff of 1.23E-2 + runAllAndDiffOnFailure diffex $DIR/*.blq + diffutil -i $DIR/coastal50_PREM.blq loading/blq/C50_FES2014b_PREM_CE.blq -a $ATOL + ;; + 2) + DIR="ex52" + mkdir -p $DIR + interpolate_loading --grid loading/grids/oceantide.nc --code 'ALIC 50137M0014' --location 133.8855 -23.6701 --output $DIR/alic.blq + interpolate_loading --grid loading/grids/oceantide.nc --code 'BRO1 50176M003' --location 122.2090 -18.0039 --output $DIR/bro1.blq + interpolate_loading --grid loading/grids/oceantide.nc --input loading/sites_coastal50.csv --output $DIR/coastal50.blq + results2s3 $DIR + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $OTHER + ATOL=1E-2 + runAllAndDiffOnFailure diffex $DIR/*.blq + ;; + 3) + pea --config ex43_pea_pp_user_gps.yaml -v | tee pea43.out + sed -f edit_ex43.sed < ex43_pea_pp_user_gps.yaml > ex43a_pea_pp_user_gps.yaml + pea --config ex43a_pea_pp_user_gps.yaml -v | tee pea43a.out # TODO which branch is this config in? Need to modify output dir + DIR="ex43" # having ex11a or ex11 will download results with PEA TAG, not OTHER, if no TAG provided + results2s3 $DIR + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $OTHER + DIR="ex43a" # having ex11a or ex11 will download results with PEA TAG, not OTHER, if no TAG provided + results2s3 $DIR + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $OTHER + runAllAndDiffOnFailure diffex $DIR/{*snx,!(*Network*).TRACE} + DIR="ex43" # having ex11a or ex11 will download results with PEA TAG, not OTHER, if no TAG provided + runAllAndDiffOnFailure diffex $DIR/{*snx,!(*Network*).TRACE} + diffutil -a 1e-4 -i ex43/ex43-AGGO*.TRACE ex43a/ex43a-AGGO*.TRACE + diffutil -a 1e-4 -i ex43/ex43-ALIC*.TRACE ex43a/ex43a-ALIC*.TRACE + diffutil -a 1e-4 -i ex43/ex43-BAKO*.TRACE ex43a/ex43a-BAKO*.TRACE + diffutil -a 1e-4 -i ex43/ex43-COCO*.TRACE ex43a/ex43a-COCO*.TRACE + ;; + 9) + pea --config ex41_gin2_pp_user.yaml + DIR="ex41" + results2s3 $DIR + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $OTHER + runAllAndDiffOnFailure diffex $DIR/*.TRACE + ;; + 10) + pea --config ex42_gin2_pp_user_3freq.yaml + DIR="ex42" + results2s3 $DIR + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $OTHER + runAllAndDiffOnFailure diffex $DIR/*.TRACE + ;; + 8) + # up trace level in ex11 to level 5 and change name to ex44 + pea -dex44 -l5 --config ex11_pea_pp_user_gps.yaml -v | tee pea44.out + DIR="ex44" + results2s3 $DIR + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $OTHER + #diffex $DIR/{*snx,*ALIC*.TRACE} # no need to check results - this is done in ex11 + count=`grep "STARTING SPP LSQ" $DIR/*ALIC*.TRACE | wc -l` + if [ $count -eq 0 ] + then + echo "no indication of LSQ in use" + exit 1 + else + echo "LSQ is deomnstrated" + fi + ;; +esac diff --git a/docker/run-tests-pea.sh b/docker/run-tests-pea.sh index 3f9bd7ab6..ae7fe68db 100755 --- a/docker/run-tests-pea.sh +++ b/docker/run-tests-pea.sh @@ -24,65 +24,77 @@ ATOL=1E-4 # in all cases there is a pea.out file but no sensible way to compare it case $TEST_NUM in - 1) - pea --config ex11_pea_pp_user_gps.yaml -V | tee pea11.out + 11) + pea --config ex11_pea_pp_user_gps.yaml -v | tee pea11.out DIR="ex11" results2s3 $DIR - ../scripts/download_examples.py --dirs $DIR --tag $TAG --push - ../scripts/download_examples.py --dirs $DIR --tag $PEA - diffex $DIR/{*snx,!(*Network*).TRACE*} + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*snx,!(*Network*).TRACE*} ;; - 2) + 12) pea --config ex12_pea_pp_user_gnss.yaml | tee pea12.out DIR="ex12" results2s3 $DIR - ../scripts/download_examples.py --dirs $DIR --tag $TAG --push - ../scripts/download_examples.py --dirs $DIR --tag $PEA - diffex $DIR/{*snx,!(*Network*).TRACE*} + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*snx,!(*Network*).TRACE} ;; - 3) + 13) pea --config ex13_pea_pp_user_gps_sf.yaml | tee pea13.out DIR="ex13" results2s3 $DIR - ../scripts/download_examples.py --dirs $DIR --tag $TAG --push - ../scripts/download_examples.py --dirs $DIR --tag $PEA - diffex $DIR/{*snx,!(*Network*).TRACE*} + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*snx,!(*Network*).TRACE} ;; - 4) + 14) pea --config ex14_pea_pp_user_gnss_ar.yaml | tee pea14.out # ex14 run 5 DIR="ex14" results2s3 $DIR - ../scripts/download_examples.py --dirs $DIR --tag $TAG --push - ../scripts/download_examples.py --dirs $DIR --tag $PEA - diffex $DIR/{*snx,!(*Network*).TRACE*} + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*snx,!(*Network*).TRACE} ;; - 5) - pea --config ex15_pea_rt_user_gnss_ar.yaml | tee pea15.out - DIR="ex15" - results2s3 $DIR - ../scripts/download_examples.py --dirs $DIR --tag $TAG --push - ../scripts/download_examples.py --dirs $DIR --tag $PEA - diffex $DIR/{*snx,!(*Network*).TRACE*} + 15) + # TODO: broken recordings maybe + #pea --config ex15_pea_rt_user_gnss_ar.yaml | tee pea15.out + #DIR="ex15" + #results2s3 $DIR + #../scripts/download_examples.py $DIR --tag $TAG --push + #../scripts/download_examples.py $DIR --tag $PEA + #runAllAndDiffOnFailure diffex $DIR/{*snx,!(*Network*).TRACE} ;; - 6) + 16) pea --config ex16_pea_pp_ionosphere.yaml | tee pea16.out DIR="ex16" results2s3 $DIR - ../scripts/download_examples.py --dirs $DIR --tag $TAG --push - ../scripts/download_examples.py --dirs $DIR --tag $PEA - diffex $DIR/{*.*I,*Network*.TRACE,*stec} + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*.INX*,*Network*.TRACE,*stec} ;; - 7) + 17) pea --config ex17_pea_pp_netw_gnss_ar.yaml | tee pea17.out DIR="ex17" results2s3 $DIR - ../scripts/download_examples.py --dirs $DIR --tag $TAG --push - ../scripts/download_examples.py --dirs $DIR --tag $PEA - diffex $DIR/{*snx,*Network*.TRACE} + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*snx,*Network*.TRACE} ;; - 8) - # TODO not working: - # pea --config ex18_pea_rt_netw_gnss_ar.yaml + 41) + pea --config ex41_gin2_pp_user.yaml -v | tee pea41.out + DIR="ex41" + results2s3 $DIR + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*.TRACE,*.TRACE} + ;; + 2) + pea --config ex02_fit_sp3_pseudoobs.yaml -v | tee pea02.out + DIR="ex02" + results2s3 $DIR + ../scripts/download_examples.py $DIR --tag $TAG --push + ../scripts/download_examples.py $DIR --tag $PEA + runAllAndDiffOnFailure diffex $DIR/{*.TRACE,*.TRACE} ;; esac - diff --git a/docker/run-tests-pod.sh b/docker/run-tests-pod.sh index 396d6ad9b..e4897eaa3 100755 --- a/docker/run-tests-pod.sh +++ b/docker/run-tests-pod.sh @@ -21,8 +21,8 @@ case $TEST_NUM in mv pod21.out ex21/pod.out DIR="ex21" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 2g) # ex22 GPS @@ -30,8 +30,8 @@ case $TEST_NUM in mv pod22g.out ex22g/pod.out DIR="ex22g" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 2r) # ex22 GLONASS @@ -39,8 +39,8 @@ case $TEST_NUM in mv pod22r.out ex22r/pod.out DIR="ex22r" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 2e) # ex22 GALILEO @@ -48,8 +48,8 @@ case $TEST_NUM in mv pod22e.out ex22e/pod.out DIR="ex22e" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 2c) # ex22 BEIDOU @@ -57,8 +57,8 @@ case $TEST_NUM in mv pod22c.out ex22c/pod.out DIR="ex22c" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 2j) # ex22 QZSS @@ -66,8 +66,8 @@ case $TEST_NUM in mv pod22j.out ex22j/pod.out DIR="ex22j" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 3) @@ -75,8 +75,8 @@ case $TEST_NUM in mv pod23.out ex23/pod.out DIR="ex23" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 4) @@ -84,8 +84,8 @@ case $TEST_NUM in mv pod24.out ex24/pod.out DIR="ex24" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 5) @@ -93,8 +93,8 @@ case $TEST_NUM in mv pod25.out ex25/pod.out DIR="ex25" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; 6) @@ -102,8 +102,8 @@ case $TEST_NUM in mv pod26.out ex26/pod.out DIR="ex26" results2s3 $DIR - ../scripts/download_examples.py --push --dirs $DIR --tag $TAG - ../scripts/download_examples.py --dirs $DIR --tag $POD + ../scripts/download_examples.py --push $DIR --tag $TAG + ../scripts/download_examples.py $DIR --tag $POD diffex $DIR/{*.sp3,pod.out} ;; esac diff --git a/docker/tags b/docker/tags index 064094c5a..861dd3ff0 100644 --- a/docker/tags +++ b/docker/tags @@ -1,2 +1,4 @@ -PEA="2c7eb4a" -POD="0c8627b" +PEA="378e30e" +POD="a03f60a" +PEAPOD="22d80b6" +OTHER="9564eaa" diff --git a/examples/ex00.yaml b/examples/ex00.yaml index 189d26716..722ef6dd8 100644 --- a/examples/ex00.yaml +++ b/examples/ex00.yaml @@ -1,215 +1,63 @@ -input_files: +inputs: - root_input_directory: products/ + root_directory: products/ - atxfiles: [ igs14_2045_plus.atx ] # Antenna models for receivers and satellites in ANTEX format - snxfiles: [ "igs*.snx" ] # SINEX file for meta data and initial position - blqfiles: [ OLOAD_GO.BLQ ] # ocean loading is applied - #navfiles: [ brdm1990.19p ] # broadcast navigation file - sp3files: [ COD0MGXFIN_20191990000_01D_05M_ORB.SP3 ] - clkfiles: [ COD0R03FIN_20191990000_01D_30S_CLK.CLK ] - bsxfiles: [ COD0R03FIN_20191990000_01D_01D_OSB.BIA ] - - -station_data: - - root_stations_directory: data/ - - rnxfiles: - # Select files to run by: - - "T*.rnx" - # - "*.rnx" # - searching all in file_root directory - # - ALIC00AUS_R_20191990000_01D_30S_MO.rnx # - selecting them individually below, or - # - selecting one on the command line using the -rnxfiles option - -output_files: + #atx_files: [ igs14_2045_plus.atx ] # Antenna models for receivers and satellites in ANTEX format + #snx_files: [ "igs*.snx", tables/igs_satellite_metadata_2203_plus.snx ] # SINEX file for meta data and initial position + #blq_files: [ OLOAD_GO.BLQ ] # ocean loading is applied - root_output_directory: / - - output_trace: true - trace_level: 2 - trace_directory: ./ - trace_filename: -.TRACE - - output_residuals: true - #output_residual_chain: false - - output_summary: true - - enable_mongo: true - output_mongo_measurements: true - output_mongo_states: true - output_mongo_metadata: false - #delete_mongo_history: true - mongo_uri: mongodb://127.0.0.1:27017 - mongo_suffix: pppnetx3 + troposphere: + #vmf3_directory: grid5/ + #orography_files: orography_ell_5x5 + # gpt2grid_files: EX03/general/gpt_25.grd + + satellite_data: + #nav_files: [ brdm1990.19p ] # broadcast navigation file + #sp3_files: [ igs20624.sp3 ] # satellite orbit files in SP3 format + #clk_files: [ igs20624.clk_30s ] # Clk files + #bsx_files: [ TUG0R03FIN_20191990000_01D_01D_OSB.BIA ] # daily signal biases files + + #rtcm_inputs: -output_options: - config_description: new - analysis_agency: GAA - analysis_center: Geoscience Australia - analysis_program: AUSACS - rinex_comment: AUSNETWORK1 - -processing_options: - - #start_epoch: 2019-07-18 23:44:30 - #end_epoch: 2019-07-18 23:59:30 - epoch_interval: 30 #seconds - #max_epochs: 10 #0 is infinite - - process_modes: - #user: true - ppp: true - #network: true - #minimum_constraints: true - #rts: true - #ionosphere: true - - model: - relativity2: false - clock_definitions: false - - process_sys: - gps: true - glo: false - gal: false - bds: false - - process_freq: - gps: - l1: true - l2: true - #l5: true - gal: - l1: true - l5: true - - process_meas: - #code: false - #phase: false + gnss_observations: + inputs_root: data/ - elevation_mask: 7 #degrees - - ionosphere: - common_ionosphere: true - - tide_solid: true - tide_pole: true - tide_otl: true - - cycle_slip: - thres_slip: 0.05 - - max_inno: 0 - max_gdop: 30 - - troposphere: - model: vmf3 #gpt2 - vmf3dir: grid5/ - orography: orography_ell_5x5 - # gpt2grid: EX03/general/gpt_25.grd - - code_priorities: [ L1C, #L1P, L1Y, L1W, L1M, L1N, L1S, L1L, - L2W, #L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, - L5I, L5Q, L5X] - -user_filter_parameters: + ubx_inputs: + - serial:///dev/ttyACM0 + #- "bin.bin" + rtcm_inputs: + #- https://:@ntrip.data.gnss.ga.gov.au/ALIC00AUS0 + rnx_inputs: + # Select files to run by: + #- "ALIC*.rnx" # ALIC station rnx file will be found + #- "AGGO*.rnx" + #- "BAKO*.rnx" + #- "COCO*.rnx" + #- "*.19o" + #- "*.rnx" # - searching all in file_root directory + # - ALIC00AUS_R_20191990000_01D_30S_MO.rnx # - selecting them individually below, or + # - selecting one on the command line using the -rnxfiles option - max_filter_iterations: 5 #5 - max_prefit_removals: 3 #5 +outputs: -network_filter_parameters: - max_filter_iterations: 5 - max_prefit_removals: 5 - phase_reject_limit: 3 - outage_reset_limit: 3 - sigma_threshold: 40 - - chunk_stations: true + root_directory: / - rts_lag: -1 - rts_directory: ./ - rts_filename: -.rts + trace: + output_stations: true + level: 3 + directory: ./ + station_filename: -.TRACE + output_residuals: true -ambiguity_resolution_options: - reduction_limit: 5000 + sinex: + output: true + directory: ./ -default_filter_parameters: - - stations: - - error_model: elevation_dependent - code_sigmas: [0.15] - phase_sigmas: [0.0015] - - pos: - estimated: [true] - sigma: [0.1] - proc_noise: [0] - - clk: - estimated: [true] - sigma: [30] - proc_noise: [10] - - clk_rate: - #estimated: [true] - sigma: [500] - proc_noise: [1e-4] - - amb: - estimated: [true] - sigma: [60] - proc_noise: [0] - - code_bias: - estimated: [true] - sigma: [100] - #proc_noise: [0.001] - - phase_bias: - estimated: [true] - sigma: [1] - #proc_noise: [0.001] - - trop: - estimated: [true] - sigma: [0.1] - proc_noise: [0.0001] #0.1 mm/sqrt(s) - proc_noise_dt: second - - trop_grads: - estimated: [true] - sigma: [0.02] - proc_noise: [1.0E-6] - proc_noise_dt: second - - ion: - estimated: [true] - sigma: [20] - proc_noise: [5] - proc_noise_dt: second - - satellites: - - #clk: - #estimated: [true] - #sigma: [1000] - #proc_noise: [1] - - #code_bias: - #estimated: [true] - #sigma: [1] - ##proc_noise: [0.001] - - #phase_bias: - #estimated: [true] - #sigma: [1] - ##proc_noise: [0.001] - -override_filter_parameters: - satellites: - G04: - #exclude: true + clocks: + output: true + + rinex_obs: + output: true + split_sys: true + diff --git a/examples/ex01.yaml b/examples/ex01.yaml index 2b932550f..e44e82485 100644 --- a/examples/ex01.yaml +++ b/examples/ex01.yaml @@ -1,142 +1,137 @@ # ex01 - Orbit Propagation Example +inputs: -input_files: - - root_input_directory: products/ + root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # required - snx_files: [ igs19P2062.snx ] # required + snx_files: [ igs19P2062.snx, tables/igs_satellite_metadata_2219.snx] # required blq_files: [ OLOAD_GO.BLQ ] # required if ocean loading is applied - sp3_files: [ igs20624.sp3 ] - erp_files: [ igs20627.erp ] #config parser doesn't accept weekly files yet. - # bsx_files: [ CAS0MGXRAP_20191990000_01D_01D_DCB.BSX ] - #clk_files: [ igs20624.clk_30s ] # Clk files - #clk_files: [ cod19900.clk_05sA ] # Clk files - #orb_files: [ orb_partials/gag20624_orbits_partials.out.eop_test23 ] # only need this if we are estimating orbits - - nav_files: [ brdm1990.19p ] # broadcast navigation file - # dcb_files: [ TUG0R03FIN_20191990000_01D_01D_OSB.BIA ] # daily signal biases files - egm_files: [ GGM03S.txt ] # Earth gravity model coefficients file - jpl_files: [ DE436.1950.2050] # JPL planetary and lunar ephemerides file - -station_data: - - root_stations_directory: products/ - - pseudoobs_files: [igs20624.sp3 ] - - -output_files: - - root_output_directory: / - - output_trace: true - trace_level: 4 - trace_directory: ./ - trace_filename: --.TRACE - #trace_rotate_period: 6 - #trace_rotate_period_units: hours - - output_residuals: true - - output_summary: true - summary_directory: ./ - summary_filename: PEA.SUM - - - -output_options: - - config_description: ex01 - + erp_files: [ igs96p02.erp ] + + pseudo_observations: + inputs_root: "products/" + #sp3_inputs: [ IGS_Orbit_Test_sp3/esoc2_ecf_not_nst_hax.sp3 ] + sp3_inputs: [ IGS_Orbit_Test_sp3/esoc2_eci_not_nst.sp3 ] + #sp3_inputs: [ IGS_Orbit_Test_sp3/esoc2_ecf_not_nst.sp3 ] + + #satellite_modeling: + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat] + +outputs: + + root_directory: / + + trace: + output_stations: true + output_network: true + level: 2 + directory: ./ + station_filename: -.TRACE + network_filename: -.TRACE + output_residuals: true + #output_config: true + + sp3: + output: true + output_inertial: true + data_source: kalman # {none,precise,ssr,kalman,broadcast,nominal,model} + directory: "./" + filename: "_.sp3" + output_interval: 300 # (int) Update interval for sp3 records + output_velocities: true # (bool) + + metadata: + + config_description: esoc_not_nst # sets macro + analysis_agency: GAA + analysis_center: Geoscience Australia + analysis_program: AUSACS + rinex_comment: AUSNETWORK1 + +mongo: + database: "ECI_sim" # default is + enable: true + output_measurements: true + output_states: true + output_rtcm_messages: false + output_test_stats: false + delete_history: true + uri: mongodb://127.0.0.1:27017 + suffix: "" processing_options: - #start_epoch: 2019-07-18 12:00:00 - end_epoch: 2019-07-18 23:45:00 - #max_epochs: 9 #0 is infinite - epoch_interval: 900 #seconds - wait_next_epoch: 100000 - wait_all_stations: 1 - + epoch_control: + start_epoch: 2007-04-14 01:00:00 + end_epoch: 2007-04-14 23:00:00 + max_epochs: 0 #5 #0 is infinite + epoch_interval: 900 #seconds + require_obs: false + # wait_next_epoch: 100000 + wait_all_stations: 0.01 process_modes: ppp: true - #rts: true - - process_sys: - gps: true - gal: false - - force_models: - #earth_gravity: true - gravity_modol: GGM03SModel - solid_earth_tides: true - ocean_tide_loading: true - third_body_attraction: true - third_body_sun: true - third_body_moon: true - third_body_planet: true - relativity_effect: true - solar_radiation_pressure: true - thermal_emission: false - earth_albedo: false - infrared_radiation: false - antenna_thrust: false - satellite_manoeuvre: false - empirical_acceleration: false - - process_third_body: - #earth: true - - sat_mass: 455 - srp_model: CANNONBALL - srp_area: 65 - srp_coef: 1 - egmAccDeg: 12 - egmAccOrd: 12 - egmSTMDeg: 4 - egmSTMOrd: 4 + preprocessor: false -network_filter_parameters: + gnss_general: - max_filter_iterations: 1 - max_prefit_removals: 0 + sys_options: + gps: + process: true + + gnss_models: + + ionospheric_component: + use_if_combo: false + + orbit_propagation: + central_force: true + planetary_perturbation: true + indirect_J2: true + egm_field: true + solid_earth_tide: false + ocean_tide: false + general_relativity: false + pole_tide_ocean: false + pole_tide_solid: false + solar_pressure_radiation: false + + sat_mass: 1500 + sat_area: 15 + srp_cr: 1.25 + degree_max: 15 + + itrf_pseudoobs: false + + filter_options: + simulate_filter_only: true + + outlier_screening: + sigma_threshold: 100000 - rts_lag: -1 #-ve for full reverse, +ve for limited epochs - rts_directory: ./ - rts_filename: .rts + rts: + enable: false # (bool) Perform backward smoothing of states to improve precision of earlier states + lag: -1 # (int) Number of epochs to use in RTS smoothing. Negative numbers indicate full reverse smoothing. + directory: "./" # (string) Directory for rts intermediate files -default_filter_parameters: +estimation_parameters: - stations: - ion: - estimated: true - satellites: - pos: - estimated: false - sigma: [5] - proc_noise: [0] - - pos_rate: - estimated: false - sigma: [5000] - proc_noise: [0.01] + + global: + exclude: true -override_filter_parameters: - satellites: + G01: + exclude: false + G02: + exclude: false + + orbit: + estimated: [true] + sigma: [1, 1, 1, 100] + #proc_noise: [0.0001] - PRN_G01: - pos: - estimated: true - sigma: [5] - proc_noise: [0] - - pos_rate: - estimated: true - sigma: [5000] - proc_noise: [0.03] - - diff --git a/examples/ex11_pea_pp_user_gps.yaml b/examples/ex11_pea_pp_user_gps.yaml index f42d06bd7..b4b208224 100644 --- a/examples/ex11_pea_pp_user_gps.yaml +++ b/examples/ex11_pea_pp_user_gps.yaml @@ -7,39 +7,51 @@ inputs: root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # Antenna models for receivers and satellites in ANTEX format - snx_files: [ "igs*.snx" ] # SINEX file for meta data and initial position + snx_files: [ igs19P2062.snx, tables/igs_satellite_metadata_2203_plus.snx ] # SINEX file for meta data and initial position blq_files: [ OLOAD_GO.BLQ ] # ocean loading is applied troposphere: - vmf3_directory: grid5/ + vmf_files: [grid5/VMF3_20190718.H00, grid5/VMF3_20190718.H06, grid5/VMF3_20190718.H12, grid5/VMF3_20190718.H18] orography_files: orography_ell_5x5 - # gpt2grid_files: EX03/general/gpt_25.grd - + # gpt2grid_files: gpt_25.grd + + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat] + satellite_data: #nav_files: [ brdm1990.19p ] # broadcast navigation file sp3_files: [ igs20624.sp3 ] # satellite orbit files in SP3 format clk_files: [ igs20624.clk_30s ] # Clk files bsx_files: [ TUG0R03FIN_20191990000_01D_01D_OSB.BIA ] # daily signal biases files - + + #rtcm_inputs: gnss_observations: - root_directory: ../data/ - rnx_files: - # Select files to run by: - - "ALIC*.rnx" # ALIC station rnx file will be found - - "AGGO*.rnx" - - "BAKO*.rnx" - - "COCO*.rnx" - #- "*.rnx" # - searching all in file_root directory - # - ALIC00AUS_R_20191990000_01D_30S_MO.rnx # - selecting them individually below, or - # - selecting one on the command line using the -rnxfiles option - + inputs_root: data/ + + ubx_inputs: + #- serial:///dev/ttyACM0 + rtcm_inputs: + #- https://:@ntrip.data.gnss.ga.gov.au/ALIC00AUS0 + rnx_inputs: + - "ALIC*.rnx" + #- "ANKO*.rnx" + +station_options: + XMPL: + #apriori_position: [120000,20000,40000] + #eccentricity: [1, 2, 3] + #antenna_type: LEICA + #receiver_type: UBLOX + outputs: root_directory: / trace: - output_stations: true - level: 3 + output_stations: true + output_network: true + level: 4 directory: ./ station_filename: -.TRACE output_residuals: true @@ -50,21 +62,23 @@ outputs: clocks: output: true - directory: ./ - filename: .clk - - rinex_obs: - output: true - split_sys: true trop_sinex: - output: true - source: KALMAN - directory: ./ - filename: -.tro + #output: true + sources: [KALMAN] + + cost: + #output: true + sources: [KALMAN] + directory: ./ + filename: cost_s_t__ga__.dat + time_interval: 300 gpx: - output: true + #output: true + + orbex: + #output: true metadata: config_description: ex11 @@ -72,22 +86,57 @@ outputs: analysis_center: Geoscience Australia analysis_program: AUSACS rinex_comment: AUSNETWORK1 + + ppp_sol: + output: true + filename: _.POS mongo: enable: true - #output_measurements: true - #output_states: true - #output_test_stats: true + output_measurements: true + output_states: true + output_test_stats: true delete_history: true uri: mongodb://127.0.0.1:27017 - suffix: _ + #suffix: debug: #unit_tests: #stop_on_done: true #output_pass: false + +station_options: + + global: + rnx_code_conversions: + gps: + C1: L1C + C2: L2S + P2: L2W + C5: L5Q + rnx_phase_conversions: + gps: + L2: L2W + L5: L5Q + L1: L1C + AGGO: + rnx_code_conversions: + gps: + C5: L5I + rnx_phase_conversions: + gps: + L5: L5I + + COCO: + rnx_code_conversions: + gps: + C5: L5I + rnx_phase_conversions: + gps: + L5: L5I + processing_options: epoch_control: @@ -97,19 +146,24 @@ processing_options: #max_epochs: 1 #0 is infinite process_modes: + #ppp: true user: true gnss_general: + + #require_apriori_positions: true elevation_mask: 7 #degrees - reject_eclipse: true raim: true max_gdop: 30 sys_options: + bds: + #process: true gps: process: true + reject_eclipse: true code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, L5I, L5Q, L5X] @@ -117,11 +171,17 @@ processing_options: gnss_models: tides: - solid: true - pole: true - otl: true + #solid: false + #pole: false + #otl: false troposphere: model: vmf3 #gpt2 + sat_pos: + #sources: [broadcast] + sat_clock: + #sources: [broadcast] + sat_attitude: + sources: [model] #reinit_on_all_slips: true #reinit_on_clock_error: true @@ -134,12 +194,15 @@ processing_options: outlier_screening: max_filter_iterations: 5 #5 max_prefit_removals: 3 #5 + + station_chunking: + #enable: true rts: enable: true lag: -1 #-ve for full reverse, +ve for limited epochs directory: ./ - filename: PPP--.rts + suffix: _smoothed inverter: LDLT #LLT LDLT INV @@ -154,8 +217,8 @@ estimation_parameters: pos: estimated: [true] - sigma: [0.1] - proc_noise: [0] + sigma: [100] + proc_noise: [100] proc_noise_dt: second clk: @@ -184,8 +247,6 @@ estimation_parameters: trop_grads: estimated: [true] - sigma: [0.02] + sigma: [0.005] proc_noise: [1.0E-6] proc_noise_dt: second - - diff --git a/examples/ex12_pea_pp_user_gnss.yaml b/examples/ex12_pea_pp_user_gnss.yaml index 448139780..4d96a05f4 100644 --- a/examples/ex12_pea_pp_user_gnss.yaml +++ b/examples/ex12_pea_pp_user_gnss.yaml @@ -7,7 +7,7 @@ inputs: root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # Antenna models for receivers and satellites in ANTEX format - snx_files: [ "igs*.snx" ] # SINEX file for meta data and initial position + snx_files: [ "igs*.snx", tables/igs_satellite_metadata_2203_plus.snx ] # SINEX file for meta data and initial position blq_files: [ OLOAD_GO.BLQ ] # ocean loading is applied satellite_data: @@ -15,15 +15,20 @@ inputs: sp3_files: [ TUG0R03FIN_20191990000_01D_05M_ORB.SP3 ] # satellite orbit files in SP3 format clk_files: [ TUG0R03FIN_20191990000_01D_30S_CLK.CLK ] # satellite clock files in RNX CLK format bsx_files: [ TUG0R03FIN_20191990000_01D_01D_OSB.BIA ] # daily signal biases files + # obx_files: [ TUG0R03FIN_20191990000_01D_30S_ATT.OBX ] # satellite attitude files in orbex format troposphere: - vmf3_directory: grid5/ + vmf_files: [grid5/VMF3_20190718.H00, grid5/VMF3_20190718.H06, grid5/VMF3_20190718.H12, grid5/VMF3_20190718.H18] orography_files: orography_ell_5x5 - # gpt2grid_files: EX03/general/gpt_25.grd - + # gpt2grid_files: gpt_25.grd + + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat] + gnss_observations: - root_directory: ../data/ - rnx_files: + inputs_root: data/ + rnx_inputs: # Select files to run by: - "ALIC*.rnx" # ALIC station rnx file will be found # - "*.rnx" # - searching all in file_root directory @@ -36,7 +41,7 @@ outputs: root_directory: / trace: - output_stations: true + output_stations: true level: 3 directory: ./ station_filename: -.TRACE @@ -56,19 +61,16 @@ outputs: analysis_program: AUSACS rinex_comment: AUSNETWORK1 - rinex_nav: - output: true - directory: ./ - filename: _nav_.rnx - version: 4.00 # 3.05 or 4.00 + ppp_sol: + output: true + filename: _.POS mongo: - enable: true - output_measurements: true - output_states: true + enable: false + output_measurements: false + output_states: false #delete_history: true uri: mongodb://127.0.0.1:27017 - suffix: __ processing_options: @@ -86,32 +88,33 @@ processing_options: elevation_mask: 7 #degrees - reject_eclipse: true # reject observation during satellite eclipse periods raim: true max_gdop: 30 sys_options: gps: process: true - clock_codes: [L1C, L2W] + reject_eclipse: false code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, L5I, L5Q, L5X] gal: process: true - clock_codes: [L1C, L5Q] + reject_eclipse: false code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, - L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, L5I, L5Q, L5X] gnss_models: - troposphere: model: vmf3 #gpt2 - + sat_attitude: + sources: [MODEL] + valid_var: 0.01 + invalid_var: 1 + filter_options: @@ -168,40 +171,3 @@ estimation_parameters: sigma: [0.02] proc_noise: [1.0E-6] proc_noise_dt: second - - satellites: - - clk: - #estimated: [true] - # sigma: [0] - # proc_noise: [0.03651483716701108] - #proc_noise_dt: min - - clk_rate: - #estimated: [true] - # sigma: [500] - # proc_noise: [1e-4] - - orb: - #estimated: [true] - - - overrides: - - stations: - - #ALIC: - #pos: - # sigma: [60] - - #proc_noise: [0] - #clk: - #sigma: [0.01] - - #AGGO: - #exclude: true - #ALIC: - #exclude: true - #ANKR: - #exclude: true - #estimated: false diff --git a/examples/ex13_pea_pp_user_gps_sf.yaml b/examples/ex13_pea_pp_user_gps_sf.yaml index f0ff36624..5a06f6371 100644 --- a/examples/ex13_pea_pp_user_gps_sf.yaml +++ b/examples/ex13_pea_pp_user_gps_sf.yaml @@ -7,24 +7,29 @@ inputs: root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # Antenna models for receivers and satellites in ANTEX format - snx_files: [ "igs*.snx" ] # SINEX file for meta data and initial position + snx_files: [ "igs*.snx", tables/igs_satellite_metadata_2203_plus.snx ] # SINEX file for meta data and initial position blq_files: [ OLOAD_GO.BLQ ] # ocean loading is applied - ion_files: [ codg1990.19i ] # Ionospheric delay maps in IONEX format troposphere: gpt2grid_files: gpt_25.grd - + + ionosphere: + ion_files: [ codg1990.19i ] # Ionospheric delay maps in IONEX format + + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat] + satellite_data: nav_files: [ brdm1990.19p ] # broadcast navigation file sp3_files: [ COD0MGXFIN_20191990000_01D_05M_ORB.SP3 ] # satellite orbit files in SP3 format clk_files: [ COD0R03FIN_20191990000_01D_30S_CLK.CLK ] # satellite clock files in RNX CLK format - # dcb_files: [ ] # DCB files for Ionosphere may be provided separately gnss_observations: - root_directory: ../data/ + inputs_root: data/ - rnx_files: + rnx_inputs: # Select files to run by: #- "AGGO*.rnx" - ALIC00AUS_R_20191990000_01D_30S_MO.rnx # - selecting them individually below, or @@ -47,7 +52,7 @@ outputs: ppp_sol: output: true - filename: SF_.POS + filename: _.POS metadata: @@ -58,23 +63,13 @@ outputs: analysis_program: AUSACS rinex_comment: AUSNETWORK1 -mongo: - enable: true - output_measurements: true - output_states: true - output_test_stats: true - #delete_history: true - uri: mongodb://127.0.0.1:27017 - suffix: _ - processing_options: epoch_control: start_epoch: 2019-07-18 00:00:00 # end_epoch: 2019-07-18 03:59:30 epoch_interval: 30 #seconds - # max_epochs: 120 #0 is infinite - # wait_next_epoch: 3600 + max_epochs: 360 #0 is infinite process_modes: user: true @@ -82,16 +77,14 @@ processing_options: gnss_general: elevation_mask: 7 #degrees - reject_eclipse: true # reject observation during satellite eclipse periods raim: true max_gdop: 30 sys_options: gps: - process: true - code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, - L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, - L5I, L5Q, L5X] + process: true + reject_eclipse: true + code_priorities: [ L1C ] gnss_models: @@ -155,32 +148,3 @@ estimation_parameters: sigma: [1] proc_noise: [0.01] proc_noise_dt: second - - satellites: - - clk: - #estimated: [true] - clk_rate: - #estimated: [true] - orb: - #estimated: [true] - - - overrides: - - stations: - - #ALIC: - #pos: - # sigma: [60] - #proc_noise: [0] - #clk: - #sigma: [0.01] - - #AGGO: - #exclude: true - #ALIC: - #exclude: true - #ANKR: - #exclude: true - #estimated: false diff --git a/examples/ex14_pea_pp_user_gnss_ar.yaml b/examples/ex14_pea_pp_user_gnss_ar.yaml index 8bb86b89c..f034f1b9f 100644 --- a/examples/ex14_pea_pp_user_gnss_ar.yaml +++ b/examples/ex14_pea_pp_user_gnss_ar.yaml @@ -3,27 +3,32 @@ inputs: root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # Antenna models for receivers and satellites in ANTEX format - snx_files: [ "*.snx" ] # SINEX file for meta data and initial position + snx_files: [ igs19P2062.snx, tables/igs_satellite_metadata_2203_plus.snx ] # SINEX file for meta data and initial position blq_files: [ OLOAD_GO.BLQ ] # ocean loading is applied erp_files: [ COD0R03FIN_20191990000_01D_01D_ERP.ERP ] troposphere: - # vmf3dir: grid5/ - # orography: orography_ell_5x5 + # vmf_files: [grid5/VMF20190718.H00, grid5/VMF20190718.H06, grid5/VMF20190718.H12, grid5/VMF20190718.H18] + # orography: orography_ell_5x5 gpt2grid_files: gpt_25.grd - + + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat] + satellite_data: + nav_files: [ brdm1990.19p ] # broadcast navigation file sp3_files: [ COD0MGXFIN_20191990000_01D_05M_ORB.SP3 ] # satellite orbit files in SP3 format clk_files: [ COD0R03FIN_20191990000_01D_30S_CLK.CLK ] # satellite clock files in RNX CLK format bsx_files: [ COD0R03FIN_20191990000_01D_01D_OSB.BIA ] # daily signal biases files gnss_observations: - root_directory: ../data/ - rnx_files: + inputs_root: data/ + rnx_inputs: # Select files to run by: - - "AREQ*.rnx" # ALIC station rnx file will be found - - "AREG*.rnx" + - "AREQ00PER_R_20191990000_01D_30S_MO.rnx" # ALIC station rnx file will be found + - "AREG00PER_R_20191990000_01D_30S_MO.rnx" # - ALIC00AUS_R_20191990000_01D_30S_MO.rnx # - selecting them individually below, or # - selecting one on the command line using the -rnxfiles option @@ -33,11 +38,14 @@ outputs: root_directory: / trace: - output_stations: true + output_stations: true + output_network: true level: 2 directory: ./ station_filename: .TRACE + network_filename: Network_trace.SUM output_residuals: true + output_config: true sinex: output: true @@ -45,7 +53,7 @@ outputs: ppp_sol: output: true - filename: _.POS + filename: _.POS log: output: true @@ -59,12 +67,11 @@ outputs: rinex_comment: AUSNETWORK1 mongo: - enable: true - output_measurements: true - output_states: true + enable: false + output_measurements: false + output_states: false delete_history: false uri: mongodb://127.0.0.1:27017 - suffix: "_sol" debug: unit_tests: @@ -86,7 +93,6 @@ processing_options: elevation_mask: 10 #degrees - reject_eclipse: true # reject observation during satellite eclipse periods raim: true max_gdop: 30 @@ -95,20 +101,14 @@ processing_options: sys_options: gps: process: true - clock_codes: [L1C, L2W] ambiguity_resolution: true - - code_priorities: [ L1C, - L2W, - L5Q, L5X] + reject_eclipse: true + code_priorities: [ L1C, L2W ] gal: process: true - clock_codes: [L1C, L5Q] ambiguity_resolution: false - - code_priorities: [ L1C, - L2W, - L5Q, L5X] + reject_eclipse: true + code_priorities: [ L1C,L1X, L5Q, L5X] model_error_checking: ambiguities: @@ -208,10 +208,3 @@ estimation_parameters: orb: #estimated: [true] - - overrides: - stations: - AREG: - pos: - proc_noise: [0] - diff --git a/examples/ex15_pea_rt_user_gnss_ar.yaml b/examples/ex15_pea_rt_user_gnss_ar.yaml index ea306ba06..ef9b746bc 100644 --- a/examples/ex15_pea_rt_user_gnss_ar.yaml +++ b/examples/ex15_pea_rt_user_gnss_ar.yaml @@ -7,7 +7,7 @@ inputs: root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # required - snx_files: [ meta_gather_20210721.snx ] # required + snx_files: [ meta_gather_20210721.snx, tables/igs_satellite_metadata_2203_plus.snx ] # required blq_files: [ OLOAD_GO.BLQ ] # required if ocean loading is applied troposphere: @@ -15,28 +15,30 @@ inputs: #vmf3_directory: grid5/ #orography_files: orography_ell_5x5 + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat] + gnss_observations: - root_directory: ../data/recordings/ + inputs_root: recordings/ - rtcm_files: - - "*OBS.rtcm3" - - #streams: - # - "https://:@ntrip.data.gnss.ga.gov.au/ALIC00AUS0" + rtcm_inputs: + - "*OBS.rtcm" + #- "https://:@ntrip.data.gnss.ga.gov.au/ALIC00AUS0" + #- "https://:@ntrip.data.gnss.ga.gov.au/AGGO00AUS0" + #- "https://:@ntrip.data.gnss.ga.gov.au/DARW00AUS0" satellite_data: - root_directory: ../data/recordings/ + inputs_root: recordings/ - rtcm_files: + #inputs_root: "https://:@ntrip.data.gnss.ga.gov.au/" + + rtcm_inputs: + #- "BCEP00DLR0" + #- "SSRA02IGS0" - "*NAV.rtcm3" - - #root_stream_url: "https://:@ntrip.data.gnss.ga.gov.au/ - #streams: - # - "BCEP00DLR0" - # - "SSRA02IGS0" - - + outputs: root_directory: / @@ -65,6 +67,37 @@ outputs: analysis_center: Geoscience Australia analysis_program: AUSACS rinex_comment: AUSNETWORK1 + + decoded_rtcm: + output: true + filename: -_decoded_rtcm.json + + rinex_nav: + output: true + filename: BRDC_.rnx + + rinex_obs: + output: true + filename: _.rnx + + rtcm_nav: + #output: true + filename: --NAV.rtcm3 + rtcm_obs: + #output: true + filename: --OBS.rtcm3 + + ntrip_log: + output: true + +mongo: + enable: true + output_measurements: true + output_states: true + #output_test_stats: true + #delete_history: true + uri: mongodb://127.0.0.1:27017 + suffix: _ processing_options: @@ -84,13 +117,12 @@ processing_options: #simulate_real_time: true process_modes: - user: true + ppp: true gnss_general: elevation_mask: 10 #degrees - reject_eclipse: true # reject observation during satellite eclipse periods raim: true delete_old_ephemerides: true @@ -100,6 +132,7 @@ processing_options: gps: process: true ambiguity_resolution: true + reject_eclipse: true code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, L5X, L5Q, L5I, @@ -109,24 +142,26 @@ processing_options: gal: process: true ambiguity_resolution: true + reject_eclipse: true code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, L5X, L5Q, L5I, L6Q, L6I, L6X, L7Q, L7X, L7I] - - gnss_models: troposphere: model: gpt2 #vmf3 sat_pos: - source: ssr # broadcast ssr precise + sources: [ssr, broadcast] # broadcast ssr precise ionospheric_component: corr_mode: iono_free_linear_combo iflc_freqs: l1l2_only #any l1l2_only l1l5_only + + sat_attitude: + #enable: false ambiguity_resolution: elevation_mask: 15 @@ -200,6 +235,12 @@ estimation_parameters: proc_noise: [1.0E-6] proc_noise_dt: second + ion_stec: + estimated: [true] + sigma: [10] + proc_noise: [10] + proc_noise_dt: second + satellites: clk: @@ -216,49 +257,3 @@ estimation_parameters: orb: #estimated: [true] - - overrides: - - stations: - - #ALIC: - # pos: - # sigma: [60] - # proc_noise: [0] - #clk: - #sigma: [0.01] - - #AGGO: - #exclude: true - #ALIC: - #exclude: true - #ANKR: - #exclude: true - #estimated: false - - satellites: - - ### Constellation Overrides - #SYS_GPS: - #srp: - #sigma: [0.01] - #proc_noise: [0.001] - - ### Block Type Overrides - #GPS-IIR-A: - #pos: { sigma: [10.0] } - #vel: { sigma: [0.1] } - - ### PRN Overrides - #PRN_G10: - #pos: { sigma: [10.0] } - #vel: { sigma: [0.1] } - #clk: { sigma: [1.0] } - - #PRN_G15: - #exclude: true - - ### SVN Overrides - #SVN_G265: - #pos: {sigma: [10.0] } - #vel: {sigma: [0.1] } diff --git a/examples/ex16_pea_pp_ionosphere.yaml b/examples/ex16_pea_pp_ionosphere.yaml index b2399c688..4e6796318 100644 --- a/examples/ex16_pea_pp_ionosphere.yaml +++ b/examples/ex16_pea_pp_ionosphere.yaml @@ -4,7 +4,7 @@ inputs: root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # required - snx_files: [ igs19P2062.snx ] # required + snx_files: [ igs19P2062.snx, tables/igs_satellite_metadata_2203_plus.snx ] # required blq_files: [ OLOAD_GO.BLQ ] # required if ocean loading is applied erp_files: [ TUG0R03FIN_20191990000_01D_01D_ERP.ERP ] # config parser doesn't accept weekly files yet. @@ -12,15 +12,20 @@ inputs: nav_files: [ brdm1990.19p ] # broadcast navigation file sp3_files: [ TUG0R03FIN_20191990000_01D_05M_ORB.SP3 ] # satellite orbit files in SP3 format clk_files: [ TUG0R03FIN_20191990000_01D_30S_CLK.CLK ] # satellite clock files in RNX CLK format + bsx_files: [ TUG0R03FIN_20191990000_01D_01D_OSB.BIA ] # satellite hardware biases in BSX format troposphere: # vmf3dir: grid5/ # orography: orography_ell_5x5 gpt2grid_files: gpt_25.grd + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat] + gnss_observations: - root_directory: ../data/ - rnx_files: + inputs_root: data/ + rnx_inputs: - "*.rnx" # - searching all in file_root directory, or outputs: @@ -32,15 +37,15 @@ outputs: output_network: true level: 2 directory: ./ - station_filename: --.TRACE - network_filename: --.TRACE + station_filename: _.TRACE + network_filename: _.TRACE output_residuals: true output_config: true ionex: output: true directory: ./ - filename: AUSG0.I + filename: 0GINRPD00_02H_05M_GIM.INX grid: lat_center: 0 lon_center: 2.5 @@ -58,9 +63,9 @@ outputs: bias_sinex: output: true directory: ./ - filename: AUS0ACSRAP_00_01D_01D_REL.BIA - output_interval: 600 - + filename: 0GINRPD00_01D_01D_OSB.BIA + code_output_interval: 86400 + sinex: output: true @@ -68,20 +73,21 @@ outputs: config_description: ex16 analysis_agency: GAA analysis_center: Geoscience Australia - analysis_program: AUSACS - rinex_comment: AUSNETWORK1 + analysis_program: GINAN + rinex_comment: IGS processing_options: epoch_control: - start_epoch: 2019-07-18 00:00:00 - # end_epoch: 2019-07-18 23:59:30 - max_epochs: 200 #0 is infinite - epoch_interval: 30 #seconds + start_epoch: 2019-07-18 00:00:00 + # end_epoch: 2019-07-18 23:59:30 + max_epochs: 241 #0 is infinite + epoch_interval: 30 #seconds process_modes: - ionosphere: true + # ppp: true + ionosphere: true gnss_general: error_model: elevation_dependent @@ -92,45 +98,108 @@ processing_options: elevation_mask: 10 #degrees - reject_eclipse: true #reject observation during satellite eclipse periods raim: true max_gdop: 30 pivot_station: "USN7" sys_options: gps: - process: true - code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, - L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, - L5I, L5Q, L5X] - - + process: true + reject_eclipse: true #reject observation during satellite eclipse periods + use_for_iono_model: true + code_priorities: [ L1C, L2W ] + gnss_models: troposphere: model: gpt2 ionospheric_component: - corr_mode: iono_free_linear_combo - iflc_freqs: l1l2_only #any l1l2_only l1l5_only + common_ionosphere: true + use_if_combo: false ionospheric_model: model: spherical_harmonics # meas_out, spherical_harmonics function_order: 8 layer_heights: [450] - model_noise: 0.01 filter_options: + inverter: ldlt #LLT LDLT INV + outlier_screening: - max_filter_iterations: 5 - #max_prefit_removals: 4 + max_filter_iterations: 10 + max_prefit_removals: 2 + + rts: + enable: true + lag: -1 #-ve for full reverse, +ve for limited epochs + directory: ./ + filename: -Network.rts -estimation_parameters: - stations: +estimation_parameters: + stations: + error_model: elevation_dependent #uniform elevation_dependent + code_sigmas: [0.3] + phase_sigmas: [0.003] + + pos: + estimated: [true] + sigma: [100.0] + proc_noise: [0] + proc_noise_dt: second + + clk: + estimated: [true] + sigma: [1000] + proc_noise: [100] + + amb: + estimated: [true] + sigma: [1000.0] + proc_noise: [0] + #proc_noise_dt: day + + trop: + estimated: [true] + sigma: [0.1] + proc_noise: [0.0001] + proc_noise_dt: second + + trop_grads: + estimated: [true] + sigma: [0.02] + proc_noise: [1.0E-6] + proc_noise_dt: second + + ion_stec: + estimated: [true] + sigma: [200] + proc_noise: [0.1] + + phase_bias: + estimated: [true] + sigma: [10] + proc_noise: [0] + + code_bias: + estimated: [true] + sigma: [100.0] + proc_noise: [0] + + ion: + estimated: [true] + sigma: [100] + proc_noise: [0.01] + + satellites: + code_bias: + estimated: [true] + sigma: [100.0] + proc_noise: [0] debug: unit_tests: #enable: true diff --git a/examples/ex17_pea_pp_netw_gnss_ar.yaml b/examples/ex17_pea_pp_netw_gnss_ar.yaml index 7b92b4b5c..f91e9bb99 100644 --- a/examples/ex17_pea_pp_netw_gnss_ar.yaml +++ b/examples/ex17_pea_pp_netw_gnss_ar.yaml @@ -1,46 +1,97 @@ - # ex17 - Network Example -# Uses TU GRAZ orbit to solve for satellite clocks (GPS-only, resolved ambiguities) +# Uses IGS final orbit to solve for satellite clocks (GPS-only, resolved ambiguities) # Estimates clocks inputs: root_directory: products/ - atx_files: [ igs14_2045_plus.atx ] # required - snx_files: [ igs19P2062.snx ] # required + atx_files: [ igs20.atx ] # required + #atx_files: [ igsR3_2077.atx ] # required + #atx_files: [ igs14_2045_plus.atx ] # required + snx_files: [ IGS1R03SNX_20192000000_01D_01D_CRD.SNX, tables/igs_satellite_metadata_2203_plus.snx ] # required + #snx_files: [ igs19P2062.snx, tables/igs_satellite_metadata_2203_plus.snx ] # required blq_files: [ OLOAD_GO.BLQ ] # required if ocean loading is applied - erp_files: [ igs19P2062.erp ] + erp_files: [ IGS1R03SNX_20191950000_07D_01D_ERP.ERP ] + #erp_files: [ igs19P2062.erp ] satellite_data: - # nav_files: [ brdm1990.19p ] - # sp3_files: [ igs20624.sp3 ] - # dcb_files: # monthly DCB file - # bsx_files: [ CAS0MGXRAP_20191990000_01D_01D_DCB.BSX ] - # clk_files: [ jpl20624.clk ] # Clk file - # orb_files: [ orb_partials/gag20624_orbits_partials.out.eop_test23 ] # only need this if we are estimating orbits - - nav_files: [ brdm1990.19p ] # broadcast navigation file - sp3_files: [ TUG0R03FIN_20191990000_01D_05M_ORB.SP3 ] # satellite orbit files in SP3 format - # clk_files: [ TUG0R03FIN_20191990000_01D_30S_CLK.CLK ] # satellite clock files in RNX CLK format - # dcb_files: [ TUG0R03FIN_20191990000_01D_01D_OSB.BIA ] # daily signal biases files - + nav_files: [ brdm1990.19p ] + #sp3_files: [ igs20624.sp3 ] + #bsx_files: [ code_monthly.bia ] + #clk_files: [ igs20624.clk_30s ] + sp3_files: [ IGS2R03FIN_20191990000_01D_05M_ORB.SP3 ] + bsx_files: [ IGS2R03FIN_20191990000_01D_01D_OSB.BIA ] + #clk_files: [ IGS2R03FIN_20191990000_01D_30S_CLK.CLK ] + + egm_files: [ tables/EGM2008.gfc ] # Earth gravity model coefficients file + jpl_files: [ tables/DE436.1950.2050 ] # JPL planetary and lunar ephemerides file + tide_files: [ tables/fes2014b_Cnm-Snm.dat ] troposphere: - vmf3_directory: grid5/ - orography_files: orography_ell_5x5 - # gpt2grid: EX03/general/gpt_25.grd - + orography_files: orography_ell_5x5 + gpt2grid_files: gpt_25.grd + vmf_files: [ grid5/VMF3_20190718.H00, grid5/VMF3_20190718.H06, grid5/VMF3_20190718.H12, grid5/VMF3_20190718.H18, grid5/VMF3_20190719.H00 ] + gnss_observations: - root_directory: ../data/ + inputs_root: data/ - rnx_files: - - "AGGO*.rnx" + rnx_inputs: + - "CPVG*.rnx" + - "DJIG*.rnx" + - "DUMG*.rnx" + - "GAMB*.rnx" + - "GLPS*.rnx" + - "HARB*.rnx" + - "KOKV*.rnx" + - "NYA2*.rnx" + - "OHI3*.rnx" + - "NYA2*.rnx" + - "MAW1*.rnx" + - "STK2*.rnx" + - "URUM*.rnx" + - "COCO*.rnx" + - "KRGG*.rnx" + - "ASCG*.rnx" + - "PTGG*.rnx" + - "OUS2*.rnx" + - "KITG*.rnx" + - "ULAB*.rnx" + - "RAEG*.rnx" + - "BAKE*.rnx" + - "LHAZ*.rnx" + - "KZN2*.rnx" + - "MCIL*.rnx" + - "BSHM*.rnx" + - "REYK*.rnx" + - "LMMF*.rnx" + - "VACS*.rnx" + - "AREG*.rnx" + - "KARR*.rnx" + - "HOB2*.rnx" + - "PERT*.rnx" + - "RABT*.rnx" + - "DUBO*.rnx" + - "MDO1*.rnx" + - "MBAR*.rnx" + - "PERT*.rnx" + - "JFNG*.rnx" + - "NKLG*.rnx" + - "DARW*.rnx" + - "PNGM*.rnx" + - "MIKL*.rnx" + - "SYDN*.rnx" + - "YKRO*.rnx" + - "NRMG*.rnx" + - "CZTG*.rnx" + - "IQAL*.rnx" + #- "AGGO*.rnx" + #- "FFMJ*.rnx" + - "ZIM2*.rnx" - "CEDU*.rnx" - "DGAR*.rnx" - "FAIR*.rnx" - - "FFMJ*.rnx" - "HERS*.rnx" - "IISC*.rnx" - "KIRI*.rnx" @@ -56,8 +107,6 @@ inputs: - "TOPL*.rnx" - "TOW2*.rnx" - "USN7*.rnx" - - "ZIM2*.rnx" - outputs: @@ -66,7 +115,7 @@ outputs: trace: output_stations: true output_network: true - level: 2 + level: 4 directory: ./ station_filename: --.TRACE network_filename: --.TRACE @@ -74,8 +123,8 @@ outputs: output_config: true output_rotation: - period: 6 - period_units: hours + period: 1 + period_units: day ionex: output: false @@ -89,10 +138,13 @@ outputs: bias_sinex: output: true + code_output_interval: 900.0 directory: ./ - filename: AUS0ACSRAP_00_01D_01D_REL.BIA - output_interval: 900 - + filename: -.BIA + #filename: AUS0ACSRAP_00_01D_01D_REL.BIA + output_rec_bias: false + phase_output_interval: 900.0 + clocks: output: true directory: ./ @@ -107,10 +159,17 @@ outputs: trop_sinex: output: true - source: KALMAN + sources: [KALMAN] directory: ./ filename: -.tro + cost: + output: true + sources: [KALMAN] + directory: ./ + filename: cost_s_t__ga__.dat + time_interval: 300 + metadata: config_description: ex17 @@ -121,22 +180,24 @@ outputs: mongo: enable: true + database: output_measurements: true output_states: true output_rtcm_messages: true output_test_stats: true - #delete_history: true + delete_history: true uri: mongodb://127.0.0.1:27017 - suffix: "a" - rts_suffix: "_rts" + suffix: "" processing_options: epoch_control: - start_epoch: 2019-07-18 01:15:00 - end_epoch: 2019-07-18 22:30:00 - max_epochs: 12 #0 is infinite # comment for full day run + #start_epoch: 2019-07-18 14:40:00 + #start_epoch: 2019-07-18 12:00:00 + end_epoch: 2019-07-18 15:10:00 + #max_epochs: 12 #0 is infinite # comment for full day run epoch_interval: 60 #seconds + fatal_message_level: 1 model_error_checking: deweighting: @@ -145,34 +206,37 @@ processing_options: ambiguities: outage_reset_limit: 1 phase_reject_limit: 2 - + #reinit_on_all_slips: true # (bool) Any detected slips cause removal and reinitialisation of ambiguities + cycle_slips: - detect: + exclude: lli: false - + reset_on: + scdia: false process_modes: network: true + #ppp: true gnss_general: max_gdop: 30 elevation_mask: 10 #degrees - reject_eclipse: true raim: true + use_if_apc: true pivot_station: "USN7" #if not provided then will be selected automatically sys_options: gps: process: true - ambiguity_resolution: true - + ambiguity_resolution: false + reject_eclipse: false code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, - L5I, L5Q, L5X] - + #L5I, L5Q, L5X + ] gnss_models: @@ -182,50 +246,68 @@ processing_options: ionospheric_component: corr_mode: iono_free_linear_combo iflc_freqs: l1l2_only + #use_if_combo: false + + sat_pos: + source: precise - ambiguity_resolution: + #ambiguity_resolution: - elevation_mask: 15 + #elevation_mask: 15 - wide_lane: - mode: iter_rnd - success_rate_threshold: 0.9999 - solution_ratio_threshold: 3 - process_noise_sat: 0.00001 - process_noise_rec: 0.0001 + #wide_lane: + #mode: iter_rnd + #success_rate_threshold: 0.9999 + #solution_ratio_threshold: 3 + #process_noise_sat: 0.00001 + #process_noise_rec: 0.0001 - narrow_lane: - mode: iter_rnd - success_rate_threshold: 0.9999 - solution_ratio_threshold: 3 + #narrow_lane: + #mode: iter_rnd + #success_rate_threshold: 0.9999 + #solution_ratio_threshold: 3 - #lambda_set_size: 10 - #max_round_iterations: 3 + ##lambda_set_size: 10 + ##max_round_iterations: 3 ssr_corrections: - calculate_precursors: true + calculate_precursors: false minimum_constraints: enable: true + once_per_epoch: true # (bool) Perform minimum constraints on a temporary filter and output results once per epoch + translation: estimated: [true] rotation: estimated: [true] - - - + scale: + estimated: [false] + #sigma: [1] + inverter: ldlt #full_vcv: true - scale_by_vcv: true - default_station_noise: [1] #constrain all by default + #scale_by_vcv: true + max_filter_iterations: 10 + max_prefit_removals: 5 # (int) Maximum number of measurements to exclude using prefit checks before attempting to filter + outlier_screening: + chi_square_mode: none # (enum) Chi-square test mode - innovation, measurement, state {NONE,INNOVATION,MEASUREMENT,STATE} + chi_square_test: false # (bool) Enable Chi-square test + sigma_check: true # (bool) Enable prefit and postfit sigma check + sigma_threshold: 3.000000 # (float) sigma threshold + w_test: false # (bool) Enable w-test + + #default_station_noise: [1] #constrain all by default + #default_station_noise: [0.01, 0.01, 0.01] #constrain all by default station_noise: + global: [0.01, 0.01, 0.01] # ALIC: 0.001 #constrain strongly - #STN3: [20] - #DONT: [-1] + # STN3: [20] + # DONT: [-1] # BOAV: 100 #constrain weakly @@ -238,10 +320,10 @@ processing_options: max_prefit_removals: 2 rts: - enable: true + #enable: true lag: -1 #-ve for full reverse, +ve for limited epochs directory: ./ - filename: -Network.rts + filename: -Netwuseork.rts estimation_parameters: @@ -251,49 +333,112 @@ estimation_parameters: code_sigmas: [0.3333] phase_sigmas: [0.0033] - pos: - estimated: [true] - sigma: [0.01] - proc_noise: [0] - - clk: - estimated: [true] - sigma: [1000] - proc_noise: [10] - proc_noise_dt: sqrt_second - - amb: - estimated: [true] - sigma: [100] - proc_noise: [0] - - trop: - estimated: [true] - sigma: [0.3] - proc_noise: [0.0001] #0.1 mm - proc_noise_dt: sqrt_second - - trop_grads: - estimated: [true] - sigma: [0.02] - proc_noise: [1.0E-6] - proc_noise_dt: sqrt_second + global: + pos: + estimated: [true] + sigma: [1.0] + proc_noise: [0] + + clk: + estimated: [true] + sigma: [1000] + proc_noise: [10] + proc_noise_dt: sqrt_second + + amb: + estimated: [true] + sigma: [1000] + proc_noise: [0] + + phase_bias: + estimated: [true] + sigma: [10] + proc_noise: [0] + + code_bias: + estimated: [true] + sigma: [10] + proc_noise: [0] + + trop: + estimated: [true] + sigma: [0.3] + proc_noise: [0.0001] #0.1 mm + proc_noise_dt: sqrt_second + + trop_grads: + estimated: [true] + sigma: [0.03] + proc_noise: [1.0E-6] + proc_noise_dt: sqrt_second + + ion_stec: + estimated: [true] + sigma: [70] + proc_noise: [-1] + + USN7: + clk: + #estimated: [false] # Set reference (pivot) station clock + #sigma: [10] + #proc_noise: [1e-8] + + AGGO: + clk_rate: + estimated: [true] + sigma: [10] + proc_noise: [1e-8] + + CEDU: + trop_gauss_markov: + estimated: [true] + sigma: [0.05] + proc_noise: [0.01] + tau: [12600] + proc_noise_dt: sqrt_second + + trop_grads_gauss_markov: + estimated: [true] + sigma: [0.01] + proc_noise: [0.00549] + tau: [9216] + proc_noise_dt: second satellites: - clk: - estimated: [true] - sigma: [1000] - proc_noise: [1] - #proc_noise_dt: min - - # clk_rate: - # estimated: [true] - # sigma: [10] - # proc_noise: [1e-5] - - orb: - #estimated: [true] + global: + clk: + estimated: [true] + sigma: [1000] + proc_noise: [1] + #proc_noise_dt: min + + #clk_rate: + #estimated: [true] + #sigma: [10] + #proc_noise: [1e-5] + + #orb: + #estimated: [false] + + G01: + clk_rate: + estimated: [true] + sigma: [10] + proc_noise: [1e-5] + + G02: + clk_rate: + estimated: [true] + sigma: [0.1] + proc_noise: [1e-6] + + clk_rate_gauss_markov: + estimated: [true] + sigma: [0.05] + proc_noise: [1e-3] + proc_noise_dt: sqrt_second + tau: [86400] eop: estimated: [true] @@ -303,70 +448,6 @@ estimation_parameters: estimated: [true] sigma: [30] - - overrides: - - stations: - AGGO: - clk_rate: - estimated: [true] - sigma: [10] - proc_noise: [1e-8] - - CEDU: - trop_gauss_markov: - estimated: [true] - sigma: [0.05] - proc_noise: [0.01] - tau: [12600] - proc_noise_dt: sqrt_second - - trop_grads_gauss_markov: - estimated: [true] - sigma: [0.01] - proc_noise: [0.00549] - tau: [9216] - proc_noise_dt: second - - satellites: - - ### Constellation Overrides - #SYS_GPS: - #srp: - #sigma: [0.01] - #proc_noise: [0.001] - - #SYS_GAL: - #clk: - #sigma: [1.0] - #proc_noise: [0.01] - - ### Block Type Overrides - #GPS-IIR-A: - - ### PRN Overrides - - PRN_G01: - clk_rate: - estimated: [true] - sigma: [10] - proc_noise: [1e-5] - - PRN_G02: - - clk_rate: - estimated: [true] - sigma: [0.1] - proc_noise: [1e-6] - - clk_rate_gauss_markov: - estimated: [true] - sigma: [0.05] - proc_noise: [1e-3] - proc_noise_dt: sqrt_second - tau: [86400] - - ### SVN Overrides - #SVN_G265: - #pos: {sigma: [10.0] } - #vel: {sigma: [0.1] } +debug: + unit_tests: + #enable: true diff --git a/examples/ex18_pea_rt_netw_gnss_ar.yaml b/examples/ex18_pea_rt_netw_gnss_ar.yaml index e2b10d72e..006ba8e0c 100644 --- a/examples/ex18_pea_rt_netw_gnss_ar.yaml +++ b/examples/ex18_pea_rt_netw_gnss_ar.yaml @@ -7,7 +7,7 @@ inputs: root_directory: products/ atx_files: [ igs14_2045_plus.atx ] # required - snx_files: [ cod21620.snx ] # required + snx_files: [ cod21620.snx, tables/igs_satellite_metadata_2203_plus.snx ] # required blq_files: [ OLOAD_GO.BLQ ] # required if ocean loading is applied erp_files: [ "*.erp" ] # erps that go with ultras @@ -134,22 +134,26 @@ inputs: - BCEP00BKG0 outputs: - streams: - root_stream_url: "http://user:pass@tier3.auscors.ga.gov.au:2101/" - - #streams: - #- GGA1 - #GGA1: - #streams: "SSRA00GGA1" - #messages: - #- "1060" # RTCM messages to be broadcast - #- "1243" - #- "1059" - #- "1242" - #- "1265" - #- "1267" - + #streams: + # root_url: "http://user:pass@tier3.auscors.ga.gov.au:2101/" + # labels: + # - GGA1 + # GGA1: + # url: "SSRA00GGA1" + # messages: + # rtcm_1057: + # udi: 60 + # rtcm_1058: + # udi: 5 + # rtcm_1059: + # udi: 60 + # rtcm_1060: + # udi: 5 + # rtcm_1061: + # udi: 5 + # rtcm_1062: + # udi: 1 root_directory: / @@ -193,6 +197,7 @@ mongo: enable: true output_measurements: false output_states: false + #output_rtcm_messages: true #output_metadata: false delete_history: false @@ -294,6 +299,10 @@ processing_options: directory: ./ filename: PPP--.rts + #ssr_corrections: + # calculate_precursors: true + # prediction_interval: 10 + # ephemeris_source: PRECISE estimation_parameters: diff --git a/examples/ex31_pea_pp_netw_gnss_orb_ar.yaml b/examples/ex31_pea_pp_netw_gnss_orb_ar.yaml index 7d8fd8430..541a4af90 100644 --- a/examples/ex31_pea_pp_netw_gnss_orb_ar.yaml +++ b/examples/ex31_pea_pp_netw_gnss_orb_ar.yaml @@ -9,7 +9,7 @@ inputs: root_directory: products/ atx_files: [ igs14.atx ] # required - snx_files: [ igs19P2062.snx ] # required + snx_files: [ igs19P2062.snx, tables/igs_satellite_metadata_2203_plus.snx ] # required blq_files: [ OLOAD_GO.BLQ ] # required if ocean loading is applied erp_files: [ ../ex31/pod_fit/gag20624.erp ] #config parser doesn't accept weekly files yet. @@ -23,16 +23,16 @@ inputs: gnss_observations: - root_directory: ../data/ + inputs_root: data/ - rnx_files: + rnx_inputs: # Select files to run by: # - selecting one on the command line using the -rnxfiles option - "*.rnx" # - searching all in file_root directory, or # - "A*.rnx" # - searching all in file_root directory, or troposphere: - vmf3_directory: grid5/ + vmf_files: [ "grid5/*.H00","grid5/*.H06","grid5/*.H12","grid5/*.H18" ] orography_files: orography_ell_5x5 # gpt2grid: EX03/general/gpt_25.grd @@ -69,7 +69,8 @@ outputs: output: false directory: ./ filename: AUS0ACSRAP_00_01D_01D_REL.BIA - output_interval: 900 + phase_output_interval: 900 + code_output_interval: 900.0 clocks: output: true @@ -101,15 +102,14 @@ outputs: rinex_comment: AUSNETWORK1 mongo: - enable: true + enable: false output_measurements: true output_states: true output_rtcm_messages: true output_test_stats: true #delete_history: true uri: mongodb://127.0.0.1:27017 - suffix: _ - rts_suffix: _rts + debug: mincon_only: false @@ -135,7 +135,7 @@ processing_options: phase_reject_limit: 2 cycle_slips: - detect: + exclude: lli: false process_modes: @@ -152,7 +152,6 @@ processing_options: max_gdop: 30 elevation_mask: 10 #degrees - reject_eclipse: true raim: true pivot_station: "USN7" #if not provided then will be selected automatically @@ -161,7 +160,7 @@ processing_options: gps: process: true ambiguity_resolution: false - + reject_eclipse: true code_priorities: [ L1C, L1P, L1Y, L1W, L1M, L1N, L1S, L1L, L1X, L2W, L2P, L2Y, L2C, L2M, L2N, L2D, L2S, L2L, L2X, L5I, L5Q, L5X] @@ -269,7 +268,7 @@ processing_options: w_test: false # (bool) Enable w-test #default_station_noise: [1,1,1] #constrain all by defaul. [-1] to unconstrain all stations - default_station_noise: [0.003, 0.004, 0.007] + # default_station_noise: [0.003, 0.004, 0.007] #station_noise: # ALIC: 0.001 # constrain strongly @@ -387,7 +386,7 @@ estimation_parameters: estimated: [true] sigma: [30] - overrides: + # overrides: #stations: #AGGO: diff --git a/examples/record_streams.yaml b/examples/record_streams.yaml index d923d3a17..14b420a08 100644 --- a/examples/record_streams.yaml +++ b/examples/record_streams.yaml @@ -1,45 +1,58 @@ inputs: + + root_directory: products + gnss_observations: - satellite_data: - - root_stream_url: "https://:@ntrip.data.gnss.ga.gov.au/" - streams: + inputs_root: "https://:@ntrip.data.gnss.ga.gov.au/" + rtcm_inputs: - GATT00AUS0 - - ssr_antenna_offset: APC + + #rtcm_inputs: + #- "recordings/*.rtcm" + + satellite_data: + inputs_root: "https://:@ntrip.data.gnss.ga.gov.au/" + #rtcm_inputs: + #- GATT00AUS0 + rtcm_inputs: + - "BCEP00DLR0" + - "SSRA02IGS0" + + #sp3_files: [blah.sp3] + outputs: root_directory: recordings rtcm_nav: - record: true + output: true rinex_nav: - output: true + #output: true rtcm_obs: - record: true + output: true rinex_obs: + #output: true + + orbex: output: true - - decoded_rtcm: - output: true - directory: ./rtcm - + processing_options: epoch_control: epoch_interval: 1 #seconds - wait_next_epoch: 31 + wait_next_epoch: 10 wait_all_stations: 1 #max_epochs: 3600 require_obs: false + simulate_real_time: true process_modes: preprocessor: false @@ -51,4 +64,19 @@ processing_options: process: true gal: process: true + + gnss_models: + + tides: + #solid: false + #pole: false + #otl: false + troposphere: + model: vmf3 #gpt2 + sat_pos: + #source: broadcast + sat_clock: + #source: broadcast + sat_attitude: + source: model diff --git a/scripts/GinanEDA/GinanEDA/apps/meas.py b/scripts/GinanEDA/GinanEDA/apps/meas.py deleted file mode 100644 index 0d3a0c602..000000000 --- a/scripts/GinanEDA/GinanEDA/apps/meas.py +++ /dev/null @@ -1,366 +0,0 @@ -import logging - -import GinanEDA.apps.utilities as util -import numpy as np -import plotly.express as px -# Imports -import plotly.graph_objs as go -from app import app -from dash import dash_table, dcc, html -from dash.dependencies import Input, Output, State -from GinanEDA.datasets import db -from scipy.stats import normaltest, probplot -from statsmodels.graphics.gofplots import qqplot - -logger = logging.getLogger(__name__) - - -def qq_plot(data, sample_size): - d = (data - np.mean(data)) / np.std(data) - qq = np.ones([sample_size, 2]) - np.random.shuffle(d) - qq[:, 0] = np.sort(d[0:sample_size]) - qq[:, 1] = np.sort(np.random.normal(size=sample_size)) - return qq - - -possible_plot = ["Line", "Scatter", "Polar", "HistogramX", "HistogramY", "QQ"] -dropdown_type = html.Div( - [ - dcc.Dropdown( - id="mes_dropdown_type", - options=[{"label": i, "value": i} for i in possible_plot], - placeholder="Graph Type", - value=None, - ) - ], - style={"width": "10%", "display": "inline-block"}, -) - - -def check_list(): - return dcc.Checklist( - id="aggregate", - options=[ - {"label": "Aggregate (hist/stats)", "value": "agg"}, - ], - value=[""], - ) - - -def exclude_start(): - return html.Div( - [ - html.P( - "Exclude the first points", - style={"display": "inline-block", "margin-right": 5}, - ), - dcc.Input(id="exclude_npt", value="0", type="text", size="2"), - html.P(" points", style={"display": "inline-block", "margin-right": 5}), - ] - ) - - -def dropdown_site(site_list): - site_list2 = list(["ALL"]) - site_list2.extend(site_list) - p = util.namedDropdown( - None, - id="mes_dropdown_site", - options=[{"label": i, "value": i} for i in site_list2], - placeholder="Site", - value=None, - multi=True, - ) - p.style = {"width": "20%", "display": "inline-block"} - return p - - -def dropdown_sat(sat_list): - sat_list2 = list(["ALL"]) - sat_list2.extend(sat_list) - p = util.namedDropdown( - None, - id="mes_dropdown_sat", - options=[{"label": i, "value": i} for i in sat_list2], - placeholder="Sat", - value=None, - multi=True, - ) - p.style = {"width": "20%", "display": "inline-block"} - return p - - -def keys(name): - return [{"label": i, "value": i} for i in name if i not in db.exclude_measurements] - - -def dropdown_key_y(name): - p = util.namedDropdown( - None, - id="mes_dropdown_key_y", - options=[i for i in keys(name)], - placeholder="Y Axis", - value=None, - multi=True, - ) - p.style = {"width": "20%", "display": "inline-block"} - return p - - -def dropdown_key_x(name): - p = util.namedDropdown( - None, - id="mes_dropdown_key_x", - options=[i for i in keys(name)], - placeholder="X Axis", - value=None, - ) - p.style = {"width": "20%", "display": "inline-block"} - return p - - -update_button = html.Div( - [html.Button("update graph", id="update_graph", n_clicks=0)], - style={"width": "5%", "display": "inline-block"}, -) - - -def get_empty_graph(message): - emptiness = { - "layout": { - "xaxis": {"visible": False}, - "yaxis": { - "visible": False, - }, - "annotations": [ - { - "text": message, - "xref": "paper", - "yref": "paper", - "showarrow": False, - "font": {"size": 28}, - } - ], - } - } - return emptiness - - -def generate_trace(graph_type, x, y, label): - if graph_type == "Line" or graph_type == "Scatter": - if graph_type == "Line": - mode = "lines" - else: - mode = "markers" - trace = go.Scatter(x=x, y=y, mode=mode, name=label) - elif graph_type == "Polar": - trace = go.Scatterpolar(r=y, theta=x, mode="markers", name=label) - elif graph_type == "HistogramX": - trace = go.Histogram(x=y, name=label) - elif graph_type == "HistogramY": - trace = go.Histogram(y=y, name=label) - elif graph_type == "QQ": - trace = go.Scatter(x=x, y=y, mode="Scatter") - return trace - - -@app.callback( - Output("plot1", "figure"), - Output("tableDiv1", "children"), - inputs=[Input("update_graph", "n_clicks")], - state=[ - State("session-store", "data"), - State("mes_dropdown_type", "value"), - State("mes_dropdown_site", "value"), - State("mes_dropdown_sat", "value"), - State("mes_dropdown_key_x", "value"), - State("mes_dropdown_key_y", "value"), - State("mes_dropdown_site", "options"), - State("mes_dropdown_sat", "options"), - State("exclude_npt", "value"), - State("aggregate", "value"), - ], -) -def update_graph_measurements( - click, data_dict, graph_type, site, sat, xaxis, yaxis, list_site, list_sat, exclude, aggr -): - try: - exclude = int(exclude) - except: - exclude = 0 - print(" ==== ", data_dict, click) - table = [] - if exclude < 0: - exclude = 0 - if ( - graph_type is None - or site is None - or sat is None - or xaxis is None - or yaxis is None - ): - return ( - get_empty_graph("Make sure a value for all the Dropdown Menu is selected"), - [], - ) - else: - fig = go.Figure() - site = [i["value"] for i in list_site] if "ALL" in site else site - sat = [i["value"] for i in list_sat] if "ALL" in sat else sat - logger.debug( - f"\n Plotting request type {graph_type} \n\t\t sat {' ,'.join(sat)} \n\t\t site {' ,'.join(site)}" - ) - trace = [] - tab = [] - for yaxis_ in yaxis: - site_, sat_, x_, y_ = db.get_series(data_dict, - "Measurements", None, site, sat, xaxis, yaxis_ - ) - if graph_type == "QQ": - if "agg" in aggr: - _y = [] - for y in y_: - _y.append(y[exclude:]) # .ravel() - _y = np.concatenate(_y, axis=0) - qqplot_data = qq_plot(_y, len(_y)) - - trace.append( - generate_trace( - "Scatter", qqplot_data[:, 0], qqplot_data[:, 1], f"Agg" - ) - ) - trace.append( - generate_trace( - "Line", - [qqplot_data[0, 0], qqplot_data[-1, 0]], - [qqplot_data[0, 0], qqplot_data[-1, 0]], - f"Agg", - ) - ) - else: - for i in range(len(x_)): - qqplot_data = qq_plot(y_[i][exclude:], len(y_[i][exclude:])) - trace.append( - generate_trace( - "Scatter", - qqplot_data[:, 0], - qqplot_data[:, 1], - f"{site_[i]} {sat_[i]}", - ) - ) - elif "agg" in aggr and graph_type in ["HistogramX", "HistogramY"]: - _y = [] - for y in y_: - _y.append(y[exclude:]) # .ravel() - print(_y) - _y = np.concatenate(_y, axis=0) - print(_y) - trace.append( - generate_trace(graph_type, x_[0][exclude:], _y, f"{yaxis_}") - ) - a = dict() - a["ID"] = f"{yaxis_}" - a["RMS"] = np.sqrt(np.mean(np.square(_y))) - a["Mean"] = np.mean(_y) - a["Std"] = np.std(_y) - print(a) - table.append(a) - - else: - for i in range(len(x_)): - logging.debug(f"ploting data {site_[i]} {sat_[i]}") - _y = y_[i][exclude:] - label = [] - if len(site) != 1: - label.append(site_[i]) - if len(sat) != 1: - label.append(sat_[i]) - if len(yaxis) != 1: - label.append(yaxis_) - trace.append( - generate_trace( - graph_type, x_[i][exclude:], _y, f"{'-'.join(label)}" - ) - ) - if "agg" not in aggr: - if np.issubdtype(_y.dtype, np.float): - a = dict() - a["ID"] = f"{'-'.join(label)}" - a["RMS"] = np.sqrt(np.mean(np.square(_y))) - a["Mean"] = np.mean(_y) - a["Std"] = np.std(_y) - table.append(a) - if "agg" in aggr and np.issubdtype(y_[0].dtype, np.float): - _y = [] - for y in y_: - _y.append(y[exclude:]) # .ravel() - _y = np.concatenate(_y, axis=0) - - a = dict() - a["ID"] = f"{yaxis_}" - a["RMS"] = np.sqrt(np.mean(np.square(_y))) - a["Mean"] = np.mean(_y) - a["Std"] = np.std(_y) - table.append(a) - - - fig = go.Figure(data=trace) - cols = [] - cols.append("ID") - cols.append("RMS") - cols.append("Mean") - cols.append("Std") - tab = [ - dash_table.DataTable( - id="table", - columns=[{"name": i, "id": i} for i in cols], - data=table, - ) - ] - if graph_type == "QQ": - fig.update_layout( - xaxis=dict( - rangeslider=dict(visible=True), scaleanchor="y", scaleratio=1 - ), - yaxis=dict(fixedrange=False, tickformat=".3f"), - height=700, - width=700, - ) - else: - fig.update_layout( - xaxis=dict(rangeslider=dict(visible=True)), - yaxis=dict(fixedrange=False, tickformat=".3f"), - height=600, - ) - fig.layout.autosize = True - if graph_type == "Polar": - if yaxis == "Elevation": - fig.update_polars(radialaxis_range=[90, 0]) - if xaxis == "Azimuth": - fig.update_polars(angularaxis_direction="clockwise") - return fig, tab - - -def layout(data_dict): - if data_dict== None: - return html.Div( - [html.P("First you will need to select a DB in the Db Info menu")] - ) - else: - return html.Div( - [ - dropdown_type, - dropdown_site(data_dict['DB_SITE']), - dropdown_sat(data_dict['DB_SAT']), - dropdown_key_x(data_dict['DB_MEAS_KEY']), - dropdown_key_y(data_dict['DB_MEAS_KEY']), - exclude_start(), - check_list(), - update_button, - dcc.Graph( - id="plot1", figure=get_empty_graph("select information first") - ), - html.Div(id="tableDiv1", className="tableDiv"), - ] - ) diff --git a/scripts/GinanEDA/GinanEDA/apps/pos.py b/scripts/GinanEDA/GinanEDA/apps/pos.py deleted file mode 100644 index 382ccc3cc..000000000 --- a/scripts/GinanEDA/GinanEDA/apps/pos.py +++ /dev/null @@ -1,479 +0,0 @@ -import logging -from itertools import cycle -import GinanEDA.apps.utilities as util -import numpy as np -import plotly.express as px - -# Imports -import plotly.graph_objs as go -from app import app -from dash import dash_table, dcc, html -from dash.dependencies import Input, Output, State -from GinanEDA.datasets import db -from scipy.stats import normaltest, probplot -from statsmodels.graphics.gofplots import qqplot - -logger = logging.getLogger(__name__) - -colorcycle = cycle([ - "rgba( 99, 110, 250, 0.8)", - "rgba(171, 99, 250, 0.8)", - "rgba(239, 85, 59, 0.8)", - "rgba(255, 161, 90, 0.8)", - "rgba( 25, 211, 243, 0.8)", - "rgba(255, 102, 146, 0.8)", - "rgba(182, 232, 128, 0.8)", - "rgba(255, 151, 255, 0.8)", - "rgba(254, 203, 82, 0.8)"]) -colorcycleal = cycle([ - "rgba( 99, 110, 250, 0.1)", - "rgba(171, 99, 250, 0.1)", - "rgba(239, 85, 59, 0.1)", - "rgba(255, 161, 90, 0.1)", - "rgba( 25, 211, 243, 0.1)", - "rgba(255, 102, 146, 0.1)", - "rgba(182, 232, 128, 0.1)", - "rgba(255, 151, 255, 0.1)", - "rgba(254, 203, 82, 0.1)"]) - -possible_plot = ["XYZ", "NEU"] -dropdown_type = html.Div( - [ - dcc.Dropdown( - id="mes_dropdown_type", - options=[{"label": i, "value": i} for i in possible_plot], - placeholder="Graph Type", - value=None, - ) - ], - style={"width": "10%", "display": "inline-block"}, -) - - -def xyz2blh(x, y, z): - A = 6378137.0 - B = 6356752.314245 - e = np.sqrt(1 - (B ** 2) / (A ** 2)) - # calculate longitude, in radians - longitude = np.arctan2(y, x) - # calculate latitude, in radians - xy_hypot = np.hypot(x, y) - lat0 = 0 - latitude = np.arctan(z / xy_hypot) - while abs(latitude - lat0) > 1e-9: - lat0 = latitude - N = A / np.sqrt(1 - e ** 2 * np.sin(lat0) ** 2) - latitude = np.arctan((z + e ** 2 * N * np.sin(lat0)) / xy_hypot) - # calculate height, in meters - N = A / np.sqrt(1 - e ** 2 * np.sin(latitude) ** 2) - if abs(latitude) < np.pi / 4: - R, phi = np.hypot(xy_hypot, z), np.arctan(z / xy_hypot) - height = R * np.cos(phi) / np.cos(latitude) - N - else: - height = z / np.sin(latitude) - N * (1 - e ** 2) - # convert angle unit to degrees - longitude = np.degrees(longitude) - latitude = np.degrees(latitude) - - return latitude, longitude, height - - -def xyz2neu(x0, y0, z0, x, y, z): - A = 6378137.0 - E2 = 0.00669438 - E4 = 0.0067394968 - B = 0.1 - lat, lon, _ = xyz2blh(x0, y0, z0) - # convert angle unit to radians - lat, lon = np.radians(lat), np.radians(lon) - # calculate NEU - north = ( - -np.sin(lat) * np.cos(lon) * (x - x0) - - np.sin(lat) * np.sin(lon) * (y - y0) - + np.cos(lat) * (z - z0) - ) - east = -np.sin(lon) * (x - x0) + np.cos(lon) * (y - y0) - up = ( - np.cos(lat) * np.cos(lon) * (x - x0) - + np.cos(lat) * np.sin(lon) * (y - y0) - + np.sin(lat) * (z - z0) - ) - - return north, east, up - - -def exclude_start(): - return html.Div( - [ - html.P( - "Exclude the first points", - style={"display": "inline-block", "margin-right": 5}, - ), - dcc.Input(id="exclude_npt", value="0", type="text", size="2"), - html.P(" points", style={"display": "inline-block", "margin-right": 5}), - ] - ) - - -def dropdown_site(site_list): - site_list2 = list(["ALL"]) - site_list2.extend(site_list) - p = util.namedDropdown( - None, - id="mes_dropdown_site", - options=[{"label": i, "value": i} for i in site_list2], - placeholder="Site", - value=None, - multi=True, - ) - p.style = {"width": "20%", "display": "inline-block"} - return p - - -update_button = html.Div( - [html.Button("update graph", id="update_graph", n_clicks=0)], - style={"width": "5%", "display": "inline-block"}, -) - - -def get_empty_graph(message): - emptiness = { - "layout": { - "xaxis": {"visible": False}, - "yaxis": {"visible": False}, - "annotations": [ - { - "text": message, - "xref": "paper", - "yref": "paper", - "showarrow": False, - "font": {"size": 28}, - } - ], - } - } - return emptiness - - -def generate_trace(graph_type, x, y, label=None, error_x=None, error_y=None): - if graph_type == "Line" or graph_type == "Scatter": - if graph_type == "Line": - mode = "lines" - else: - mode = "markers" - trace = go.Scatter(x=x, y=y, mode=mode, name=label, error_x=error_x, error_y=error_y) - elif graph_type == "Polar": - trace = go.Scatterpolar(r=y, theta=x, mode="markers", name=label) - elif graph_type == "HistogramX": - trace = go.Histogram(x=y, name=label) - elif graph_type == "HistogramY": - trace = go.Histogram(y=y, name=label) - elif graph_type == "QQ": - trace = go.Scatter(x=x, y=y, mode="Scatter") - return trace - - -@app.callback( - Output("plot3", "figure"), - Input("update_graph", "n_clicks"), - State("session-store", "data"), - State("mes_dropdown_type", "value"), - State("mes_dropdown_site", "value"), - State("checklist", "value"), - State("exclude_npt", "value") -) -def update_graph_measurements(click, data_dict, graph_type, site, opt, exclude): - try: - exclude = int(exclude) - except: - exclude = 0 - if exclude < 0: - exclude = 0 - if graph_type is None or site is None: - return get_empty_graph( - "Make sure a value for all the Dropdown Menu is selected" - ) - else: - fig = go.Figure() - trace = [] - for st in data_dict['DB_STATE_DIC']: - if st["_id"] == "REC_POS": - break - l_site = [i for i in st["Site"] if i[-2:] != "_0"] - site = [i for i in l_site] if "ALL" in site else site - logger.info("Request done") - req = {} - for site_ in site: - pipeline = [ - {"$match": {"State": "REC_POS", "Site": site_}}, - {"$sort": {"Epoch": 1}}, - { - "$group": { - "_id": "$Site", - "Epoch": {"$push": "$Epoch"}, - "x0": {"$push": "$x0"}, - "x1": {"$push": "$x1"}, - "x2": {"$push": "$x2"}, - } - } - ] - if "unc" in opt: - pipeline[2]["$group"]["P0"] = {"$push": "$P0"} - pipeline[2]["$group"]["P1"] = {"$push": "$P1"} - pipeline[2]["$group"]["P2"] = {"$push": "$P2"} - req[site_] = pipeline - if graph_type == "NEU": - for st in data_dict['DB_STATE_DIC']: - if st["_id"] == "REC_POS": - break - l_site = [i for i in st["Site"] if i[-2:] == "_0"] - for site_ in site: - for l in l_site: - if l.split("_")[0] == site_.split("_")[0]: - pipeline = [ - {"$match": {"State": "REC_POS", "Site": l}}, - {"$sort": {"Epoch": 1}}, - { - "$group": { - "_id": "$Site", - "Epoch": {"$push": "$Epoch"}, - "x0": {"$push": "$x0"}, - "x1": {"$push": "$x1"}, - "x2": {"$push": "$x2"}, - } - } - ] - req[l.split("_")[0]] = pipeline - MONGO_CL = db.connect_client(data_dict['MONGO_URL'])[data_dict['MONGO_DB']] - answer = list(MONGO_CL["States"].aggregate([{"$facet": req}]))[0] - logger.info("Request done") - - for site_ in site: - print(site_) - data = answer[site_] - print(data) - # print(data) - time = np.array(data[0]["Epoch"])[exclude:] - x = np.array(data[0]["x0"])[exclude:] - y = np.array(data[0]["x1"])[exclude:] - z = np.array(data[0]["x2"])[exclude:] - if "unc" in opt: - dx0 = (np.array(data[0]["P0"]))[exclude:] - dx1 = (np.array(data[0]["P1"]))[exclude:] - dx2 = (np.array(data[0]["P2"]))[exclude:] - else: - dx0 = None - dx1 = None - dx2 = None - if graph_type == "XYZ": - if "plan" in opt: - if "unc" in opt: - data = go.Scatter3d(x=x, y=y, z=z, \ - marker=dict( - size=6, - color=np.sqrt(dx0 + dx1 + dx2), - colorscale=[(0, "green"), (0.03, "green"), (0.05, "purple"), - (0.10, "orange"), (1, "red")], - showscale=True, - cmin=0, - cmax=1 - ), - name=site_) - else: - data = go.Scatter3d(x=x, y=y, z=z, name=site_) - trace.append(data) - else: - c1 = next(colorcycle) - c2 = next(colorcycleal) - trace.append(go.Scatter(x=time, y=x, mode='lines', line=dict(color=c1), - name=f"{site_}-X", )) - if "unc" in opt: - trace.append( - go.Scatter( - x=np.concatenate([time, time[::-1]], axis=None), # x, then x reversed - y=np.concatenate([x + np.sqrt(dx0), x[::-1] - np.sqrt(dx0[::-1])], axis=None), - # upper, then lower reversed - fill='toself', - fillcolor=c2, - line=dict(color=c2), - hoverinfo="skip", - showlegend=True - ) - ) - - c1 = next(colorcycle) - c2 = next(colorcycleal) - trace.append(go.Scatter(x=time, y=y, mode='lines', line=dict(color=c1), - name=f"{site_}-Y", )) - if "unc" in opt: - trace.append( - go.Scatter( - x=np.concatenate([time, time[::-1]], axis=None), # x, then x reversed - y=np.concatenate([y + np.sqrt(dx1), y[::-1] - np.sqrt(dx1[::-1])], axis=None), - # upper, then lower reversed - fill='toself', - fillcolor=c2, - line=dict(color=c2), - hoverinfo="skip", - showlegend=True - ) - ) - - c1 = next(colorcycle) - c2 = next(colorcycleal) - trace.append(go.Scatter(x=time, y=z, mode='lines', line=dict(color=c1), - name=f"{site_}-Z", )) - if "unc" in opt: - trace.append( - go.Scatter( - x=np.concatenate([time, time[::-1]], axis=None), # x, then x reversed - y=np.concatenate([z + np.sqrt(dx2), z[::-1] - np.sqrt(dx2[::-1])], axis=None), - # upper, then lower reversed - fill='toself', - fillcolor=c2, - line=dict(color=c2), - hoverinfo="skip", - showlegend=True - ) - ) - else: - base = answer[site_.split('_')[0]] - # print(base) - # print(data) - # time = np.array(base[0]["Epoch"]) - x0 = np.array(base[0]["x0"])[0] - y0 = np.array(base[0]["x1"])[0] - z0 = np.array(base[0]["x2"])[0] - - lat, lon, h = xyz2blh(x0, y0, z0) - #using formula from https://gssc.esa.int/navipedia/index.php/Positioning_Error - lat, lon = np.radians(lat), np.radians(lon) - rot = np.array([[-np.sin(lon) , - np.cos(lon)*np.sin(lat), np.cos(lat) * np.cos(lon)], - [ np.cos(lon) , - np.sin(lat)*np.sin(lon), np.cos(lat) * np.sin(lon)], - [ 0 , np.cos(lat) , np.sin(lat) ] - ]) - # north, east, up = xyz2neu(x0[0], y0[0], z0[0], x + x0[0], y + y0[0], z + z0[0]) - enu = [] - for i in range(len(x)): - enu.append(rot.transpose().dot(np.array([x[i],y[i],z[i]]).transpose())) - enu = np.asarray(enu) - north = enu[:,1] - east = enu[:,0] - up = enu[:,2] - if "unc" in opt: - denu = [] - for i in range(len(dx0)): - P = np.diag([dx0[i],dx1[i],dx2[i]]) - denu.append(np.sqrt(np.diag(rot.transpose().dot(P).dot(rot)))) - - denu = np.asarray(denu) - delta_north = denu[:,1] - delta_east = denu[:,0] - delta_up = denu[:,2] - else: - delta_north = None - delta_east = None - delta_up = None - if "plan" in opt: - trace.append(go.Scatter(x=east, y=north, mode='lines+markers', name=f"{site_}-N", )) - if "unc" in opt: - marker = dict(size=6, - color=np.sqrt(dx0 ** 2 + dx1 ** 2 + dx2 ** 2), - colorscale=[(0, "green"), (0.03, "green"), (0.05, "purple"), (0.10, "orange"), - (1, "red")], - showscale=True, - cmin=0, - cmax=1 - ) - trace.append(go.Scatter(x=east, y=north, mode='lines+markers', name=f"{site_}-N", marker=marker)) - - else: - c1 = next(colorcycle) - c2 = next(colorcycleal) - trace.append(go.Scatter(x=time, y=north, mode='lines', line=dict(color=c1), - name=f"{site_}-N", )) - if "unc" in opt: - trace.append( - go.Scatter( - x=np.concatenate([time, time[::-1]], axis=None), # x, then x reversed - y=np.concatenate([north + delta_north, north[::-1] - delta_north[::-1]], axis=None), # upper, then lower reversed - fill='toself', - fillcolor=c2, - line=dict(color=c2), - hoverinfo="skip", - showlegend=True - ) - ) - - c1 = next(colorcycle) - c2 = next(colorcycleal) - trace.append(go.Scatter(x=time, y=east, mode='lines', line=dict(color=c1), - name=f"{site_}-E", )) - if "unc" in opt: - trace.append( - go.Scatter( - x=np.concatenate([time, time[::-1]], axis=None), - y=np.concatenate([east + delta_east, east[::-1] - delta_east[::-1]], axis=None), - fill='toself', - fillcolor=c2, - line=dict(color=c2), - hoverinfo="skip", - showlegend=True - ) - ) - - c1 = next(colorcycle) - c2 = next(colorcycleal) - trace.append(go.Scatter(x=time, y=up, mode='lines', line=dict(color=c1), - name=f"{site_}-U", )) - if "unc" in opt: - trace.append( - go.Scatter( - x=np.concatenate([time, time[::-1]], axis=None), - y=np.concatenate([up + delta_up, up[::-1] - delta_up[::-1]], axis=None), - fill='toself', - fillcolor=c2, - line=dict(color=c2), - hoverinfo="skip", - showlegend=True - ) - ) - logger.info("PLOT done") - fig = go.Figure(data=trace) - fig.update_layout( - xaxis=dict(rangeslider=dict(visible=True)), - yaxis=dict(fixedrange=False, tickformat=".3f"), - height=800, - ) - fig.layout.autosize = True - return fig - - -def layout(data_dict): - if data_dict is None: - return html.Div( - [html.P("First you will need to select a DB in the Db Info menu")] - ) - else: - for st in data_dict['DB_STATE_DIC']: - if st["_id"] == "REC_POS": - break - l_site = [i for i in st["Site"] if i[-2:] != "_0"] - return html.Div( - [ - dropdown_type, - dropdown_site(l_site), - dcc.Checklist(id="checklist", - options=[ - {'label': "unc", "value": "unc"}, - {'label': "plan view", "value": "plan"}], - value=[''] - - ), - exclude_start(), - update_button, - dcc.Graph( - id="plot3", figure=get_empty_graph("select information first") - ), - ] - ) diff --git a/scripts/GinanEDA/GinanEDA/apps/utilities.py b/scripts/GinanEDA/GinanEDA/apps/utilities.py deleted file mode 100644 index 2529e6d19..000000000 --- a/scripts/GinanEDA/GinanEDA/apps/utilities.py +++ /dev/null @@ -1,30 +0,0 @@ -from dash import dcc -from dash import html - - -# Display utility functions -def _merge(a, b): - return dict(a, **b) - - -def _omit(omitted_keys, d): - return {k: v for k, v in d.items() if k not in omitted_keys} - - -def namedSlider(name, **kwargs): - return html.Div( - # style={'padding': '10px 10px 15px 4px'}, - children=[ - html.P(f"{name}:"), - html.Div(dcc.Slider(**kwargs), style={"margin-left": "3px"}), - ] - ) - - -def namedDropdown(name, **kwargs): - p = [] - if name is not None: - p.append(html.P(f"{name}:", style={"margin-left": "3px"})) - p.append(dcc.Dropdown(**kwargs)) - return html.Div(p) - diff --git a/scripts/GinanEDA/GinanEDA/datasets/__init__.py b/scripts/GinanEDA/GinanEDA/datasets/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/scripts/GinanEDA/GinanEDA/datasets/db.py b/scripts/GinanEDA/GinanEDA/datasets/db.py deleted file mode 100644 index ef87de7a3..000000000 --- a/scripts/GinanEDA/GinanEDA/datasets/db.py +++ /dev/null @@ -1,254 +0,0 @@ -import logging - -import numpy as np -import pymongo -from dash import html -from pymongo import MongoClient - -logger = logging.getLogger(__name__) -#MONGO_DB = None -#MONGO_CL = None -DB_SITE = None -DB_SAT = None -DB_STATES = None -DB_STATE_DIC = None -DB_MEAS_KEY = None -DB_STATE_KEY = None - - -# exclusion list for dropdown x and y -exclude_measurements = [ - "_id", - "REF0-Prefit", - "REF1-Prefit", - "REF0-Postfit", - "REF1-Postfit", - "REF1-Prefit", - "REF0-Variance", - "REF1-Variance", - "0-Prefit", - "0-Postfit", - "0-Variance", - "1-Variance", - "1-Prefit", - "0-Prefit", -] - -exclude_state = ["_id"] - - -def check_db(url=None, db=None): - if url is None: - return html.P(f"Not connected") - else: - return html.P(f"Connected to dataserver {url}, dataset {db}") - - -def connect_client(url): - logger.debug(f"CONNECING TO {url}") - return MongoClient(host=url) - - -pipeline_state = [ - { - "$group": { - "_id": "$State", - "Site": {"$addToSet": "$Site"}, - "Sat": {"$addToSet": "$Sat"}, - } - } -] - - -def connect_db(data_dict): - print(f" **** {data_dict}") - if data_dict['MONGO_URL'] is None or data_dict['MONGO_DB'] is None: - return - logger.info(f"Connecting to DB {data_dict['MONGO_URL']} / {data_dict['MONGO_DB']}") - MONGO_CL = connect_client(data_dict['MONGO_URL'])[data_dict['MONGO_DB']] - list_cl = list(MONGO_CL.list_collection_names()) - if "Measurements" in list_cl: - data_dict['DB_SITE'] = get_stations_list(MONGO_CL, "Measurements") - data_dict['DB_SAT'] = get_sats_list(MONGO_CL, "Measurements") - data_dict['DB_MEAS_KEY'] = get_keys(MONGO_CL, "Measurements") - logger.info( - f" => Measurements contains {len(data_dict['DB_SITE'])} sites and {len(data_dict['DB_SAT'])} satellites" - ) - logger.info(f" List of Keys : {', '.join( data_dict['DB_MEAS_KEY'])}") - else: - logger.warning(f" => Measurements collection not present") - # to do if states exist - if "States" in list_cl : #temporary locked - data_dict['DB_STATES'] = get_states_list(MONGO_CL, "States") - data_dict['DB_STATE_DIC'] = list(MONGO_CL["States"].aggregate(pipeline_state)) - req = {} - for l in data_dict['DB_STATE_DIC']: - pipeline = [ - {"$match": {"State": l["_id"]}}, - {"$project": {"keyvalue": {"$objectToArray": "$$ROOT"}}}, - {"$unwind": {"path": "$keyvalue"}}, - {"$group": {"_id": None, "allkeys": {"$addToSet": "$keyvalue.k"}}}, - ] - req[l["_id"]] = pipeline - answer = list(MONGO_CL["States"].aggregate([{"$facet": req}]))[0] - for l in data_dict['DB_STATE_DIC']: - l["Site"].sort() - l["Sat"].sort() - l["keys"] = sorted(answer[l["_id"]][0]["allkeys"]) - - else: - logger.warning(f" => States collection not present") - - -def get_keys(MONGO_CL, collection): - pipeline = [ - {"$project": {"keyvalue": {"$objectToArray": "$$ROOT"}}}, - {"$unwind": {"path": "$keyvalue"}}, - {"$group": {"_id": None, "allkeys": {"$addToSet": "$keyvalue.k"}}}, - ] - if MONGO_CL is not None:# and MONGO_DB is not None: - l = list(MONGO_CL[collection].aggregate(pipeline)) - else: - return list([None]) - return sorted(l[0]["allkeys"]) - - -def get_stations_list(MONGO_CL, collection): - pipeline = [{"$group": {"_id": None, "sites": {"$addToSet": "$Site"}}}] - if MONGO_CL is not None :#and MONGO_DB is not None: - l = list(MONGO_CL[collection].aggregate(pipeline)) - else: - return list([None]) - return sorted(l[0]["sites"]) - - -def get_sats_list(MONGO_CL, collection): - pipeline = [{"$group": {"_id": None, "sats": {"$addToSet": "$Sat"}}}] - if MONGO_CL is not None:# and MONGO_DB is not None: - l = list(MONGO_CL[collection].aggregate(pipeline)) - else: - l = list([None]) - return sorted(l[0]["sats"]) - - -def get_states_list(MONGO_CL, collection): - pipeline = [{"$group": {"_id": None, "State": {"$addToSet": "$State"}}}] - if MONGO_CL is not None:# and MONGO_DB is not None: - l = list(MONGO_CL[collection].aggregate(pipeline)) - else: - l = list([None]) - return sorted(l[0]["State"]) - - -def get_series(data, collection, state, site, sat, x1, x2): - req_match_1 = {"$match": {"Sat": {"$in": sat}, "Site": {"$in": site}}} - req_match_2 = {"$match": {x1: {"$ne": None}, x2: {"$ne": None}}} - - req_match_state1 = { - "$match": { - "Sat": {"$in": sat}, - "Site": {"$in": site}, - "State": state, - } - } - req_match_state2 = {"$match": {x1: {"$ne": None}, x2: {"$ne": None}}} - req_sort = {"$sort": {"Epoch": 1}} - req_group = { - "$group": { - "_id": {"site": "$Site", "sat": "$Sat"}, - "x": {"$push": "$" + x1}, - "y": {"$push": "$" + x2}, - } - } - req_sort2 = {"$sort": {"_id.site": 1, "_id.sat": 1}} - pipeline = [] - if state is not None: - pipeline.append(req_match_state1) - pipeline.append(req_match_state2) - else: - pipeline.append(req_match_1) - pipeline.append(req_match_2) - - pipeline.append(req_sort) - if x1 == "Epoch": - pipeline.append({"$project": {x1: 1, x2: 1, "Sat": 1, "Site": 1}}) - pipeline.append(req_group) - pipeline.append(req_sort2) - MONGO_CL = connect_client(data["MONGO_URL"])[data["MONGO_DB"]] - req = MONGO_CL[collection].aggregate(pipeline) - x_ = [] - y_ = [] - sat_ = [] - site_ = [] - for i in req: - x1_ = np.array(i["x"]) - x2_ = np.array(i["y"]) - if x1 == "Epoch": - x_.append(x1_.astype("datetime64[s]")) - else: - x_.append(x1_) - y_.append(x2_) - sat_.append(i["_id"]["sat"]) - site_.append(i["_id"]["site"]) - return site_, sat_, x_, y_ - - -def get_series_xyz(data, collection, state, site, sat, x1, x2, x3): - req_match = { - "$match": { - "Sat": {"$in": sat}, - "Site": {"$in": site}, - x1: {"$ne": None}, - x2: {"$ne": None}, - x3: {"$ne": None}, - } - } - req_match_state = { - "$match": { - "Sat": {"$in": sat}, - "Site": {"$in": site}, - "State": state, - x1: {"$ne": None}, - x2: {"$ne": None}, - x3: {"$ne": None}, - } - } - req_sort = {"$sort": {"Epoch": 1}} - req_group = { - "$group": { - "_id": {"site": "$Site", "sat": "$Sat"}, - "x": {"$push": "$" + x1}, - "y": {"$push": "$" + x2}, - "z": {"$push": "$" + x3}, - } - } - req_sort2 = {"$sort": {"_id.site": 1, "_id.sat": 1}} - pipeline = [] - if state is not None: - pipeline.append(req_match_state) - else: - pipeline.append(req_match) - - pipeline.append(req_sort) - if x1 == "Epoch": - pipeline.append({"$project": {x1: 1, x2: 1, x3: 1, "Sat": 1, "Site": 1}}) - pipeline.append(req_sort) - pipeline.append(req_group) - pipeline.append(req_sort2) - MONGO_CL = connect_client(data["MONGO_URL"])[data["MONGO_DB"]] - req = MONGO_CL[collection].aggregate(pipeline) - x_ = [] - y_ = [] - z_ = [] - sat_ = [] - site_ = [] - for i in req: - x1 = np.array(i["x"]) - x2 = np.array(i["y"]) - x3 = np.array(i["z"]) - x_.append(x1) - y_.append(x2) - z_.append(x3) - sat_.append(i["_id"]["sat"]) - site_.append(i["_id"]["site"]) - return site_, sat_, x_, y_, z_ diff --git a/scripts/GinanEDA/app.py b/scripts/GinanEDA/app.py index 939d901ff..58fb90c33 100644 --- a/scripts/GinanEDA/app.py +++ b/scripts/GinanEDA/app.py @@ -1,3 +1,5 @@ +"""_summary_ +""" import dash @@ -9,5 +11,5 @@ {"name": "viewport", "content": "width=device-width, initial-scale=1.0"} ], ) -app.title = "GinanEDA" +app.title = "Ginan EDA" server = app.server diff --git a/scripts/GinanEDA/GinanEDA/__init__.py b/scripts/GinanEDA/ginaneda/__init__.py similarity index 97% rename from scripts/GinanEDA/GinanEDA/__init__.py rename to scripts/GinanEDA/ginaneda/__init__.py index f22c1ae1e..3336b0ae8 100644 --- a/scripts/GinanEDA/GinanEDA/__init__.py +++ b/scripts/GinanEDA/ginaneda/__init__.py @@ -1,3 +1,5 @@ +"""_summary_ +""" import logging import os import sys diff --git a/scripts/GinanEDA/ginaneda/apps/__init__.py b/scripts/GinanEDA/ginaneda/apps/__init__.py new file mode 100644 index 000000000..d8fadb364 --- /dev/null +++ b/scripts/GinanEDA/ginaneda/apps/__init__.py @@ -0,0 +1,2 @@ +"""_summary_ +""" diff --git a/scripts/GinanEDA/ginaneda/apps/clock.py b/scripts/GinanEDA/ginaneda/apps/clock.py new file mode 100644 index 000000000..6109c82f1 --- /dev/null +++ b/scripts/GinanEDA/ginaneda/apps/clock.py @@ -0,0 +1,199 @@ +"""_summary_ +""" + +import logging +from itertools import cycle +import itertools + +import numpy as np +import plotly.graph_objs as go +from dash import dcc, html +from dash.dependencies import Input, Output, State + +from app import app +from ginaneda.datasets import db +import ginaneda.apps.utilities as util + +logger = logging.getLogger(__name__) + +colorcycle = cycle([ + "rgba( 99, 110, 250, 0.8)", + "rgba(171, 99, 250, 0.8)", + "rgba(239, 85, 59, 0.8)", + "rgba(255, 161, 90, 0.8)", + "rgba( 25, 211, 243, 0.8)", + "rgba(255, 102, 146, 0.8)", + "rgba(182, 232, 128, 0.8)", + "rgba(255, 151, 255, 0.8)", + "rgba(254, 203, 82, 0.8)"]) +colorcycleal = cycle([ + "rgba( 99, 110, 250, 0.1)", + "rgba(171, 99, 250, 0.1)", + "rgba(239, 85, 59, 0.1)", + "rgba(255, 161, 90, 0.1)", + "rgba( 25, 211, 243, 0.1)", + "rgba(255, 102, 146, 0.1)", + "rgba(182, 232, 128, 0.1)", + "rgba(255, 151, 255, 0.1)", + "rgba(254, 203, 82, 0.1)"]) + +possible_plot = ["SITE", "SAT"] +dropdown_type = html.Div( + [ + dcc.Dropdown( + id="cl_dropdown_type", + options=[{"label": i, "value": i} for i in possible_plot], + placeholder="Graph Type", + value=None, + ) + ], + style={"width": "10%", "display": "inline-block"}, +) + + + +def dropdown_serie1(sim_list): + """_summary_ + """ + simList = list(["ALL"]) + simList.extend(sim_list) + p = util.named_dropdown( + None, + id="cl_dropdown_serie1", + options=[{"label": i, "value": i} for i in simList], + placeholder="Series", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +def dropdown_serie(sim_list): + """_summary_ + """ + simList = list(["ALL"]) + simList.extend(sim_list) + p = util.named_dropdown( + None, + id="cl_dropdown_serie", + options=[{"label": i, "value": i} for i in simList], + placeholder="Series", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +update_button = html.Div( + [html.Button("update graph", id="update_graph", n_clicks=0)], + style={"width": "5%", "display": "inline-block"}, +) + + +@app.callback( + Output("plot4", "figure"), + Input("update_graph", "n_clicks"), + State("session-store", "data"), + State("cl_dropdown_type", "value"), + State("cl_dropdown_serie1", "value"), + State("cl_dropdown_serie", "value"), + # State("checklist", "value"), + # State("exclude_npt", "value") +) +def update_graph_pos(click, data_dict, graph_type, serie, serie1): + """Update the new graph + """ + if graph_type is None: + return util.get_empty_graph( + "Make sure a value for all the Dropdown Menu is selected") + else: + fig = go.Figure() + trace = [] + logger.info("Request done") + if graph_type == "SAT": + list_serie = data_dict['DB_SAT']#[1:] + dd = db.get_series2(data_dict, "States", "SAT_CLOCK", [""], list_serie, serie, "Epoch", "x", x3=None) + dd1 = db.get_series2(data_dict, "States", "SAT_CLOCK", [""], list_serie, serie1, "Epoch", "x", x3=None) + key = "sat" + elif graph_type == "SITE": + list_serie = data_dict['DB_SITE']#[1:] + dd = db.get_series2(data_dict, "States", "REC_CLOCK", list_serie, [""], serie, "Epoch", "x", x3=None) + dd1 = db.get_series2(data_dict, "States", "REC_CLOCK", list_serie, ["G00"], serie1, "Epoch", "x", x3=None) + key = "site" + + data_ =[] + data_single = [] + label = [] + for i in list_serie[1:]: + dev = None + ref = None + for s in dd: + if dd[s]['_id'][key] == i: + dev = dd[s] + for s2 in dd1: + if dd1[s2]['_id'][key] == i : + ref = dd1[s2] + if dev and ref: + if ref['_id'][key] == dev['_id'][key]: + dev2 = np.asarray(dev['y']).flatten()#[:-1501] + ref2 = np.asarray(ref['y']).flatten()#[:-1500] + if len(dev2) != len(ref2): + time1 = np.asarray(dev['x']).flatten() + time2 = np.asarray(ref['x']).flatten() + intersect, c1, c2 = np.intersect1d(time1, time2, return_indices = True) + dev2 = dev2[c1] + ref2 = ref2[c2] + + data_single.append(dev2 - ref2) + data_.append( dev2 - np.mean(dev2) - (ref2 - np.mean(ref2))) + label.append(dev['_id'][key]) + + data_ = np.asarray(data_) + data_single = np.asarray(data_single) + data2 = data_ - data_.mean(axis=0) + trace =[] + for i in range(data2.shape[0]): + trace.append( + go.Scatter( + # x=time, + y=data2[i,:], + mode='lines', + name=label[i], + )) + + fig = go.Figure(data=trace) + fig.update_layout( + xaxis=dict(rangeslider=dict(visible=True)), + yaxis=dict(fixedrange=False, tickformat=".3f"), + height=800, + ) + fig.layout.autosize = True + return fig + + +def layout(data_dict): + """_summary_ + """ + if data_dict is None: + return html.Div( + [html.P("First you will need to select a DB in the Db Info menu")] + ) + elif data_dict['STATE_DB']: + return html.Div( + [ + dropdown_type, + dropdown_serie(data_dict['Series']), + dropdown_serie1(data_dict['Series']), + # exclude_start(), + update_button, + dcc.Graph( + id="plot4", figure=util.get_empty_graph("select information first") + ), + ] + ) + else: + return html.Div( + [html.P("No KF State in the DB, can't do anything on this page")] + ) diff --git a/scripts/GinanEDA/GinanEDA/apps/dbinfo.py b/scripts/GinanEDA/ginaneda/apps/dbinfo.py similarity index 62% rename from scripts/GinanEDA/GinanEDA/apps/dbinfo.py rename to scripts/GinanEDA/ginaneda/apps/dbinfo.py index 164a0e39f..6f795783b 100644 --- a/scripts/GinanEDA/GinanEDA/apps/dbinfo.py +++ b/scripts/GinanEDA/ginaneda/apps/dbinfo.py @@ -1,11 +1,13 @@ -import plotly.express as px -from app import app +""" +Page for the information on the DB +""" +import logging + from dash import dcc, html from dash.dependencies import Input, Output, State -from GinanEDA.apps import meas -from GinanEDA.datasets import db -import logging +from app import app +from ginaneda.datasets import db logger = logging.getLogger(__name__) @@ -22,7 +24,7 @@ html.Div( [ html.P("Database to connect to:"), - dcc.Input(id="databaseName", value="127.0.0.1", type="text"), + dcc.Input(id="databaseName", value="127.0.0.1", type="text"), html.Button( id="connect-to-mongo", type="Connect", children="Connect to mongo" ), @@ -38,8 +40,12 @@ # optionss=[], placeholder="Databases", value=None, + multi=True ), - html.Button(id="connect-to-db", type="Connect", children="Load DB"), + html.Button( + id="connect-to-db", + type="Connect", + children="Load DB"), ], className="row", ), @@ -54,8 +60,10 @@ Input("connect-to-mongo", "n_clicks"), State("databaseName", "value"), ) -def update_connection( n, databaseName): - client = db.connect_client(databaseName) +def update_connection_list(_n, database_name): + """Update the connection list of the database + """ + client = db.connect_client(database_name) if client is not None: dropdowns = [ {"label": i["name"], "value": i["name"]} @@ -66,7 +74,6 @@ def update_connection( n, databaseName): return dropdowns - @app.callback( Output("db-info", "children"), Output("db-info-side", "children"), @@ -77,31 +84,35 @@ def update_connection( n, databaseName): State("dropdown-db", "value"), State("databaseName", "value"), ) -def update_connection_db( n, v, database_name): - data_dict={} - data_dict['MONGO_URL'] = database_name +def update_connection(_n, database_name, database_url): + """Update the connection + """ + data_dict = {} + data_dict['MONGO_URL'] = database_url client = db.connect_client(data_dict['MONGO_URL']) - data_dict['MONGO_DB'] = v + data_dict['MONGO_DB'] = database_name db.connect_db(data_dict) - sidebar_log = html.P(f"{data_dict['MONGO_URL']} / ({data_dict['MONGO_DB']})") + sidebar_log = html.P( + f"{data_dict['MONGO_URL']} / ({data_dict['MONGO_DB']})") infobox = [] if client is not None and data_dict['MONGO_DB'] is not None: infobox.append(html.H2("Connection successful")) - client = db.connect_client(data_dict['MONGO_URL'])[data_dict['MONGO_DB']] + client = db.connect_client(data_dict['MONGO_URL'])[ + data_dict['MONGO_DB'][0]] list_cl = list(client.list_collection_names()) if "Measurements" in list_cl: - infobox.append(html.P(f"Measurements present")) + infobox.append(html.P("Measurements present")) if data_dict['DB_SAT']: - infobox.append(html.P(f"Num satelites {len(data_dict['DB_SAT'])}")) - infobox.append(html.P(f"Num sites {len(data_dict['DB_SITE'])}")) + infobox.append( + html.P(f"Num satelites {len(data_dict['DB_SAT'])}")) + infobox.append( + html.P(f"Num sites {len(data_dict['DB_SITE'])}")) else: - infobox.append(html.P(f"Measurements NOT present")) - infobox.append(html.P(f"Num satelites N/A")) - infobox.append(html.P(f"Num sites N/A")) - + infobox.append(html.P("Measurements NOT present")) + infobox.append(html.P("Num satelites N/A")) + infobox.append(html.P("Num sites N/A")) if "States" in list_cl: - infobox.append(html.P(f"State present")) + infobox.append(html.P("State present")) else: - infobox.append(html.P(f"States NOT present")) - print(f"******\n{data_dict}") + infobox.append(html.P("States NOT present")) return db.check_db(), sidebar_log, infobox, data_dict diff --git a/scripts/GinanEDA/ginaneda/apps/meas.py b/scripts/GinanEDA/ginaneda/apps/meas.py new file mode 100644 index 000000000..ae74a7805 --- /dev/null +++ b/scripts/GinanEDA/ginaneda/apps/meas.py @@ -0,0 +1,410 @@ +"""_summary_ +""" +import logging + +import numpy as np +import plotly.graph_objs as go + +from dash import dash_table, dcc, html +from dash.dependencies import Input, Output, State + +from app import app +import ginaneda.apps.utilities as util +from ginaneda.datasets import db + +logger = logging.getLogger(__name__) + + +def qq_plot(data, sample_size): + """_summary_ + """ + d = (data - np.mean(data)) / np.std(data) + qq = np.ones([sample_size, 2]) + np.random.shuffle(d) + qq[:, 0] = np.sort(d[0:sample_size]) + qq[:, 1] = np.sort(np.random.normal(size=sample_size)) + return qq + + +possible_plot = ["Line", "Scatter", "Polar", "HistogramX", "HistogramY", "QQ"] +dropdown_type = html.Div( + [ + dcc.Dropdown( + id="mes_dropdown_type", + options=[{"label": i, "value": i} for i in possible_plot], + placeholder="Graph Type", + value=None, + ) + ], + style={"width": "10%", "display": "inline-block"}, +) + + +def check_list(): + """_summary_ + """ + return dcc.Checklist( + id="aggregate", + options=[ + {"label": "Aggregate (hist/stats)", "value": "agg"}, + ], + value=[""], + ) + + +def exclude_start(): + """_summary_ + """ + return html.Div( + [ + html.P( + "Exclude the first points", + style={ + "display": "inline-block", + "margin-right": 5}, + ), + dcc.Input( + id="exclude_npt", + value="0", + type="text", + size="2"), + html.P( + " points", + style={ + "display": "inline-block", + "margin-right": 5}), + ]) + + +def dropdown_site(site_list): + """_summary_ + """ + site_list2 = ["ALL"] + site_list + p = util.named_dropdown( + None, + id="mes_dropdown_site", + options=[{"label": i, "value": i} for i in site_list2], + placeholder="Site", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +def dropdown_sat(sat_list): + """_summary_ + """ + sat_list2 = ["ALL"] + sat_list + p = util.named_dropdown( + None, + id="mes_dropdown_sat", + options=[{"label": i, "value": i} for i in sat_list2], + placeholder="Sat", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +def dropdown_serie(sim_list): + """_summary_ + """ + simList = ["ALL"] + sim_list + p = util.named_dropdown( + None, + id="mes_dropdown_serie", + options=[{"label": i, "value": i} for i in simList], + placeholder="Series", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +def keys(name): + """_summary_ + """ + return [{"label": i, "value": i} + for i in name if i not in db.exclude_measurements] + + +def dropdown_key_y(name): + """_summary_ + """ + p = util.named_dropdown( + None, + id="mes_dropdown_key_y", + options=[i for i in keys(name)], + placeholder="Y Axis", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +def dropdown_key_x(name): + """_summary_ + """ + p = util.named_dropdown( + None, + id="mes_dropdown_key_x", + options=[i for i in keys(name)], + placeholder="X Axis", + value=None, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + +def generates_statistics(label, time_serie): + """_summary_ + + Args: + label (_type_): _description_ + time_serie (_type_): _description_ + + Returns: + _type_: _description_ + """ + a = {} + a["ID"] = label + a["RMS"] = np.sqrt(np.mean(np.square(time_serie))) + a["Mean"] = np.mean(time_serie) + a["Std"] = np.std(time_serie) + return a + +update_button = html.Div( + [html.Button("update graph", id="update_graph", n_clicks=0)], + style={"width": "5%", "display": "inline-block"}, +) + + +@app.callback( + Output("plot1", "figure"), + Output("tableDiv1", "children"), + inputs=[Input("update_graph", "n_clicks")], + state=[ + State("session-store", "data"), + State("mes_dropdown_type", "value"), + State("mes_dropdown_site", "value"), + State("mes_dropdown_sat", "value"), + State("mes_dropdown_key_x", "value"), + State("mes_dropdown_key_y", "value"), + State("mes_dropdown_serie", "value"), + State("mes_dropdown_site", "options"), + State("mes_dropdown_sat", "options"), + State("mes_dropdown_serie", "options"), + State("exclude_npt", "value"), + State("aggregate", "value"), + ], +) +def update_meas_graph( + click, + data_dict, + graph_type, + site, + sat, + xaxis, + yaxis, + serie, + list_site, + list_sat, + list_series, + exclude, + aggr): + """_summary_ + """ + try: + exclude = int(exclude) + except BaseException: + exclude = 0 + table = [] + agg_y = [] + if exclude < 0: + exclude = 0 + if ( + graph_type is None + or site is None + or sat is None + or xaxis is None + or yaxis is None + ): + return (util.get_empty_graph( + "Make sure a value for all the Dropdown Menu is selected"), [], ) + else: + fig = go.Figure() + site = [i["value"] for i in list_site] if "ALL" in site else site + sat = [i["value"] for i in list_sat] if "ALL" in sat else sat + serie = [i["value"] for i in list_series] if "ALL" in serie else serie + if "ALL" in site: + site.remove("ALL") + if "ALL" in sat: + sat.remove("ALL") + if "ALL" in serie: + serie.remove("ALL") + logger.debug( + f"\n Plotting request type {graph_type} \n\t\t sat {' ,'.join(sat)} \n\t\t site {' ,'.join(site)} \n\t {xaxis} \n\t {' ,'.join(yaxis)}" + ) + trace = [] + tab = [] + for yaxis_ in yaxis: + logger.info("entering req") + queryResult = db.get_series2( + data_dict, + "Measurements", + None, + site, + sat, + serie, + xaxis, + yaxis_, + x3=None) + logger.info("exiting req") + if len(queryResult) == 0 : + return (util.get_empty_graph( + "Nothing to plot"), [], ) + x = [] + y = [] + label = [] + for query in sorted(queryResult): + data = queryResult[query] + try: + if len(np.array(data['y'])) != 0: + y.append(np.array(data['y'])) + x.append(np.array(data['x'])) + label.append(query) + except BaseException: + pass + if graph_type == "QQ": + if "agg" in aggr: + _y = [] + for x_, y_, label_ in zip(x, y, label): + _y.append(y_[exclude:]) # .ravel() + _y = np.concatenate(_y, axis=0) + qqplot_data = qq_plot(_y, len(_y)) + + trace.append( + util.generate_trace( + "Scatter", qqplot_data[:, 0], qqplot_data[:, 1], "Agg" + ) + ) + trace.append( + util.generate_trace( + "Line", + [qqplot_data[0, 0], qqplot_data[-1, 0]], + [qqplot_data[0, 0], qqplot_data[-1, 0]], + "Agg", + ) + ) + else: + for x_, y_, label_ in zip(x, y, label): + qqplot_data = qq_plot(y_[exclude:], len(y_[exclude:])) + trace.append( + util.generate_trace( + "Scatter", + qqplot_data[:, 0], + qqplot_data[:, 1], + f"{label_}", + ) + ) + elif "agg" in aggr and graph_type in ["HistogramX", "HistogramY"]: + _y = [] + for y_ in y: + _y.append(y_[exclude:]) # .ravel() + _y = np.concatenate(_y, axis=0) + trace.append( + util.generate_trace( + graph_type, x_[exclude:], _y, f"{yaxis_}")) + table.append(generates_statistics(yaxis_, _y)) + + else: + for x_, y_, label_ in zip(x, y, label): + _y = y_[exclude:] + _x = x_[exclude:] + if len(yaxis) != 1: + label.append(yaxis_) + logger.debug("Generating 1 trace") + trace.append( + util.generate_trace(graph_type, _x, _y, label_) + ) + logger.debug("Generating 1 trace done") + if "agg" not in aggr: + if np.issubdtype(_y.dtype, np.float_): + table.append(generates_statistics(label_, _y)) + else: + if np.issubdtype(_y.dtype, np.float_): + agg_y.append(_y) + if "agg" in aggr: + _y = np.concatenate(agg_y, axis=0) + table.append(generates_statistics(yaxis_, _y)) + + fig = go.Figure(data=trace) + fig.update_layout(showlegend=True) + if len(table) != 0: + tab = [ + dash_table.DataTable( + id="table", + columns=[{"name": i, "id": i} for i in [key for key in table[0].keys()]], + data=table, + ) + ] + else: + tab = [] + if graph_type == "QQ": + fig.update_layout( + xaxis=dict( + rangeslider=dict( + visible=True), + scaleanchor="y", + scaleratio=1), + yaxis=dict( + fixedrange=False, + tickformat=".3f"), + height=700, + width=700, + ) + else: + fig.update_layout( + xaxis=dict(rangeslider=dict(visible=True)), + yaxis=dict(fixedrange=False, tickformat=".3f"), + height=600, + ) + fig.layout.autosize = True + if graph_type == "Polar": + if yaxis == "Elevation": + fig.update_polars(radialaxis_range=[90, 0]) + if xaxis == "Azimuth": + fig.update_polars(angularaxis_direction="clockwise") + return fig, tab + + +def layout(data_dict): + """_summary_ + """ + if data_dict is None: + return html.Div( + [html.P("First you will need to select a DB in the Db Info menu")] + ) + elif data_dict["MEAS_DB"]: + dropd = sorted(data_dict['Geom'] + data_dict['DB_MEAS_KEY']) + return html.Div([dropdown_type, + dropdown_site(data_dict['DB_SITE']), + dropdown_sat(data_dict['DB_SAT']), + dropdown_serie(data_dict['Series']), + dropdown_key_x(dropd), + dropdown_key_y(dropd), + exclude_start(), + check_list(), + update_button, + dcc.Graph(id="plot1", + figure=util.get_empty_graph("select information first")), + html.Div(id="tableDiv1", + className="tableDiv"), + ]) + else: + return html.Div( + [html.P("No measurements collection in the DB can't do anything on this page")] + ) diff --git a/scripts/GinanEDA/GinanEDA/apps/meas_polar.py b/scripts/GinanEDA/ginaneda/apps/meas_polar.py similarity index 69% rename from scripts/GinanEDA/GinanEDA/apps/meas_polar.py rename to scripts/GinanEDA/ginaneda/apps/meas_polar.py index 9dddc3f73..185aefe2e 100644 --- a/scripts/GinanEDA/GinanEDA/apps/meas_polar.py +++ b/scripts/GinanEDA/ginaneda/apps/meas_polar.py @@ -1,11 +1,15 @@ -import GinanEDA.apps.utilities as util +"""_summary_ +""" import numpy as np import plotly.express as px import plotly.graph_objs as go -from app import app + from dash import dcc, html from dash.dependencies import Input, Output, State -from GinanEDA.datasets import db + +from app import app +from ginaneda.datasets import db +import ginaneda.apps.utilities as util possible_plot = ["Line", "Scatter"] dropdown_type = html.Div( @@ -20,24 +24,12 @@ style={"width": "10%", "display": "inline-block"}, ) - -import plotly.express as px - colorscales = px.colors.named_colorscales() -def exclude_start(): - return html.Div( - [ - html.P("Exclude the first points", style={"margin-left": "3px"}), - dcc.Input(id="exclude_npt", value="0", type="text", size="2") - # html.P(' points',style={'display':'inline-block','margin-right':5}), - ], - style={"width": "15%", "display": "inline-block"}, - ) - - def dropdown_site(site_list): + """_summary_ + """ site_list2 = list(["ALL"]) site_list2.extend(site_list) return html.Div( @@ -54,6 +46,8 @@ def dropdown_site(site_list): def dropdown_sat(sat_list): + """_summary_ + """ sat_list2 = list(["ALL"]) sat_list2.extend(sat_list) return html.Div( @@ -70,17 +64,39 @@ def dropdown_sat(sat_list): ) +def dropdown_serie(sim_list): + """_summary_ + """ + simList = list(["ALL"]) + simList.extend(sim_list) + p = util.named_dropdown( + None, + id="mes_dropdown_serie", + options=[{"label": i, "value": i} for i in simList], + placeholder="Series", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + def keys(data): - # a = db.MONGO_CL["Measurements"].find_one() - return [{"label": i, "value": i} for i in data if i not in db.exclude_measurements] + """_summary_ + """ + # a = db.mongo_cl["Measurements"].find_one() + return [{"label": i, "value": i} + for i in data if i not in db.exclude_measurements] -def dropdown_key_y(): +def dropdown_key_y(data): + """_summary_ + """ return html.Div( [ dcc.Dropdown( id="mespolar_dropdown_key_y", - options=[i for i in keys()], + options=[i for i in keys(data)], placeholder="Y axis", value=None, ) @@ -90,6 +106,8 @@ def dropdown_key_y(): def dropdown_key_x(data): + """_summary_ + """ return html.Div( [ dcc.Dropdown( @@ -109,37 +127,6 @@ def dropdown_key_x(data): ) -def get_empty_graph(message): - emptiness = { - "layout": { - "xaxis": {"visible": False}, - "yaxis": {"visible": False}, - "annotations": [ - { - "text": message, - "xref": "paper", - "yref": "paper", - "showarrow": False, - "font": {"size": 28}, - } - ], - } - } - return emptiness - - -def generate_trace(graph_type, x, y, label): - if graph_type == "Line" or graph_type == "Scatter": - if graph_type == "Line": - mode = "lines" - else: - mode = "markers" - trace = go.Scatter(x=x, y=y, mode=mode, name=label) - elif graph_type == "POLAR": - trace = go.Scatterpolar(r=y, theta=x, mode="markers") # , name=label) - return trace - - @app.callback( Output("plot_polar", "figure"), inputs=[Input("update_graph_measP", "n_clicks")], @@ -147,6 +134,7 @@ def generate_trace(graph_type, x, y, label): State("session-store", "data"), State("mespolar_dropdown_site", "value"), State("mespolar_dropdown_sat", "value"), + State("mes_dropdown_serie", "value"), State("mespolar_dropdown_key_C", "value"), State("mespolar_dropdown_site", "options"), State("mespolar_dropdown_sat", "options"), @@ -158,10 +146,11 @@ def generate_trace(graph_type, x, y, label): ], ) def update_graph_measurements( - click, + _click, data_dict, site, sat, + serie, caxis, list_site, list_sat, @@ -171,40 +160,56 @@ def update_graph_measurements( exclude, cmap, ): + """_summary_ + """ try: exclude = int(exclude) - except: + except BaseException: exclude = 0 if exclude < 0: exclude = 0 fig = go.Figure() if site is None or sat is None or caxis is None: - return get_empty_graph( + return util.get_empty_graph( "Make sure a value for all the Dropdown Menu is selected" ) else: site = [i["value"] for i in list_site] if site == "ALL" else [site] sat = [i["value"] for i in list_sat] if "ALL" in sat else sat - site_, sat_, x_, y_, z_ = db.get_series_xyz(data_dict, - "Measurements", None, site, sat, "Azimuth", "Elevation", caxis - ) + queryResult = db.get_series2( + data_dict, + "Measurements", + None, + site, + sat, + serie, + "Azimuth", + "Elevation", + x3=caxis) trace = [] min_ = 0 max_ = 0 - for z in z_: - min_ = min(min_, z[exclude:].min()) - max_ = max(max_, z[exclude:].max()) + for lab in sorted(queryResult): + d = queryResult[lab] + z = np.asarray(d["z"]) + if len(z) > exclude: + min_ = min(min_, z[exclude:].min()) + max_ = max(max_, z[exclude:].max()) min_ = np.floor(min_) max_ = np.ceil(max_) if input_min is not None: min_ = input_min if input_max is not None: max_ = input_max - - for i in range(len(x_)): - _x, _y, _z = x_[i][exclude:], y_[i][exclude:], z_[i][exclude:] + for lab in sorted(queryResult): + d = queryResult[lab] + if len(np.asarray(d["x"])) == 0: + continue + _x = np.asarray(d["x"])[exclude:] + _y = np.asarray(d["y"])[exclude:] + _z = np.asarray(d["z"])[exclude:] trace.append( go.Scatterpolar( r=_y, @@ -218,42 +223,67 @@ def update_graph_measurements( cmin=min_, cmax=max_, ), - name=f"{site_[i]}-{sat_[i]}", + name='_'.join(map(str, d['_id'].values())), hovertemplate="r:%{r:.3f}
theta:%{theta:.3f}
c: %{marker.color:.3f} ", ) ) fig = go.Figure(data=trace) fig.update_layout( - xaxis=dict(rangeslider=dict(visible=True)), - yaxis=dict(fixedrange=False), + # xaxis={"rangeslider": {"visible": True}}, + # yaxis={"rangeslider": {"visible": False}}, height=600, coloraxis_colorbar_x=-1.0, polar=dict( radialaxis_tickfont_size=8, - angularaxis=dict(tickfont_size=8, rotation=90, direction="clockwise"), - radialaxis=dict(range=[90, 0]), + angularaxis=dict( + tickfont_size=8, + rotation=90, + direction="clockwise"), + radialaxis=dict( + range=[ + 90, + 0]), ), - legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.85), + legend=dict( + yanchor="top", + y=0.99, + xanchor="left", + x=0.85), ) fig.layout.autosize = True - return fig +def exclude_start(): + """Create a box to exclude the first n points + """ + return html.Div( + [ + html.P("Exclude the first points", style={"margin-left": "3px"}), + dcc.Input(id="exclude_npt", value="0", type="text", size="2") + # html.P(' points',style={'display':'inline-block','margin-right':5}), + ], + style={"width": "15%", "display": "inline-block"}, + ) + + def layout(data_dict): - if data_dict== None: + """_summary_ + """ + if data_dict is None: return html.Div( [html.P("First you will need to select a DB in the Db Info menu")] ) - else: + elif data_dict["MEAS_DB"]: return html.Div( [ dropdown_site(data_dict['DB_SITE']), dropdown_sat(data_dict['DB_SAT']), + dropdown_serie(data_dict['Series']), dropdown_key_x(data_dict['DB_MEAS_KEY']), html.Div( children=[ - util.namedSlider( + util.named_slider( name="Symbol size", id="symbol_size", min=1, @@ -285,7 +315,11 @@ def layout(data_dict): ), update_button, dcc.Graph( - id="plot_polar", figure=get_empty_graph("select information first") + id="plot_polar", figure=util.get_empty_graph("select information first") ), ] ) + else: + return html.Div( + [html.P("No measurements collection in the DB can't do anything on this page")] + ) diff --git a/scripts/GinanEDA/ginaneda/apps/pos.py b/scripts/GinanEDA/ginaneda/apps/pos.py new file mode 100644 index 000000000..da9bf6f9f --- /dev/null +++ b/scripts/GinanEDA/ginaneda/apps/pos.py @@ -0,0 +1,566 @@ +"""_summary_ +""" + +import logging +from itertools import cycle +import itertools + +import numpy as np +import plotly.graph_objs as go +from dash import dcc, html +from dash.dependencies import Input, Output, State + +from app import app +from ginaneda.datasets import db +import ginaneda.apps.utilities as util + +logger = logging.getLogger(__name__) + +colorcycle = cycle([ + "rgba( 99, 110, 250, 0.8)", + "rgba(171, 99, 250, 0.8)", + "rgba(239, 85, 59, 0.8)", + "rgba(255, 161, 90, 0.8)", + "rgba( 25, 211, 243, 0.8)", + "rgba(255, 102, 146, 0.8)", + "rgba(182, 232, 128, 0.8)", + "rgba(255, 151, 255, 0.8)", + "rgba(254, 203, 82, 0.8)"]) +colorcycleal = cycle([ + "rgba( 99, 110, 250, 0.1)", + "rgba(171, 99, 250, 0.1)", + "rgba(239, 85, 59, 0.1)", + "rgba(255, 161, 90, 0.1)", + "rgba( 25, 211, 243, 0.1)", + "rgba(255, 102, 146, 0.1)", + "rgba(182, 232, 128, 0.1)", + "rgba(255, 151, 255, 0.1)", + "rgba(254, 203, 82, 0.1)"]) + +possible_plot = ["XYZ", "NEU"] +dropdown_type = html.Div( + [ + dcc.Dropdown( + id="mes_dropdown_type", + options=[{"label": i, "value": i} for i in possible_plot], + placeholder="Graph Type", + value=None, + ) + ], + style={"width": "10%", "display": "inline-block"}, +) + + +def xyz2blh(x, y, z): + """_summary_ + """ + A = 6378137.0 + B = 6356752.314245 + e = np.sqrt(1 - (B ** 2) / (A ** 2)) + # calculate longitude, in radians + longitude = np.arctan2(y, x) + # calculate latitude, in radians + xy_hypot = np.hypot(x, y) + lat0 = 0 + latitude = np.arctan(z / xy_hypot) + while abs(latitude - lat0) > 1e-9: + lat0 = latitude + N = A / np.sqrt(1 - e ** 2 * np.sin(lat0) ** 2) + latitude = np.arctan((z + e ** 2 * N * np.sin(lat0)) / xy_hypot) + # calculate height, in meters + N = A / np.sqrt(1 - e ** 2 * np.sin(latitude) ** 2) + if abs(latitude) < np.pi / 4: + R, phi = np.hypot(xy_hypot, z), np.arctan(z / xy_hypot) + height = R * np.cos(phi) / np.cos(latitude) - N + else: + height = z / np.sin(latitude) - N * (1 - e ** 2) + # convert angle unit to degrees + longitude = np.degrees(longitude) + latitude = np.degrees(latitude) + + return latitude, longitude, height + + +def xyz2neu(x0, y0, z0, x, y, z): + """_summary_ + """ + lat, lon, _ = xyz2blh(x0, y0, z0) + lat, lon = np.radians(lat), np.radians(lon) + north = ( + -np.sin(lat) * np.cos(lon) * (x - x0) + - np.sin(lat) * np.sin(lon) * (y - y0) + + np.cos(lat) * (z - z0) + ) + east = -np.sin(lon) * (x - x0) + np.cos(lon) * (y - y0) + up = ( + np.cos(lat) * np.cos(lon) * (x - x0) + + np.cos(lat) * np.sin(lon) * (y - y0) + + np.sin(lat) * (z - z0) + ) + return north, east, up + + +def exclude_start(): + """_summary_ + """ + return html.Div( + [ + html.P( + "Exclude the first points", + style={ + "display": "inline-block", + "margin-right": 5}, + ), + dcc.Input( + id="exclude_npt", + value="0", + type="text", + size="2"), + html.P( + " points", + style={ + "display": "inline-block", + "margin-right": 5}), + ]) + + +def dropdown_site(site_list): + """_summary_ + """ + site_list2 = list(["ALL"]) + site_list2.extend(site_list) + p = util.named_dropdown( + None, + id="mes_dropdown_site", + options=[{"label": i, "value": i} for i in site_list2], + placeholder="Site", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +def dropdown_serie(sim_list): + """_summary_ + """ + simList = list(["ALL"]) + simList.extend(sim_list) + p = util.named_dropdown( + None, + id="pos_dropdown_serie", + options=[{"label": i, "value": i} for i in simList], + placeholder="Series", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + + +update_button = html.Div( + [html.Button("update graph", id="update_graph", n_clicks=0)], + style={"width": "5%", "display": "inline-block"}, +) + + +@app.callback( + Output("plot3", "figure"), + Input("update_graph", "n_clicks"), + State("session-store", "data"), + State("mes_dropdown_type", "value"), + State("mes_dropdown_site", "value"), + State("pos_dropdown_serie", "value"), + State("checklist", "value"), + State("exclude_npt", "value") +) +def update_graph_pos(click, data_dict, graph_type, site, serie, opt, exclude): + """Update the new graph + """ + try: + exclude = int(exclude) + except BaseException: + exclude = 0 + if exclude < 0: + exclude = 0 + if graph_type is None or site is None: + return util.get_empty_graph( + "Make sure a value for all the Dropdown Menu is selected") + else: + fig = go.Figure() + trace = [] + site = [i for i in data_dict["DB_SITE"]] if "ALL" in site else site + if "" in site: + site.remove("") + logger.info("Request done") + answer = {} + for site_, serie_ in itertools.product(site, serie): + req = {} + database , subseries = serie_.split("\\") + pipeline = [ + {"$match": {"State": "REC_POS", "Site": site_, "Series": subseries}}, + {"$sort": {"Epoch": 1}}, + { + "$group": { + "_id": "$Site", + "Epoch": {"$push": "$Epoch"}, + "x": {"$push": "$x"}, + } + } + ] + if "unc" in opt: + pipeline[2]["$group"]["P"] = {"$push": "$P"} + req[site_+'_'+serie_] = pipeline + # if graph_type == "NEU": + for site_ in site: + Serie_0 = subseries.split("_")[0]+"_apriori" + pipeline = [ + { + "$match": { + "State": "REC_POS", "Site": site_, "Series": Serie_0}}, { + "$sort": { + "Epoch": 1}}, { + "$group": { + "_id": "$Site", "Epoch": { + "$push": "$Epoch"}, "x": { + "$push": "$x"}, }}] + req[site_ + '_' + serie_ + "_apriori"] = pipeline + mongoClient = db.connect_client(data_dict['MONGO_URL'])[database] + for cursor in mongoClient["States"].aggregate([{"$facet": req}]): + answer.update(cursor) + + logger.info("Request done") + + for site_, serie_ in itertools.product(site, serie): + data = answer[site_ + '_' + serie_] + data_ap = answer [ site_ + '_' + serie_ + "_apriori"] + time = np.array(data[0]["Epoch"])[exclude:] + data2 = np.array(data[0]["x"]) + x = data2[exclude:, 0] + y = data2[exclude:, 1] + z = data2[exclude:, 2] + + data_ap_arr= np.array(data_ap[0]["x"]) + time_ap = np.array(data_ap[0]["Epoch"])[exclude:] + x_ap = data_ap_arr[exclude:, 0] + y_ap = data_ap_arr[exclude:, 1] + z_ap = data_ap_arr[exclude:, 2] + resize = False + if len(time_ap) != len(time): + common, idx1, idx2 = np.intersect1d(time, time_ap, return_indices=True) + time = time[idx1] + x = x[idx1] + y = y[idx1] + z = z[idx1] + time_ap = time_ap[idx2] + x_ap = x_ap[idx2] + y_ap = y_ap[idx2] + z_ap = z_ap[idx2] + resize = True + if "unc" in opt: + data2 = np.array(data[0]["P"]) + dx0 = data2[exclude:, 0] + dx1 = data2[exclude:, 1] + dx2 = data2[exclude:, 2] + print(len(dx0)) + if resize: + common, idx1, idx2 = np.intersect1d(time, time_ap, return_indices=True) + dx0 = dx0[idx1] + dx1 = dx1[idx1] + dx2 = dx2[idx1] + print(len(dx0)) + else: + dx0 = None + dx1 = None + dx2 = None + if (x[0]**2+y[0]**2+z[0]**2 > 6000000**2): + x = x - x_ap + y = y - y_ap + z = z - z_ap + if graph_type == "XYZ": + if "plan" in opt: + if "unc" in opt: + data = go.Scatter3d( + x=x, + y=y, + z=z, + marker=dict( + size=6, + color=np.sqrt(dx0 + dx1 + dx2), + colorscale=[(0,"green"), (0.03,"green"), (0.05,"purple"), (0.10,"orange"), (1,"red")], + showscale=True, + cmin=0, + cmax=1), + name=site_+serie_) + else: + data = go.Scatter3d(x=x, y=y, z=z, name=site_+serie_) + trace.append(data) + else: + c1 = next(colorcycle) + c2 = next(colorcycleal) + trace.append( + go.Scatter( + x=time, + y=x, + mode='lines', + line=dict( + color=c1), + name=f"{site_}-{serie_}-X", + )) + if "unc" in opt: + print(len(x), len(dx0)) + trace.append( + go.Scatter( + # x, then x reversed + x=np.concatenate( + [time, time[::-1]], axis=None), + y=np.concatenate( + [x + np.sqrt(dx0), x[::-1] - np.sqrt(dx0[::-1])], axis=None), + # upper, then lower reversed + fill='toself', + fillcolor=c2, + line=dict(color=c2), + hoverinfo="skip", + showlegend=True + ) + ) + + c1 = next(colorcycle) + c2 = next(colorcycleal) + trace.append( + go.Scatter( + x=time, + y=y, + mode='lines', + line=dict( + color=c1), + name=f"{site_}-{serie_}-Y", + )) + if "unc" in opt: + trace.append( + go.Scatter( + # x, then x reversed + x=np.concatenate( + [time, time[::-1]], axis=None), + y=np.concatenate( + [y + np.sqrt(dx1), y[::-1] - np.sqrt(dx1[::-1])], axis=None), + # upper, then lower reversed + fill='toself', + fillcolor=c2, + line=dict(color=c2), + hoverinfo="skip", + showlegend=True + ) + ) + + c1 = next(colorcycle) + c2 = next(colorcycleal) + trace.append( + go.Scatter( + x=time, + y=z, + mode='lines', + line=dict( + color=c1), + name=f"{site_}-{serie_}-Z", + )) + if "unc" in opt: + trace.append( + go.Scatter( + # x, then x reversed + x=np.concatenate( + [time, time[::-1]], axis=None), + y=np.concatenate( + [z + np.sqrt(dx2), z[::-1] - np.sqrt(dx2[::-1])], axis=None), + # upper, then lower reversed + fill='toself', + fillcolor=c2, + line=dict(color=c2), + hoverinfo="skip", + showlegend=True + ) + ) + else: + base = answer[f"{site_}_{serie_}_apriori"] + data2 = np.array(base[0]["x"]) + x0 = data2[0, 0] + y0 = data2[0, 1] + z0 = data2[0, 2] + lat, lon, _h = xyz2blh(x0, y0, z0) + # using formula from + # https://gssc.esa.int/navipedia/index.php/Positioning_Error + lat, lon = np.radians(lat), np.radians(lon) + rot = np.array([[-np.sin(lon), - np.cos(lon) * np.sin(lat), np.cos(lat) * np.cos(lon)], + [np.cos(lon), - np.sin(lat) * np.sin(lon), np.cos(lat) * np.sin(lon)], + [0, np.cos(lat), np.sin(lat)] + ]) + # north, east, up = xyz2neu(x0[0], y0[0], z0[0], x + x0[0], y + y0[0], z + z0[0]) + enu = [] + for x_, y_, z_ in zip(x,y,z): + if (x_**2+y_**2+z_**2 > 6000000**2): + x_ -= x0 + y_ -= y0 + z_ -= z0 + enu.append(rot.transpose().dot(np.array([x_ , y_ , z_ ]).transpose())) + enu = np.asarray(enu) + north = enu[:, 1] + east = enu[:, 0] + up = enu[:, 2] + if "unc" in opt: + denu = [] + for i in range(len(dx0)): + P = np.diag([dx0[i], dx1[i], dx2[i]]) + denu.append( + np.sqrt( + np.diag( + rot.transpose().dot(P).dot(rot)))) + + denu = np.asarray(denu) + delta_north = denu[:, 1] + delta_east = denu[:, 0] + delta_up = denu[:, 2] + else: + delta_north = None + delta_east = None + delta_up = None + if "plan" in opt: + trace.append( + go.Scatter( + x=east, + y=north, + mode='lines+markers', + name=f"{site_}_{serie_}-N", + )) + if "unc" in opt: + marker = dict( + size=6, + color=np.sqrt(dx0 ** 2 + dx1 ** 2 + dx2 ** 2), + colorscale=[(0,"green"), (0.03,"green"), (0.05,"purple"),(0.10, "orange"),(1,"red")], + showscale=True, + cmin=0, + cmax=1) + trace.append( + go.Scatter( + x=east, + y=north, + mode='lines+markers', + name=f"{site_}_{serie_}-N", + marker=marker)) + + else: + c1 = next(colorcycle) + c2 = next(colorcycleal) + trace.append( + go.Scatter( + x=time, + y=north, + mode='lines', + line=dict( + color=c1), + name=f"{site_}_{serie_}-N", + )) + if "unc" in opt: + trace.append( + go.Scatter( + # x, then x reversed + x=np.concatenate( + [time, time[::-1]], axis=None), + # upper, then lower reversed + y=np.concatenate( + [north + delta_north, north[::-1] - delta_north[::-1]], axis=None), + fill='toself', + fillcolor=c2, + line=dict(color=c2), + hoverinfo="skip", + showlegend=True + ) + ) + + c1 = next(colorcycle) + c2 = next(colorcycleal) + trace.append( + go.Scatter( + x=time, + y=east, + mode='lines', + line=dict( + color=c1), + name=f"{site_}_{serie_}-E", + )) + if "unc" in opt: + trace.append( + go.Scatter( + x=np.concatenate([time, time[::-1]], axis=None), + y=np.concatenate([east + delta_east, east[::-1] - delta_east[::-1]], axis=None), + fill='toself', + fillcolor=c2, + line=dict(color=c2), + hoverinfo="skip", + showlegend=True + ) + ) + + c1 = next(colorcycle) + c2 = next(colorcycleal) + trace.append( + go.Scatter( + x=time, + y=up, + mode='lines', + line=dict( + color=c1), + name=f"{site_}_{serie_}-U", + )) + if "unc" in opt: + trace.append( + go.Scatter( + x=np.concatenate([time, time[::-1]], axis=None), + y=np.concatenate([up + delta_up, up[::-1] - delta_up[::-1]], axis=None), + fill='toself', + fillcolor=c2, + line=dict(color=c2), + hoverinfo="skip", + showlegend=True + ) + ) + fig = go.Figure(data=trace) + fig.update_layout( + xaxis=dict(rangeslider=dict(visible=True)), + yaxis=dict(fixedrange=False, tickformat=".3f"), + height=800, + ) + fig.layout.autosize = True + return fig + + +def layout(data_dict): + """_summary_ + """ + if data_dict is None: + return html.Div( + [html.P("First you will need to select a DB in the Db Info menu")] + ) + elif data_dict['STATE_DB']: + return html.Div( + [ + dropdown_type, + dropdown_site(data_dict["DB_SITE"]), + dropdown_serie(data_dict['Series']), + dcc.Checklist(id="checklist", + options=[ + {'label': "unc", "value": "unc"}, + {'label': "plan view", "value": "plan"}], + value=[''] + + ), + exclude_start(), + update_button, + dcc.Graph( + id="plot3", figure=util.get_empty_graph("select information first") + ), + ] + ) + else: + return html.Div( + [html.P("No KF State in the DB, can't do anything on this page")] + ) diff --git a/scripts/GinanEDA/GinanEDA/apps/state.py b/scripts/GinanEDA/ginaneda/apps/state.py similarity index 54% rename from scripts/GinanEDA/GinanEDA/apps/state.py rename to scripts/GinanEDA/ginaneda/apps/state.py index 63ecb81d5..8cf6aff3c 100644 --- a/scripts/GinanEDA/GinanEDA/apps/state.py +++ b/scripts/GinanEDA/ginaneda/apps/state.py @@ -1,31 +1,44 @@ -import pathlib +"""_summary_ +""" -import GinanEDA.apps.utilities as util import numpy as np -import pandas as pd -import plotly.express as px -import plotly.graph_objs as go -from app import app -from dash import dash_table, dcc, html -from dash.dependencies import Input, Output, State -from GinanEDA.datasets import db from sklearn.linear_model import LinearRegression -from sklearn.metrics import mean_squared_error from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures +from dash import dash_table, dcc, html +from dash.dependencies import Input, Output, State +import plotly.graph_objs as go + +from app import app +from ginaneda.datasets import db +import ginaneda.apps.utilities as util def exclude_start(): + """_summary_ + """ return html.Div( [ html.P( "Exclude the first points", - style={"display": "inline-block", "margin-right": 20}, + style={ + "display": "inline-block", + "margin-right": 20}, ), - dcc.Input(id="exclude_npt", value="0", type="text", size="2"), - html.P(" points", style={"display": "inline-block", "margin-right": 5}), + dcc.Input( + id="exclude_npt", + value="0", + type="text", + size="2"), + html.P( + " points", + style={ + "display": "inline-block", + "margin-right": 5}), ], - style={"width": "10%", "display": "inline-block"}, + style={ + "width": "10%", + "display": "inline-block"}, ) @@ -33,9 +46,11 @@ def exclude_start(): def dropdown_type(): + """_summary_ + """ return html.Div( [ - util.namedDropdown( + util.named_dropdown( "Type", id="state_dropdown_type", options=[{"label": i, "value": i} for i in possible_plot], @@ -47,26 +62,33 @@ def dropdown_type(): ) -# dropdown_type = html.Div([ -# dcc.Dropdown( -# id='state_dropdown_type', -# options=[{'label': i, 'value': i} for i in possible_plot], -# placeholder="Graph Type", -# value=None -# ) -# ], -# style={'width': '10%', 'display': 'inline-block'} -# ) +def dropdown_serie(sim_list): + """_summary_ + """ + simList = list(["ALL"]) + simList.extend(sim_list) + p = util.named_dropdown( + "Series", + id="sate_dropdown_serie", + options=[{"label": i, "value": i} for i in simList], + placeholder="Series", + value=None, + multi=True, + ) + p.style = {"width": "20%", "display": "inline-block"} + return p + possible_trend = ["None", "Fit", "Detrend"] poly_dropdown = html.Div( [ - util.namedDropdown( + util.named_dropdown( "Trend correction", id="poly_dropdown", options=[{"label": i, "value": i} for i in possible_trend], placeholder="Fit Type", - value=None, + value="None", + multi=False ) ], style={"width": "10%", "display": "inline-block"}, @@ -84,20 +106,23 @@ def dropdown_type(): def check_list(): + """_summary_ + """ return dcc.Checklist( options=[ {"label": "Aggregate (hist/stats)", "value": "agg"}, ], - # value=['NYC', 'MTL'] ) def dropdown_site(site_list): + """_summary_ + """ site_list2 = list(["ALL"]) site_list2.extend(site_list) return html.Div( [ - util.namedDropdown( + util.named_dropdown( "Site", id="state_dropdown_site", options=[{"label": i, "value": i} for i in site_list2], @@ -123,15 +148,17 @@ def dropdown_site(site_list): def dropdown_sat(sat_list): + """_summary_ + """ sat_list2 = list(["ALL"]) sat_list2.extend(sat_list) return html.Div( [ - util.namedDropdown( + util.named_dropdown( "Sat", id="state_dropdown_sat", options=[{"label": i, "value": i} for i in sat_list2], - placeholder="Site", + placeholder="Sat", value=None, multi=True, ) @@ -141,9 +168,11 @@ def dropdown_sat(sat_list): def dropdown_state(state_list): + """_summary_ + """ return html.Div( [ - util.namedDropdown( + util.named_dropdown( "State", id="state_dropdown_state", options=[{"label": i, "value": i} for i in state_list], @@ -168,15 +197,18 @@ def dropdown_state(state_list): def keys(data): - # a = db.MONGO_CL["States"].find_one() - # temp = list(a.keys()) - return [{"label": i, "value": i} for i in data if i not in db.exclude_state] + """_summary_ + """ + return [{"label": i, "value": i} + for i in data if i not in db.exclude_state] def dropdown_key_y(data): + """_summary_ + """ return html.Div( [ - util.namedDropdown( + util.named_dropdown( "Y axis", id="state_dropdown_key_y", options=[i for i in keys(data)], @@ -201,9 +233,11 @@ def dropdown_key_y(data): def dropdown_key_x(data): + """_summary_ + """ return html.Div( [ - util.namedDropdown( + util.named_dropdown( "X axis", id="state_dropdown_key_x", options=[i for i in keys(data)], @@ -221,66 +255,30 @@ def dropdown_key_x(data): ) -def get_empty_graph(message): - emptiness = { - "layout": { - "xaxis": {"visible": False}, - "yaxis": {"visible": False}, - "annotations": [ - { - "text": message, - "xref": "paper", - "yref": "paper", - "showarrow": False, - "font": {"size": 28}, - } - ], - } - } - return emptiness - - -def generate_trace(graph_type, x, y, label): - if graph_type == "Line" or graph_type == "Scatter": - if graph_type == "Line": - mode = "lines" - else: - mode = "markers" - trace = go.Scatter(x=x, y=y, mode=mode, name=label) - elif graph_type == "POLAR": - trace = go.Scatterpolar(r=y, theta=x, mode="markers", name=label) - elif graph_type == "HistogramX": - trace = go.Histogram(x=y, name=label) - elif graph_type == "HistogramY": - trace = go.Histogram(y=y, name=label) - return trace - - -@app.callback( - - Output("state_dropdown_site", "options"), - Output("state_dropdown_sat", "options"), - Output("state_dropdown_key_x", "options"), - Output("state_dropdown_key_y", "options"), - Input("state_dropdown_state", "value"), - State("session-store", "data") -) -def update_dropdown(state, data_dict): - if not state: - return [], [], [], [] - else: - for st in data_dict['DB_STATE_DIC']: - if st["_id"] == state: - break - site_list = list(["ALL"]) - site_list.extend(st["Site"]) - sat_list = list(["ALL"]) - sat_list.extend(st["Sat"]) - keys = st["keys"] - keys_sat = [{"label": i, "value": i} for i in sat_list] - keys_site = [{"label": i, "value": i} for i in site_list] - keys_d = [{"label": i, "value": i} for i in keys if i[0] != "_"] - return keys_site, keys_sat, keys_d, keys_d +# @app.callback( +# Output("state_dropdown_site", "options"), +# Output("state_dropdown_sat", "options"), +# # Output("state_dropdown_key_x", "options"), +# Output("state_dropdown_key_y", "options"), +# Input("state_dropdown_state", "value"), +# State("session-store", "data") +# ) +# def update_dropdown(state, data_dict): +# if not state: +# return [], [], [], [] +# else: +# for st in data_dict['DB_STATE_DIC']: +# if st["_id"] == state: +# break +# site_list = list(["ALL"]) +# site_list.extend(st["Site"]) +# sat_list = list(["ALL"]) +# sat_list.extend(st["Sat"]) +# keys = st["keys"] +# keys_sat = [{"label": i, "value": i} for i in sat_list] +# keys_site = [{"label": i, "value": i} for i in site_list] +# keys_d = [{"label": i, "value": i} for i in keys if i[0] != "_"] +# return keys_site, keys_sat, keys_d @app.callback( @@ -292,37 +290,42 @@ def update_dropdown(state, data_dict): State("state_dropdown_state", "value"), State("state_dropdown_site", "value"), State("state_dropdown_sat", "value"), - State("state_dropdown_key_x", "value"), + State("sate_dropdown_serie", "value"), State("state_dropdown_key_y", "value"), State("state_dropdown_site", "options"), State("state_dropdown_sat", "options"), + State("sate_dropdown_serie", "options"), State("slider-polynomial-degree", "value"), State("poly_dropdown", "value"), State("exclude_npt", "value"), ) -def update_graph_measurements( - click, +def update_graph_state( + _click, data_dict, graph_type, state, site, sat, - xaxis, + serie, yaxis, list_site, list_sat, + list_series, poly_deg, fit_type, exclude, ): + """_summary_ + """ try: exclude = int(exclude) - except: + except BaseException: exclude = 0 if exclude < 0: exclude = 0 + xaxis = "Epoch" table = [] if ( graph_type is None @@ -331,64 +334,91 @@ def update_graph_measurements( or xaxis is None or yaxis is None ): - return ( - get_empty_graph("Make sure a value for all the Dropdown Menu is selected"), - [], - ) + return (util.get_empty_graph( + "Make sure a value for all the Dropdown Menu is selected"), [], ) else: site = [i["value"] for i in list_site] if "ALL" in site else site sat = [i["value"] for i in list_sat] if "ALL" in sat else sat + serie = [i["value"] for i in list_series] if "ALL" in serie else serie + if "ALL" in site: + site.remove("ALL") + if "ALL" in sat: + sat.remove("ALL") + if "ALL" in serie: + serie.remove("ALL") fig = go.Figure() - if fit_type != "": + if fit_type != "None": pol = PolynomialFeatures(poly_deg) model = make_pipeline(pol, LinearRegression()) trace = [] for yaxis_ in yaxis: - site_, sat_, x_, y_ = db.get_series(data_dict, - "States", state, site, sat, xaxis, yaxis_ - ) - for i in range(len(x_)): - _x, _y = x_[i][exclude:], y_[i][exclude:] - if fit_type != "": - x2 = _x.astype(float) - x2 = x2 - x2[0] - x2 = x2[:, np.newaxis] - model.fit(x2, _y) - coeff = model.steps[1][1].coef_.copy() - coeff[0] = model.steps[1][1].intercept_ - _yf = model.predict(x2) - a = dict() - a["ID"] = f"{site_[i]}-{sat_[i]}" - a["Intercept"] = coeff[0] - for ideg in range(len(coeff[1:])): - a["Deg %i" % (ideg + 1)] = coeff[ideg + 1] - a["RMS"] = np.sqrt(np.mean(np.square(_y - _yf))) - table.append(a) - if fit_type == "Detrend": - _y = _y - _yf - label = [] - if len(site) != 1: - label.append(site_[i]) - if len(sat) != 1: - label.append(sat_[i]) - if len(yaxis) != 1: - label.append(yaxis_) - - trace.append(generate_trace(graph_type, _x, _y, f'{"-".join(label)}')) - if fit_type == "Fit": + query = db.get_series2( + data_dict, "States", state, site, sat, serie, xaxis, yaxis_, "Num") + if len(query) == 0 : + return (util.get_empty_graph( + "Nothing to plot"), [], ) + for q in sorted(query): + record = query[q] + x_ = np.asarray(record['x'], dtype=np.datetime64) + y__ = record['y'] + num = record['z'] + unique_data = np.unique([item for sublist in num for item in sublist]) + d = {k: v for v, k in enumerate(unique_data)} + nx = len(x_) + ny = len(unique_data) + y_ = np.empty((nx,ny)) + y_.fill(np.nan) + # num__ = np.empty((nx,ny)).fill(np.nan) + for ix, a in enumerate(y__): + for iy, v in enumerate(a): + y_[ix, d[num[ix][iy]] ] = v + + label_base = f"{q}_{state}" + for i, v in enumerate(unique_data): + _x, _y = x_[:][exclude:], y_[:, i][exclude:] + if fit_type != "None": + nonans = ~np.isnan(_y) + x2 = (_x - _x[0]) + x2 = (x2 / np.timedelta64(1, 's')).astype(float) + x2 = x2[:, np.newaxis] + # print(len(x2), ) + model.fit(x2[nonans], _y[nonans]) + coeff = model.steps[1][1].coef_.copy() + coeff[0] = model.steps[1][1].intercept_ + _yf = model.predict(x2) + a = {} + a["ID"] = f"{label_base}_{str(unique_data[i])}" + a["Intercept"] = coeff[0] + for ideg in range(len(coeff[1:])): + a["Deg %i" % (ideg + 1)] = coeff[ideg + 1] + a["RMS"] = np.sqrt(np.mean(np.square(_y - _yf))) + table.append(a) + if fit_type == "Detrend": + _y = _y - _yf + label = label_base + "_" + str(unique_data[i]) + trace.append( - generate_trace( - graph_type, _x, _yf, f'{"-".join(label)}_deg{poly_deg}' - ) - ) + util.generate_trace( + graph_type, + _x, + _y, + f'{label}')) + if fit_type == "Fit": + trace.append( + util.generate_trace( + graph_type, + _x, + _yf, + f'{label}_deg{poly_deg}')) fig = go.Figure(data=trace) fig.update_layout( xaxis=dict(rangeslider=dict(visible=True)), - yaxis=dict(fixedrange=False, tickformat=".3f"), + yaxis=dict(fixedrange=False, tickformat=".3e"), height=800, ) fig.layout.autosize = True + fig.update_layout(showlegend=True) tab = [] if len(table) != 0 and fit_type != "None": cols = [] @@ -406,21 +436,24 @@ def update_graph_measurements( def layout(data_dict): - if data_dict== None: + """_summary_ + """ + if data_dict is None: return html.Div( [html.P("First you will need to select a DB in the Db Info menu")] ) - else: + elif data_dict['STATE_DB']: return html.Div( [ dropdown_type(), dropdown_state(data_dict['DB_STATES']), dropdown_site(data_dict['DB_SITE']), dropdown_sat(data_dict['DB_SAT']), - dropdown_key_x(data_dict['DB_STATE_DIC'][0]["keys"]), - dropdown_key_y(data_dict['DB_STATE_DIC'][0]["keys"]), + # dropdown_key_x(data_dict['DB_STATE_DIC'][0]["keys"]), + dropdown_serie(data_dict['Series']), + dropdown_key_y(["x", "P", "dx"]), # , "x+P"]), html.Div( - children=util.namedSlider( + children=util.named_slider( name="Polynomial Degree", id="slider-polynomial-degree", min=0, @@ -436,8 +469,12 @@ def layout(data_dict): # check_list(), update_button, dcc.Graph( - id="plot2", figure=get_empty_graph("select information first") + id="plot2", figure=util.get_empty_graph("select information first") ), html.Div(id="tableDiv", className="tableDiv"), ] ) + else: + return html.Div( + [html.P("No KF State in the DB, can't do anything on this page")] + ) diff --git a/scripts/GinanEDA/ginaneda/apps/utilities.py b/scripts/GinanEDA/ginaneda/apps/utilities.py new file mode 100644 index 000000000..6df525aec --- /dev/null +++ b/scripts/GinanEDA/ginaneda/apps/utilities.py @@ -0,0 +1,71 @@ +"""Generic utilites for the EDA +""" +from dash import dcc +from dash import html +import plotly.graph_objs as go + + +def _merge(origin, append): + return dict(origin, **append) + + +def _omit(omitted_keys, dictionary): + return {k: v for k, v in dictionary.items() if k not in omitted_keys} + + +def named_slider(name, **kwargs): + """Generate name slider + """ + return html.Div( + # style={'padding': '10px 10px 15px 4px'}, + children=[ + html.P(f"{name}:"), + html.Div(dcc.Slider(**kwargs), style={"margin-left": "3px"}), + ] + ) + + +def named_dropdown(name, **kwargs): + """Generate a Dropdown list + """ + dropdown = [] + if name is not None: + dropdown.append(html.P(f"{name}:", style={"margin-left": "3px"})) + dropdown.append(dcc.Dropdown(**kwargs)) + return html.Div(dropdown) + + +def get_empty_graph(message=""): + """Return an empty placeholder for the graphe with a message + """ + emptiness = { + "layout": { + "xaxis": {"visible": False}, + "yaxis": {"visible": False}, + "annotations": [ + { + "text": message, + "xref": "paper", + "yref": "paper", + "showarrow": False, + "font": {"size": 28}, + } + ], + } + } + return emptiness + + +def generate_trace(graph_type, x_array, y_array, label): + """Generate plotly traces + """ + if graph_type == "Line" or graph_type == "Scatter": + mode = "lines" if graph_type == "Line" else "markers" + trace = go.Scatter(x=x_array, y=y_array, mode=mode, name=label) + elif graph_type == "POLAR": + trace = go.Scatterpolar(r=y_array, theta=x_array, mode="markers", name=label) + elif graph_type == "HistogramX": + trace = go.Histogram(x=y_array, name=label) + elif graph_type == "HistogramY": + trace = go.Histogram(y=y_array, name=label) + return trace diff --git a/scripts/GinanEDA/GinanEDA/assets/bWLwgP.css b/scripts/GinanEDA/ginaneda/assets/bWLwgP.css similarity index 100% rename from scripts/GinanEDA/GinanEDA/assets/bWLwgP.css rename to scripts/GinanEDA/ginaneda/assets/bWLwgP.css diff --git a/scripts/GinanEDA/GinanEDA/apps/__init__.py b/scripts/GinanEDA/ginaneda/datasets/__init__.py similarity index 100% rename from scripts/GinanEDA/GinanEDA/apps/__init__.py rename to scripts/GinanEDA/ginaneda/datasets/__init__.py diff --git a/scripts/GinanEDA/ginaneda/datasets/db.py b/scripts/GinanEDA/ginaneda/datasets/db.py new file mode 100644 index 000000000..7ce4d8bb8 --- /dev/null +++ b/scripts/GinanEDA/ginaneda/datasets/db.py @@ -0,0 +1,251 @@ +"""_summary_ +""" +import logging + +import numpy as np +from dash import html +from pymongo import MongoClient + + +logger = logging.getLogger(__name__) + + +# exclusion list for dropdown x and y +exclude_measurements = [ + "_id" +] + +exclude_state = ["_id"] + + +def check_db(url=None, db=None): + """_summary_ + """ + if url is None: + return html.P(f"Not connected") + else: + return html.P(f"Connected to dataserver {url}, dataset {db}") + + +def connect_client(url): + """_summary_ + """ + cl = MongoClient(host=url) + return cl + + +pipeline_state = [ + { + "$group": { + "_id": "$State", + "Site": {"$addToSet": "$Site"}, + "Sat": {"$addToSet": "$Sat"}, + } + } +] + +def reshape_list(l): + return list(set([item for sublist in l for item in sublist])) + +def connect_db(data_dict): + """_summary_ + """ + if data_dict['MONGO_URL'] is None or data_dict['MONGO_DB'] is None: + return + data_dict['DB_MEAS_KEY'] = [] + data_dict['DB_SITE'] = [] + data_dict['DB_SAT'] = [] + data_dict['DB_STATES'] = [] + data_dict['Geom']=[] + data_dict['Series']=[] + for db_name in data_dict['MONGO_DB']: + mongo_cl = connect_client(data_dict['MONGO_URL'])[db_name] + list_cl = list(mongo_cl.list_collection_names()) + content = mongo_cl["Content"].find({}) + for doc in content: + if doc['type'] == "Site": + data_dict['DB_SITE'].append(doc['Values']) + if doc['type'] == "Sat": + data_dict['DB_SAT'].append(doc['Values']) + if doc['type'] == 'Series': + for s in doc['Values']: + data_dict['Series'].append(f"{db_name}\{s}") + if doc['type'] == 'Measurements': + data_dict['DB_MEAS_KEY'].append('Epoch') + data_dict['DB_MEAS_KEY'].append('Site') + data_dict['DB_MEAS_KEY'].append('Sat') + for rec in doc['Values']: + data_dict['DB_MEAS_KEY'].append(rec) + if doc['type'] == "State": + data_dict['DB_STATES'].append(doc['Values']) + if "Geometry" in list_cl: + geom = mongo_cl["Geometry"].find_one({}) + for i in geom: + if i not in ['Epoch', 'Site', 'Sat', 'Series']: + data_dict['Geom'].append(i) + for l in [ 'DB_SITE', 'DB_SAT', 'DB_STATES']: + data_dict[l] = reshape_list(data_dict[l]) + data_dict[l].sort() + + data_dict['DB_MEAS_KEY'] = sorted(set(data_dict['DB_MEAS_KEY'])) + data_dict['Geom'] = sorted(set(data_dict['Geom'])) + if "Measurements" in list_cl: + logger.info( + f" => Measurements contains {len(data_dict['DB_SITE'])} sites and {len(data_dict['DB_SAT'])} satellites" + ) + logger.info(f" List of Keys : {', '.join( data_dict['DB_MEAS_KEY'])}") + data_dict['MEAS_DB'] = True + else: + logger.warning(" => Measurements collection not present") + data_dict["MEAS_DB"] = False + if "States" in list_cl : + logger.info("States are present") + data_dict['STATE_DB'] = True + else: + logger.warning(" => States collection not present") + data_dict['STATE_DB'] = False + + +def get_keys(mongo_cl, collection): + """_summary_ + """ + pipeline = [ + {"$project": {"keyvalue": {"$objectToArray": "$$ROOT"}}}, + {"$unwind": {"path": "$keyvalue"}}, + {"$group": {"_id": None, "allkeys": {"$addToSet": "$keyvalue.k"}}}, + ] + if mongo_cl is not None:# and MONGO_DB is not None: + l = list(mongo_cl[collection].aggregate(pipeline)) + else: + return list([None]) + return sorted(l[0]["allkeys"]) + + +def get_series2(data, collection, state, site, sat, serie, x1, x2, x3=None): + results = {} + for s in serie: + db_, s_ = s.split('\\') + results.update(get_series(data, collection, state, site, sat, db_, s_, x1, x2, x3)) + return results + + + +def get_series(data, collection, state, site, sat, db, serie, x1, x2, x3): + """_summary_ + """ + logger.info("getting data") + pipeline = [] + pipeline.append( + {"$match": {"Sat": {"$in" : sat}, + "Site": {"$in": site}, + "Series": {"$in": [serie]}} + }) + if state is not None: + pipeline[-1]["$match"]["State"] = state + pipeline.append( {"$sort": {"Epoch": 1}}) + pipeline.append( { + "$group": { + "_id": {"site": "$Site", "sat": "$Sat", "series":"$Series"}, + "t" : {"$push": "$Epoch"}, + "x": {"$push": "$" + x1}, + "y": {"$push": "$" + x2}, + } + }) + if x3 is not None: + pipeline[-1]["$group"]["z"] = {"$push": "$" + x3} + logger.info("connection to db") + logger.info("getting data") + mongo_cl = connect_client(data["MONGO_URL"])[db] + req = {} + req2 = {} + for cursor in mongo_cl[collection].aggregate(pipeline): + req[db+"_"+cursor['_id']['series']+"_"+cursor['_id']['site']+"_"+cursor['_id']['sat']] = cursor + + suffix = "" + for i, v in enumerate(pipeline[0]["$match"]["Series"]["$in"]): + pipeline[0]["$match"]["Series"]["$in"][i] = v.split("_")[0] + if len(v.split("_")) > 1: + suffix = "_"+v.split("_")[1] + + for cursor in mongo_cl["Geometry"].aggregate(pipeline): + req2[db+"_"+cursor['_id']['series']+suffix+"_"+cursor['_id']['site']+"_"+cursor['_id']['sat']] = cursor + + for r in req2: + print(r) + print("=====") + for r in req: + print(r) + if len(req2)!=0: + for r in req: + if r in req2: + r2 = req2[r] + if len(req[r]["x"]) == 0 and len(r2["x"])!=0: + intersect, c1, c2 = np.intersect1d(req[r]["t"] , r2["t"], return_indices = True) + req[r]["x"] = np.asarray(r2["x"])[c2] + if len(req[r]["y"]) == 0 and len(r2["y"])!=0: + intersect, c1, c2 = np.intersect1d(req[r]["t"] , r2["t"], return_indices = True) + req[r]["y"] = np.asarray(r2["y"])[c2] + if x3 is not None and len(req[r]["z"]) == 0 and len(r2["z"])!=0: + intersect, c1, c2 = np.intersect1d(req[r]["x"] , r2["x"], return_indices = True) + req[r]["z"] = np.asarray(r2["z"])[c2] + # continue + logger.info("get data") + return req + + +##def get_series(data, collection, state, site, sat, serie, x1, x2): +## """_summary_ +## """ +## req_match_1 = {"$match": {"Sat": {"$in": sat}, "Site": {"$in": site}}} +## req_match_2 = {"$match": {x1: {"$ne": None}, x2: {"$ne": None}}} +## +## req_match_state1 = { +## "$match": { +## "Sat": {"$in": sat}, +## "Site": {"$in": site}, +## "State": state, +## "Series":{"$in": serie} +## } +## } +## req_match_state2 = {"$match": {x1: {"$ne": None}, x2: {"$ne": None}}} +## req_sort = {"$sort": {"Epoch": 1}} +## req_group = { +## "$group": { +## "_id": {"site": "$Site", "sat": "$Sat", "series":"$Series"}, +## "x": {"$push": "$" + x1}, +## "y": {"$push": "$" + x2}, +## } +## } +## req_sort2 = {"$sort": {"_id.site": 1, "_id.sat": 1, "_id.series": 1}} +## pipeline = [] +## if state is not None: +## pipeline.append(req_match_state1) +## pipeline.append(req_match_state2) +## else: +## pipeline.append(req_match_1) +## pipeline.append(req_match_2) +## +## pipeline.append(req_sort) +## if x1 == "Epoch": +## pipeline.append({"$project": {x1: 1, x2: 1, "Sat": 1, "Site": 1, "Series": 1}}) +## pipeline.append(req_group) +## pipeline.append(req_sort2) +## mongo_cl = connect_client(data["MONGO_URL"])[data["MONGO_DB"]] +## req = mongo_cl[collection].aggregate(pipeline) +## x_ = [] +## y_ = [] +## sat_ = [] +## site_ = [] +## serie_ =[] +## for i in req: +## x1_ = np.array(i["x"]) +## x2_ = np.array(i["y"]) +## if x1 == "Epoch": +## x_.append(x1_.astype("datetime64[s]")) +## else: +## x_.append(x1_) +## y_.append(x2_) +## sat_.append(i["_id"]["sat"]) +## site_.append(i["_id"]["site"]) +## serie_.append(i["_id"]["serie"]) +## return site_, sat_, serie_, x_, y_ diff --git a/scripts/GinanEDA/index.py b/scripts/GinanEDA/index.py old mode 100644 new mode 100755 index a0e6e9ded..71b3773a0 --- a/scripts/GinanEDA/index.py +++ b/scripts/GinanEDA/index.py @@ -1,12 +1,16 @@ +#!/usr/bin/env python3 + +"""_summary_ +""" import logging from dash import dcc, html from dash.dependencies import Input, Output, State -import GinanEDA +import ginaneda from app import app, server -from GinanEDA.apps import dbinfo, meas, meas_polar, state, pos -from GinanEDA.datasets import db +from ginaneda.apps import dbinfo, meas, meas_polar, state, pos, clock +from ginaneda.datasets import db CONTENT_STYLE = { @@ -36,8 +40,16 @@ html.Hr(), html.Ul( children=[ - html.Li(dcc.Link("Db Info", href="/dbinfo", id="page-dbinfo-link")), - html.Li(dcc.Link("States", href="/states", id="page-states-link")), + html.Li( + dcc.Link( + "Db Info", + href="/dbinfo", + id="page-dbinfo-link")), + html.Li( + dcc.Link( + "States", + href="/states", + id="page-states-link")), html.Li( dcc.Link( "Measurements", @@ -59,6 +71,13 @@ id="page-position-link", ) ), + html.Li( + dcc.Link( + "Clock Analysis", + href="/clock-analysis", + id="page-clock-link", + ) + ), ] ), html.Div(id='dummy1'), @@ -68,21 +87,26 @@ ) content = html.Div(id="page-content", children=[], style=CONTENT_STYLE) -app.layout = html.Div([dcc.Location(id="url", refresh=False), sidebar, content]) +app.layout = html.Div( + [dcc.Location(id="url", refresh=False), sidebar, content]) -@app.callback(Output("page-content", "children"), Input("url", "pathname"), State("session-store", "data"), - ) +@app.callback(Output("page-content", "children"), Input("url", + "pathname"), State("session-store", "data"), ) def display_page(pathname, datastore): + """_summary_ + """ if pathname == "/measurements": return meas.layout(datastore) - if pathname == "/states": + elif pathname == "/states": return state.layout(datastore) - if pathname == "/measurements-polar": + elif pathname == "/measurements-polar": return meas_polar.layout(datastore) - if pathname == "/position-analysis": + elif pathname == "/position-analysis": return pos.layout(datastore) - if pathname == "/dbinfo": + elif pathname == "/clock-analysis": + return clock.layout(datastore) + elif pathname == "/dbinfo": return dbinfo.layout else: return "404 Page Error! Please choose a link" diff --git a/scripts/OSX_Install.sh b/scripts/OSX_Install.sh deleted file mode 100644 index 9740dc5dd..000000000 --- a/scripts/OSX_Install.sh +++ /dev/null @@ -1,230 +0,0 @@ -#!/bin/sh -set -e - -echo "This script downloads and install the dependencies for GINA on OSX." -echo "You must first install xcode on your mac." -echo "It installs the the dependencies in /usr/local after making local_backup.tar.gz in the Documents directory." -echo "Find installation does not work try sudo rm -r /usr/local/* to clear all previously installed packages." -echo "It makes the entire GINAN (including Fortan) as well as a xcdoe project in src/xcode" -echo "It makes the directory ginan_dep in documents and then deletes it when finished." -echo "It does not install a mongoDB server (drivers only)." -echo "It expects to be run from the ginan/scripts directory." -echo "To run make requires a define on the command line, cmake -DBoost_INCLUDE_DIR=/usr/local/include .." - -xcode-select --install || true -echo "Please wait for xcode command line tools to install then press a key." -read -n 1 - - -ginan_dir=$PWD/.. -doc_dir=~/ -build=~/ginan_dep -sudo rm -r $build || true -mkdir -p $build - -backup_file=$doc_dir/local_backup.tar.gz -if test -f "$backup_file"; then - echo "Backup of /usr/local already exists." -else - sudo tar -cvf $backup_file /usr/local -fi - -CC=gcc -FC=gfortran -CPPFLAGS=-I/usr/local/include -LDFLAGS=-L/usr/local/lib - -# gcc and gfortan -cd $build -if [[ `uname -m` == 'arm64' ]]; then - curl -OL https://sourceforge.net/projects/hpc/files/hpc/gcc/gcc-m1-bin.tar.gz -else - curl -OL https://sourceforge.net/projects/hpc/files/hpc/gcc/gcc-11.2-bin.tar.gz -fi - -sudo tar -xvf gcc-11.2-bin.tar.gz -C /. || true - -cd $build -curl -OL http://gnu.mirrors.hoobly.com/m4/m4-1.4.tar.gz -tar -xvf m4-1.4.tar.gz -cd m4-1.4 -./configure --prefix=/usr/local -make -j8 -sudo make install - -cd $build -curl -OL https://github.com/Kitware/CMake/releases/download/v3.22.0-rc3/cmake-3.22.0-rc3-macos-universal.tar.gz -tar -xvf cmake-3.22.0-rc3-macos-universal.tar.gz -sudo mv ./cmake-3.22.0-rc3-macos-universal/CMake.app /Applications || true -sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install - -cd $build -curl -OL http://ftpmirror.gnu.org/autoconf/autoconf-2.68.tar.gz -tar xzf autoconf-2.68.tar.gz -cd autoconf-2.68 -./configure --prefix=/usr/local -make -j8 -sudo make install -export PATH=$PATH:$build/autotools-bin/bin - -cd $build -curl -OL http://ftpmirror.gnu.org/automake/automake-1.11.tar.gz -tar xzf automake-1.11.tar.gz -cd automake-1.11 -./configure --prefix=/usr/local -make -j8 -sudo make install - -cd $build -curl -OL http://ftpmirror.gnu.org/libtool/libtool-2.4.tar.gz -tar xzf libtool-2.4.tar.gz -cd libtool-2.4 -./configure --prefix=/usr/local -make -j8 -sudo make install - -cd $build -curl -OL https://sourceforge.net/projects/libpng/files/zlib/1.2.11/zlib-1.2.11.tar.gz -tar -xvf zlib-1.2.11.tar.gz -cd zlib-1.2.11 -./configure --prefix=/usr/local --static --archs="-arch x86_64" -./configure --prefix=/usr/local -make -j4 -sudo make install - -cd $build -curl -OL https://ftp.gnu.org/pub/gnu/gettext/gettext-0.21.tar.gz -tar -xvf gettext-0.21.tar.gz -cd gettext-0.21 -./configure --prefix=/usr/local -make -j8 -sudo make install - - -cd $build -curl -O https://mac.r-project.org/openmp/openmp-12.0.1-darwin20-Release.tar.gz -sudo tar fvxz openmp-12.0.1-darwin20-Release.tar.gz -C / || true - -cd $build -curl -OL https://github.com/xianyi/OpenBLAS/releases/download/v0.3.17/OpenBLAS-0.3.17.tar.gz -tar -xvf OpenBLAS-0.3.17.tar.gz -cd OpenBLAS-0.3.17 -mkdir build -cd build -cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. -make -j8 -sudo make install - -cd $build -curl -OL https://www.openssl.org/source/old/3.0/openssl-3.0.0-beta2.tar.gz -tar -xvf openssl-3.0.0-beta2.tar.gz -cd openssl-3.0.0-beta2 -./Configure --prefix=/usr/local -make -j8 -sudo make install - -cd $build -sudo git clone https://github.com/jbeder/yaml-cpp.git -cd yaml-cpp -sudo mkdir cmake-build -cd cmake-build -sudo cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DYAML_CPP_BUILD_TESTS=OFF -sudo make install yaml-cpp - -cd $build -git clone https://github.com/erdc/szip.git -cd szip -./configure --prefix=/usr/local -make -j8 -sudo make install - -cd $build -git clone https://github.com/HDFGroup/hdf5.git -cd hdf5 -sudo mkdir build -cd build -sudo CC=gcc CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DHDF5_ENABLE_Z_LIB_SUPPORT=ON -DBUILD_SHARED_LIBS=ON -DHDF5_BUILD_FORTRAN=ON -DBUILD_STATIC_LIBS=ON .. -sudo CC=gcc CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib make -j8 install - -#cd $build -#git clone https://github.com/Unidata/netcdf-fortran.git -#cd netcdf-fortran -#mkdir build -#cd build -#sudo cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -#sudo make -j8 install - -cd $build -git clone https://github.com/Unidata/netcdf-c.git -cd netcdf-c -mkdir build -cd build -sudo CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -sudo CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib make -j8 install - -cd $build -git clone https://github.com/Unidata/netcdf-cxx4.git -cd netcdf-cxx4 -git fetch -git checkout 4.3.0 -sudo CPPFLAGS=-I/usr/local/include ./configure --prefix=/usr/local -sudo make -j8 install - -cd $build -curl -OL https://github.com/mongodb/mongo-c-driver/releases/download/1.17.1/mongo-c-driver-1.17.1.tar.gz -tar -xvf mongo-c-driver-1.17.1.tar.gz -cd mongo-c-driver-1.17.1/ -mkdir cmakebuild -cd cmakebuild/ -sudo cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DCMAKE_INSTALL_PREFIX=/usr/local .. -sudo make -j8 install - - -cd $build -curl -OL https://github.com/mongodb/mongo-cxx-driver/releases/download/r3.6.0/mongo-cxx-driver-r3.6.0.tar.gz -tar -xzf mongo-cxx-driver-r3.6.0.tar.gz -cd mongo-cxx-driver-r3.6.0/ -cd build/ -sudo cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local .. -sudo cmake --build . --target EP_mnmlstc_core -j8 -sudo cmake --build . -j8 -sudo cmake --build . --target install -j8 - - -cd $build -sudo git clone https://gitlab.com/libeigen/eigen.git -cd eigen -sudo mkdir cmake-build -cd cmake-build -sudo cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. -make -j8 -sudo make install - -cd $build -curl -OL https://boostorg.jfrog.io/artifactory/main/release/1.73.0/source/boost_1_73_0.tar.gz -tar -xvf boost_1_73_0.tar.gz -cd boost_1_73_0/ -sudo ./bootstrap.sh -sudo ./b2 install - -sudo rm -r $build - -cd $ginan_dir -cd src -mkdir build -cd build -cmake -DBoost_INCLUDE_DIR=/usr/local/include .. -make -j8 pea -make -j8 pod - -cd $ginan_dir -cd src -mkdir xcode -cd xcode -cmake -DBoost_INCLUDE_DIR=/usr/local/include -DFORTRAN_TARGETS=OFF -G Xcode .. - -cd $ginan_dir -cd scripts -python3 download_examples.py - -echo "Installation complete." diff --git a/scripts/auto_run_PPP.py b/scripts/auto_run_PPP.py index 0e826dae9..fcaf96cd2 100644 --- a/scripts/auto_run_PPP.py +++ b/scripts/auto_run_PPP.py @@ -129,7 +129,7 @@ def auto_run_main( start_datetime=start_datetime, end_datetime=end_datetime, most_recent=False, - ac=analysis_centre, + analysis_centre=analysis_centre, atx=atx, blq=blq, snx=snx, diff --git a/scripts/conda_gn37.yaml b/scripts/conda_gn37.yaml index 5de175015..a3e536fed 100644 --- a/scripts/conda_gn37.yaml +++ b/scripts/conda_gn37.yaml @@ -4,20 +4,6 @@ channels: dependencies: - python=3.7 # need ipython 6.5.0 as higher do not autocomlete - pip=22.1 - - requests=2.27.1 - - numpy=1.21.6 # don't care of specific numpy and pandas versions - - pandas=1.1.0 #MongoDash required version - - matplotlib=3.5.2 - - ruamel.yaml=0.17.21 - - wget=1.20.3 - - boto3=1.23.1 - - ipython=6.5.0 #need this version - - notebook>=5.3 #MongoDash - - ipywidgets>=7.2 #MongoDash - - pymongo=3.7.2 #MongoDash - - pytest=7.1.2 - - scipy=1.7.3 - - statsmodels=0.13.2 - pip: - sklearn==0.0 - gnssanalysis==0.0.28 @@ -28,4 +14,18 @@ dependencies: - plotext==4.2 - requests_oauthlib==1.3.1 - werkzeug==2.0.3 + - gnssanalysis #may need to fix version so various branches of ginan could evolve independently, though requires updating the image + - requests==2.27.1 + - numpy==1.21.6 # don't care of specific numpy and pandas versions + - pandas==1.1.0 #MongoDash required version + - matplotlib==3.5.2 + - ruamel.yaml==0.17.21 + - boto3==1.23.1 + - ipython==6.5.0 #need this version + - notebook>=5.3 #MongoDash + - ipywidgets>=7.2 #MongoDash + - pymongo==3.7.2 #MongoDash + - pytest==7.1.2 + - scipy==1.7.3 + - statsmodels==0.13.2 diff --git a/scripts/diffutil.py b/scripts/diffutil.py deleted file mode 100755 index 649178e58..000000000 --- a/scripts/diffutil.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 - -'''Utility for testing trace files equivalence.''' -import argparse -import logging as _logging -import os as _os -import sys as _sys - -from gn_lib import gn_diffaux as _gn_diffaux - -#TODO convert argparse to click -def parse_arguments(): - parser = argparse.ArgumentParser(description='''Compares the content of two files, and returns errors on difference. \ -Supports trace (either .trace or .SUM), sinex, ionex and stec files. The user is required to set a file type with -t option.''') - parser.add_argument('-i','--file1',type=file_path,required=True, - help='path to a compared file (.trace|.snx|.I|.stec). Can be compressed with LZW (.Z) or gzip (.gz)') - parser.add_argument('-o','--file2',type=file_path,required=True, - help='path to a file to compare to - e.g. a corresponding solution file') - parser.add_argument('-t','--type', type=str,action='store',default="auto",required=False, - choices=["auto","sinex","trace","ionex","stec","clk","sp3","pod"], - help = "type of files for comparison") - parser.add_argument('-a','--atol', type=float,default=None, - help='absolute tolerance') - parser.add_argument('-c','--coef', type=float,default=1, - help='std coefficient. Default value is 1 so bounds are +- std') - parser.add_argument('-p','--plot', action='store_true', - help='output a plot to terminal. Requires plotext') - parser.add_argument( '--passthrough',action='store_true', - help='passthrough or return 0 even if failed. Useful for pipeline runs.') - parser.add_argument('--aux1', type=file_path,default=None, - help='path to aux "a" file') - parser.add_argument('--aux2', type=file_path,default=None, - help='path to aux "b" file') - return parser.parse_args() - -def file_path(path): - if _os.path.isfile(path): - return path - else: - raise argparse.ArgumentTypeError(f"{path} is not a valid path") - -def path2type(path): - """ - Returns a suffix of a file from a path, - Uses a dict to correct for known suffix issues file types. - If not present in dict -> return suffix as extracted. - """ - basename = _os.path.basename(path) - suffix = basename.split('.')[1].lower() - filetype_dict = {'snx':'sinex','sum':'trace','eph':'sp3'} - if suffix in filetype_dict.keys(): - return filetype_dict[suffix] - elif suffix == 'out': - return basename[:3] - elif suffix[:2].isdigit and suffix[2]=='i': - return 'ionex' - return suffix - -if __name__ == "__main__": - parsed_args = parse_arguments() - _logging.getLogger().setLevel(_logging.INFO) - _logging.info(f":diffutil ========== STARTING DIFFUTIL ==========") - _logging.info(f":diffutil input1 [-i]: {_os.path.abspath(parsed_args.file1)}") - _logging.info(f":diffutil input2 [-o]: {_os.path.abspath(parsed_args.file2)}" ) - - types = parsed_args.file1 - if parsed_args.type == 'auto': - types = path2type(parsed_args.file1) - _logging.info(f":diffutil determined '{types}' based on input1 as auto selected" ) - _logging.info(f":diffutil selected {'STD values' if parsed_args.atol == None else f'{parsed_args.atol:.1E} tolerance'} threshold") - - status = 0 - log_lvl = 40 if parsed_args.atol is None else 30 # 40 is error, 30 is warning. Constant tolerance differences are reported as warnings - if types == 'trace': - status = _gn_diffaux.difftrace(trace1_path=parsed_args.file1,trace2_path=parsed_args.file2,atol=parsed_args.atol,std_coeff=parsed_args.coef,log_lvl=log_lvl,plot=parsed_args.plot) - elif types == 'sinex': - status = _gn_diffaux.diffsnx(snx1_path = parsed_args.file1,snx2_path = parsed_args.file2,atol=parsed_args.atol,std_coeff=parsed_args.coef,log_lvl=log_lvl) - elif types == 'ionex': - status = _gn_diffaux.diffionex(ionex1_path=parsed_args.file1,ionex2_path=parsed_args.file1,atol=parsed_args.atol,log_lvl=log_lvl) - elif types == 'stec': - status = _gn_diffaux.diffstec(path1 = parsed_args.file1,path2 = parsed_args.file2,atol=parsed_args.atol,std_coeff=parsed_args.coef,log_lvl=log_lvl) - elif types == 'clk': - status = _gn_diffaux.diffclk(clk_a_path=parsed_args.file1,clk_b_path=parsed_args.file2,atol=parsed_args.atol,log_lvl=log_lvl) - elif types == 'sp3': - status = _gn_diffaux.diffsp3(sp3_a_path=parsed_args.file1,sp3_b_path=parsed_args.file2,clk_a_path=parsed_args.aux1,clk_b_path=parsed_args.aux2,tol=parsed_args.atol,log_lvl=log_lvl) - elif types == 'pod': - status = _gn_diffaux.diffpodout(pod_out_a_path=parsed_args.file1,pod_out_b_path=parsed_args.file2,tol=parsed_args.atol,log_lvl=log_lvl) - if status: - if not parsed_args.passthrough: - _logging.error(msg = f':diffutil failed [{_os.path.abspath(parsed_args.file1)}]\n') - _sys.exit(status) - else: - _logging.info(msg = ':diffutil failed but no sys.exit as passthrough enabled\n') - else: - _logging.info(':diffutil [ALL OK]') diff --git a/scripts/download_examples.py b/scripts/download_examples.py index 46789ae33..f45687650 100755 --- a/scripts/download_examples.py +++ b/scripts/download_examples.py @@ -1,82 +1,59 @@ #!/usr/bin/env python3 """Downloads/Uploads auxiliary examples files to/from examples dir""" - -import argparse import logging as _logging -from multiprocessing.sharedctypes import Value -from typing import Union as _Union from pathlib import Path as _Path -from shutil import copy as _copy, rmtree as _rmtree +from shutil import copy as _copy +from shutil import rmtree as _rmtree +from typing import Union as _Union -from gn_lib.gn_download import ( - download_url, - request_checksum, - upload_with_chunksize_and_meta, - get_vars_from_file -) -from gn_lib.gn_io.common import compute_checksum, tar_comp, tar_extr +import click as _click +import gnssanalysis as ga EX_GLOB_DICT = { - "ex11" :["*.TRACE", "*.snx", "*.*_smoothed"], - "ex12" :["*.TRACE", "*.snx"], - "ex13" :["*.TRACE", "*.snx"], - "ex14" :["*.TRACE", "*.snx"], - "ex15" :["*.TRACE", "*.snx"], - "ex16" :["*Network*.TRACE","*.*I", "*.stec", "*.snx", "*.BIA"], - "ex17" :["*Network*.TRACE","*.snx", "*.clk*"], - - "ex21" :["pod*.out","*.sp3"], - "ex22g":["pod*.out","*.sp3"], - "ex22r":["pod*.out","*.sp3"], - "ex22e":["pod*.out","*.sp3"], - "ex22c":["pod*.out","*.sp3"], - "ex22j":["pod*.out","*.sp3"], - "ex23" :["pod*.out","*.sp3"], - "ex24" :["pod*.out","*.sp3"], - "ex25" :["pod*.out","*.sp3"], - "ex26" :["pod*.out","*.sp3"], + "ex02": ["*.TRACE"], + "ex11": ["*.TRACE", "*.snx", "*.*_smoothed"], + "ex12": ["*.TRACE", "*.snx"], + "ex13": ["*.TRACE", "*.snx"], + "ex14": ["*.TRACE", "*.snx"], + "ex15": ["*.TRACE", "*.snx"], + "ex16": ["*Network*.TRACE", "*.*I", "*.stec", "*.snx", "*.BIA", "*.INX*"], + "ex17": ["*Network*.TRACE", "*.snx", "*.clk*"], + "ex21": ["pod*.out", "*.sp3"], + "ex22g": ["pod*.out", "*.sp3"], + "ex22r": ["pod*.out", "*.sp3"], + "ex22e": ["pod*.out", "*.sp3"], + "ex22c": ["pod*.out", "*.sp3"], + "ex22j": ["pod*.out", "*.sp3"], + "ex23": ["pod*.out", "*.sp3"], + "ex24": ["pod*.out", "*.sp3"], + "ex25": ["pod*.out", "*.sp3"], + "ex26": ["pod*.out", "*.sp3"], + "ex31": [ + "pod_fit/pod*.out", + "pod_fit/*.sp3", + "pea/*etwork*.TRACE*", # Network starts with lower case for some reason + "pea/*.snx", + "pea/*.erp", + "pea/*clk*", + "pod_ic/pod*.out", + "pod_ic/*.sp3", + ], + "ex41": ["*.TRACE", "*.snx", "*.*_smoothed"], + "ex42": ["*.TRACE", "*.snx"], + "ex43": ["*.TRACE", "*.snx"], + "ex43a": ["*.TRACE", "*.snx"], + "ex44": ["*.TRACE", "*.snx"], + "ex48": ["*.TRACE", "*.snx"], + "ex51": [ + "*blq", + ], + "ex52": [ + "*blq", + ], } -def parse_arguments(): - parser = argparse.ArgumentParser( - description=( - "Downloads 'products', 'data', and 'solutions' tarballs from s3 bucket and" - " extracts the content into examples dir. The list of tarballs can be" - " changed with the combination of [-p/-d/-s] options. Similar tarballs" - " upload functionality is available - can be activated with '--push' key" - "To configure the utility for --push functionality it is enough to create" - " ~/.aws/credentials file containing" - "[default] / aws_access_key_id=ACCESS_KEY / " - "aws_secret_access_key=SECRET_KEY" - ) - ) - parser.add_argument( - "--push", - action="store_true", - help="tar dirs and push them to aws with checksum metadata and public read", - ) - parser.add_argument("-s", "--solutions", action="store_true", help="") - parser.add_argument("-d", "--data", action="store_true", help="") - parser.add_argument("-p", "--products", action="store_true", help="") - parser.add_argument("--dirs", nargs="+", default=[]) - parser.add_argument("--tag", default='') - parser.add_argument( - "--skip_extract", - action="store_true", - help=( - "Skips extraction of the on-disk tar file if checksum test is OK and the" - " destination dir exists. This is done to save time in the pipeline as" - " there is no need to overwrite the files." - ), - ) - parser.add_argument("--path", default=None,help="custom path to examples dir, a dir that stores products/data etc, default is ginan/examples") - parser.add_argument("--bucket", default="peanpod",help="s3 bucket name to push and pull from") - parser.add_argument("--target", default="aux",help="s3 target name (dir) within the selected bucket") - return parser.parse_args() - - def insert_tag(name: str, tag: str) -> str: """inserts tag name right before the filename: insert_tag('ex11','some_tag') -> 'some_tag/ex11' @@ -87,50 +64,62 @@ def insert_tag(name: str, tag: str) -> str: return "/".join(name_split) -def get_example_type(name:str)->_Union[str,bool]: +def get_example_type(name: str) -> _Union[str, bool]: """ - Checks if input string is a type of example dir, e.g. ex22g, + Checks if input string is a type of example dir, e.g. ex22g, returns string type of the example test. ex13 (name[2]==1) is 'PEA' and ex21 (name[2]==2) is 'POD' """ - if name.startswith("ex") and len(name) <= 5: - idx = int(name[2]) - if idx == 1: return 'PEA' - elif idx == 2: return 'POD' - elif idx == 3: return 'PEAPOD' - else: raise ValueError(f"Example code '{idx}' could not be matched to a type") + ex_type_dict = {"0": "PEA", "1": "PEA", "2": "POD", "3": "PEAPOD", "4": "PEA", "5": "OTHER"} + if name.startswith("ex"): + try: + idx = name[2] + return ex_type_dict[idx] + except KeyError: + raise ValueError(f"Example code '{idx}' could not be matched to a type") return False -def update_solutions_dict(examples_dir: _Path, dir: str, ex_glob_dict: dict, tag:str=''): +def update_solutions_dict(examples_dir: _Path, directory: str, ex_glob_dict: dict, tag: str = ""): """ """ - if get_example_type(dir): # room for five-symbol name - ex22g - example_dir = examples_dir / dir - ref_sol_dir = examples_dir /"solutions" / tag / dir + if get_example_type(directory): # room for five-symbol name - ex22g + example_dir = examples_dir / directory + ref_sol_dir = examples_dir / "solutions" / tag / directory if example_dir.exists() and ref_sol_dir.exists(): _rmtree(ref_sol_dir) _logging.info( f"removing {ref_sol_dir} and its content" ) # if actual solution exists -> clean respective reference solution before copying l = len(example_dir.as_posix()) - for expr in ex_glob_dict[dir]: - expr_counter = 0 - for path in example_dir.glob(expr): + + if directory not in ex_glob_dict.keys(): + raise ValueError(f"{directory} not in EX_GLOB_DICT dictionary") + + paths_list = [] + for expr in ex_glob_dict[directory]: + paths = list(example_dir.glob(expr)) + if paths == []: + _logging.warning(msg=f"no files were found using the {expr} rule") + paths_list.append(paths) + for path in paths: dst = ref_sol_dir / (path.as_posix()[l + 1 :]) - if expr_counter == 0: - dst.parent.mkdir(parents=True, exist_ok=True) + dst.parent.mkdir(parents=True, exist_ok=True) _logging.info(f"Copying {path} -> {_copy(src=path,dst=dst)}") - # else: - # _logging.info(f"skipping examples syncing as {dir} name does not copply with examples naming convention 'ex.{{1-3}}' dir") + if not any(paths_list): + raise ValueError( + f"No files found in '{example_dir}' according to {directory} directory rules from EX_GLOB_DICT: {ex_glob_dict[directory]}" + ) def upload_examples_tar( - examples_path, - bucket, - target, - dirs=("products", "data", "solutions"), - compression="bz2", - tag='', + examples_path: _Union[_Path, str], + bucket: str, + target: str, + dirs: _Union[list, tuple] = ("products", "data", "loading", "solutions"), + compression: str = "bz2", + tag: str = "", + show_progress: bool = False, + push_no_tar: bool = False, ): __doc__ = ( "tars selected aux dirs from ginan/examples and compares their checksums with" @@ -139,31 +128,32 @@ def upload_examples_tar( " [html] https://peanpod.s3.ap-southeast-2.amazonaws.com/aux/" ) base_url = f"https://{bucket}.s3.ap-southeast-2.amazonaws.com/{target}" - for dir in dirs: + for directory in dirs: # update tarname with tag - example_type = get_example_type(dir) + example_type = get_example_type(directory) if example_type: - dir = "solutions/" + (f"{tag}/" if tag != '' else '') + dir - tarname = dir + ".tar." + compression + directory = "solutions/" + (f"{tag}/" if tag != "" else "") + directory + tarname = directory + ".tar." + compression destpath_targz = examples_path / tarname dest_url = base_url + "/" + tarname - tar_comp( - srcpath=examples_path / dir, - destpath=destpath_targz, - reset_info=True, - compression=compression, - ) # always overwrite - md5_checksum_aws = request_checksum(dest_url) - md5_checksum = compute_checksum(destpath_targz) + if not push_no_tar: + ga.gn_io.common.tar_comp( + srcpath=examples_path / directory, + destpath=destpath_targz, + reset_info=example_type, # reset timestamp etc for examples only + compression=compression, + ) # overwrite only if push_no_tar is False (default) + md5_checksum_aws = ga.gn_download.request_metadata(dest_url) + md5_checksum = ga.gn_io.common.compute_checksum(destpath_targz) if md5_checksum_aws != md5_checksum: _logging.info(f'checksums different -> uploading "{tarname}"') - upload_with_chunksize_and_meta( + ga.gn_download.upload_with_chunksize_and_meta( local_file_path=destpath_targz, metadata={"md5checksum": md5_checksum}, public_read=True, bucket_name=bucket, object_key=target + "/" + tarname, - verbose=True, + verbose=show_progress, ) else: _logging.info(f"checksums the same -> skipping upload") @@ -171,14 +161,14 @@ def upload_examples_tar( def download_examples_tar( - examples_path, - bucket, - target, - dirs=("products", "data", "solutions"), - compression="bz2", - tag='', - skip_extract=False, - tags_file_path = None # fall back on tags file if no tag was provided + examples_path: _Union[_Path, str], + bucket: str, + target: str, + dirs: _Union[list, tuple] = ("products", "data", "solutions", "loading"), + compression: str = "bz2", + tag: str = "", + skip_extract: bool = False, + tags_file_path: _Union[str, None] = None, # fall back on tags file if no tag was provided ): __doc__ = ( "Downloads compressed selected tarballs from ap-southeast-2 s3 bucket, untars" @@ -188,101 +178,135 @@ def download_examples_tar( ) base_url = f"https://{bucket}.s3.ap-southeast-2.amazonaws.com/{target}" - if tag == '' and tags_file_path is not None: - _logging.info(f'reading tags from {tags_file_path}') - tag = get_vars_from_file(tags_file_path) - tag = {'POD':tag.POD, 'PEA':tag.PEA} + if tag == "": + if tags_file_path is None: + raise ValueError("tag not provided and tags_file_path not provided") + _logging.info(f"reading tags from {tags_file_path}") + tag = ga.gn_download.get_vars_from_file(tags_file_path) else: - _logging.info(f'using the provided {tag} tag') - tag = {'POD':tag, 'PEA':tag} - for dir in dirs: - example_type = get_example_type(dir) + _logging.info(f"using the provided {tag} tag") + + for directory in dirs: + example_type = get_example_type(directory) if example_type: - dir_url = f"solutions/{(f'{tag[example_type]}/{dir}' if tag != '' else dir)}.tar.{compression}" - dir = f"solutions/{dir}.tar.{compression}" + dir_url = f"solutions/{(f'{tag[example_type]}/{directory}' if isinstance(tag,dict) else f'{tag}/{directory}')}.tar.{compression}" + directory = f"solutions/{directory}.tar.{compression}" else: - dir = dir_url = f"{dir}.tar.{compression}" + directory = dir_url = f"{directory}.tar.{compression}" - destpath_targz = examples_path / dir + destpath_targz = examples_path / directory dest_url = base_url + "/" + dir_url - md5_checksum_aws = request_checksum(dest_url) - if md5_checksum_aws is None: - raise FileNotFoundError - destpath = examples_path / dir + md5_checksum_aws = ga.gn_download.request_metadata(dest_url) + destpath = examples_path / directory if not destpath_targz.exists(): - _logging.warning(msg=f"{dir} not found on disk ['{md5_checksum_aws}'].") + _logging.info(msg=f"{directory} not found on disk ['{md5_checksum_aws}'].") destpath_targz.parent.mkdir(parents=True, exist_ok=True) - download_url(url=dest_url, destfile=destpath_targz) - tar_extr(srcpath=destpath_targz, destpath=destpath) + ga.gn_download.download_url(url=dest_url, destfile=destpath_targz) else: - _logging.info(msg=f"{dir} found on disk. Validating...") - md5_checksum = compute_checksum(destpath_targz) + _logging.info(msg=f"{directory} found on disk. Validating...") + md5_checksum = ga.gn_io.common.compute_checksum(destpath_targz) if md5_checksum_aws != md5_checksum: _logging.info(f'checksums different -> downloading "{dir_url}"') - download_url(url=dest_url, destfile=destpath_targz) - tar_extr(srcpath=destpath_targz, destpath=destpath) + ga.gn_download.download_url(url=dest_url, destfile=destpath_targz) else: _logging.info(f"checksums the same -> skipping download") - if skip_extract and destpath.exists(): - _logging.info( - "skipping extraction step as '--skip_extract' provided," - " checksums the same and destination directory exists" - ) - else: - tar_extr(srcpath=destpath_targz, destpath=destpath) + if skip_extract and destpath.exists(): + _logging.info( + "skipping extraction step as '--skip_extract' provided, checksums the same and destination directory exists" + ) + else: + ga.gn_io.common.tar_extr(srcpath=destpath_targz, destpath=destpath) -if __name__ == "__main__": - parsed_args = parse_arguments() + +@_click.command() +@_click.argument("dirs", nargs=-1, type=str) +@_click.option("--bucket", default="peanpod", help="s3 bucket name to push and pull from") +@_click.option("--target", default="aux", help="s3 target name (dir) within the selected bucket") +@_click.option( + "--path", + default=None, + help="custom path to examples dir, a dir that stores products/data etc, default is ginan/examples", +) +@_click.option("--tag", type=str, default="") +@_click.option( + "--skip_extract", + is_flag=True, + show_default=True, + default=False, + help=( + """Skips extraction of the on-disk tar file if checksum test is OK and the + destination dir exists. This is done to save time in the pipeline as + there is no need to overwrite the files.""" + ), +) +@_click.option("-s", "--solutions", is_flag=True, help="download/upload solutions only") +@_click.option("-d", "--data", is_flag=True, help="download/upload data only") +@_click.option("-p", "--products", is_flag=True, help="download/upload products only") +@_click.option("-l", "--loading", is_flag=True, help="download/upload loadings only") +@_click.option("--push", is_flag=True, help="tar dirs and push them to aws with checksum metadata and public read") +@_click.option("--push_no_tar", is_flag=True, help="push tar archive which is present on disk") +def download_examples(dirs, bucket, target, path, tag, skip_extract, solutions, data, products, loading, push, push_no_tar): + """Downloads 'products', 'data', and 'solutions' tarballs from s3 bucket and + extracts the content into examples dir. The list of tarballs can be + changed with the combination of [-p/-d/-s] options. Similar tarballs + upload functionality is available - can be activated with '--push' key + To configure the utility for --push functionality it is enough to create + ~/.aws/credentials file containing + [default] / aws_access_key_id=ACCESS_KEY / + aws_secret_access_key=SECRET_KEY""" _logging.getLogger().setLevel(_logging.INFO) script_path = _Path(__file__).resolve().parent - if parsed_args.path is None: + if path is None: examples_path = (script_path.parent / "examples").resolve() _logging.info(f"default path relative to script location selected: {examples_path}") else: - examples_path = _Path(parsed_args.path) + examples_path = _Path(path) _logging.info(f"custom path selected: {examples_path}") - if parsed_args.dirs != []: - dirs = parsed_args.dirs - else: - dirs = [] - examples_dirs = list(EX_GLOB_DICT.keys()) - if parsed_args.products: - dirs.append("products") - if parsed_args.data: - dirs.append("data") - if parsed_args.solutions: - dirs += examples_dirs - if dirs == []: - dirs = ["products", "data", *examples_dirs] - _logging.info(f"{dirs} selected") - if parsed_args.push: + if not dirs: + if products: + dirs += ("products",) + if loading: + dirs += ("loading",) + if data: + dirs += ("data",) + if solutions: + dirs += tuple(EX_GLOB_DICT.keys()) + if not dirs: # if nothing has been selected + dirs = ("products", "data") + tuple(EX_GLOB_DICT.keys()) + _logging.info(f"{dirs} selected") + + if push or push_no_tar: # copy over the required files if exist - if solutions/blah -> rm blah, copy from ../blah to solutions/blah _logging.info(msg="updating solutions") [ - update_solutions_dict( - examples_dir=examples_path, dir=dir, ex_glob_dict=EX_GLOB_DICT,tag=parsed_args.tag - ) - for dir in dirs + update_solutions_dict(examples_dir=examples_path, directory=directory, ex_glob_dict=EX_GLOB_DICT, tag=tag) + for directory in dirs ] upload_examples_tar( dirs=dirs, compression="bz2", - tag=parsed_args.tag, + tag=tag, examples_path=examples_path, - bucket=parsed_args.bucket, - target=parsed_args.target + bucket=bucket, + target=target, + show_progress=False, + push_no_tar=push_no_tar, ) else: download_examples_tar( dirs=dirs, compression="bz2", - tag=parsed_args.tag, + tag=tag, examples_path=examples_path, - skip_extract=parsed_args.skip_extract, - bucket=parsed_args.bucket, - target=parsed_args.target, - tags_file_path=(script_path.parent / "docker" / "tags").as_posix() + skip_extract=skip_extract, + bucket=bucket, + target=target, + tags_file_path=(script_path.parent / "docker" / "tags").as_posix(), ) + + +if __name__ == "__main__": + download_examples() diff --git a/scripts/download_slr_data.py b/scripts/download_slr_data.py new file mode 100755 index 000000000..af0ec95ef --- /dev/null +++ b/scripts/download_slr_data.py @@ -0,0 +1,100 @@ +#!/usr/bin/python3 +# Requires bs4 ($ pip install bs4) +# Requires a ~/.netrc file containing "machine urs.earthdata.nasa.gov login password " with a login from https://cddis.nasa.gov/archive/slr/products + +import requests +from bs4 import BeautifulSoup +import gzip +import shutil +import os +import re + +write_loc = "../examples/slr/downloaded" + +data_url = "https://cddis.nasa.gov/archive/slr/data/npt_crd" +orbits_url = "https://cddis.nasa.gov/archive/slr/products/orbits" +satellite = "lageos1" + +satellite = input("Input the name of the satellite (e.g. lageos1): ") + +print("Downloading crd/npt files") +for j in range (2008, 2021): + year = str(j) + for i in range(1, 13): + if i < 10: + file_date = year + "0" + str(i) + else: + file_date = year + str(i); + + file_name = f"{satellite}_{file_date}.npt" + url = f"{data_url}/{satellite}/{year}/{file_name}" + r = requests.get(url) + + if not r.ok: + continue + + os.makedirs(f"{write_loc}/data/{satellite}/{year}", exist_ok=True) + with open((f"{write_loc}/data/{satellite}/{year}/{file_name}"), 'wb') as fp: + print("Downloading: " + file_name) + for chunk in r.iter_content(chunk_size=1000): + fp.write(chunk) + +print("Downloading orbit data") + +orbits_url = f"{orbits_url}/{satellite}" + +r = requests.get(orbits_url) + +if not r.ok: + print("Satellite sp3 files not available.") + exit() + +flag = True +base_soup = BeautifulSoup(r.content, "html.parser") +num_directories = base_soup.find_all("a", class_="archiveDirText") +for d in num_directories: + dir_name = d.text + dir_r = requests.get(f"{orbits_url}/{dir_name}") + + file_soup = BeautifulSoup(dir_r.content, "html.parser") + files = file_soup.find_all("a", class_="archiveItemText") + for f in files: + f_name = f.text + match = re.match(f"ilrsa.orb.{satellite}.{dir_name}.v(\d+).sp3.gz", f.text) + + if (bool(match)): + print(f"Downloading: {f.text}") + flag = False + file_r = requests.get(f"{orbits_url}/{dir_name}/{f.text}") + file_path = f"{write_loc}/products/orbits/{satellite}/{f.text}" + os.makedirs(f"{write_loc}/products/orbits/{satellite}", exist_ok=True) + with open(file_path, "wb") as fp: + for chunk in file_r.iter_content(chunk_size=1000): + fp.write(chunk) + with gzip.open(file_path) as f_in: + with open(file_path[:-3], "wb") as f_out: + shutil.copyfileobj(f_in, f_out) + os.remove(file_path) + if flag: + for f in files: + f_name = f.text + match = re.match(f"([a-z]+).orb.{satellite}.{dir_name}.v(\d+).sp3.gz", f.text) + + if (bool(match)): + print(f"Downloading: {f.text}") + file_r = requests.get(f"{orbits_url}/{dir_name}/{f.text}") + os.makedirs(f"{write_loc}/products/orbits/{satellite}", exist_ok=True) + file_path = f"{write_loc}/products/orbits/{satellite}/{f.text}" + with open(file_path, "wb") as fp: + for chunk in file_r.iter_content(chunk_size=1000): + fp.write(chunk) + with gzip.open(file_path) as f_in: + with open(file_path[:-3], "wb") as f_out: + shutil.copyfileobj(f_in, f_out) + os.remove(file_path) + + break + + + +print("All downloads complete") \ No newline at end of file diff --git a/scripts/gn_lib/__init__.py b/scripts/gn_lib/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/scripts/gn_lib/gn_aux.py b/scripts/gn_lib/gn_aux.py deleted file mode 100644 index 1395d2aac..000000000 --- a/scripts/gn_lib/gn_aux.py +++ /dev/null @@ -1,181 +0,0 @@ -'''Auxiliary functions''' -import logging as _logging -from typing import Union as _Union, Tuple as _Tuple - -import numpy as _np -import pandas as _pd - - -def update_mindex(dataframe, lvl_name,loc=0,axis=1): - '''Inserts a level named as lvl_name into dataframe df in loc position. - Level can be inserted either in columns (default axis=1) or index (axis=0)''' - - mindex_df = dataframe.columns if axis == 1 else dataframe.index - mindex_df = mindex_df.to_frame(index=False) - - if loc == -1: - loc = mindex_df.shape[1] #can insert below levels - - mindex_df.insert(loc = loc,column = 'add',value = lvl_name) - mindex_df_updated = _pd.MultiIndex.from_arrays(mindex_df.values.T) - - if axis == 1: - dataframe.columns = mindex_df_updated - else: - dataframe.index = mindex_df_updated - return dataframe - -def get_common_index(*dfs,level=None): - index_sets = [set(df.index.values if level is None else df.index.levels[level].values) for df in dfs] - return set.intersection(*index_sets) - -def sync_snx_sites(*dfs): - '''Finds common sites present in all gathers and outputs - a list of gathers with common sites only''' - sites = get_common_index(*dfs,level=0) - # index.remove_unused_levels() may be required - return [snx_df.loc[sites] for snx_df in dfs] - -def code_pt_comboindex(vec): - '''returns combo index as CODE + PT''' - tmp_index = vec.index - site_code = tmp_index.droplevel([1,2]) - site_pt = tmp_index.droplevel([0,1]) - return _pd.Index(site_code.values + site_pt.values.astype(object)) - -def sync_pt_vec(vec1,vec2): - '''returns sinex vectors synced on the common site name - and takes care of PT monument type''' - cindex1 = code_pt_comboindex(vec1) - cindex2 = code_pt_comboindex(vec2) - return vec1[cindex1.isin(cindex2)],vec2[cindex2.isin(cindex1)] - -def unique_cols(df:_pd.DataFrame)->_np.ndarray: - '''returns True for a df row with all duplicates''' - a = df.to_numpy() # df.values (pandas<0.24) - return (a[:,0][:,None] == a).all(1) - -def rm_duplicates_df(df=_Union[_pd.DataFrame,_pd.Series],rm_nan_level:_Union[int,str,None]=None): - """ - Takes in a clk/sp3/other dataframe and removes any duplicate indices. - Optionally, removes level_values from the index which contain NaNs - (useful for sp3 dataframes that need to be transformed to RAC). - TODO Expand to level being a list - - Parameters - ---------- - df: DataFrame or Series - Requires at least 2-level MultiIndex - remove_nan_levels : int or None, default None - Switch to enable the removal of level keys with NaNs, any int or str is treated as a level to unstack and search for missing (NaN) values - """ - if df.index.duplicated().sum() > 0: - df = df[~df.index.duplicated()] - - if rm_nan_level is not None: - attrs = df.attrs - df_unstacked = df.unstack(level=rm_nan_level) # previous step insures successful unstacking - cols2check = df_unstacked.columns.get_level_values(-1) # -1 is the recently unstacked level - - nan_mask = ~df_unstacked.set_axis(cols2check,axis=1).isna().sum(axis=0).sum(level=0).astype(bool) - # if multiple cols with same name are present - sum(level=0) will group by same name - - if (~nan_mask).sum() != 0: - sv_complete = nan_mask.index.values[nan_mask.values] - _logging.warning(f'removed {nan_mask.index.values[~nan_mask.values]} as incomplete') - df = df_unstacked.loc(axis=1)[:,:,sv_complete].stack(-1) - df.attrs = attrs # copy over attrs which get lost in stack/unstack - df.index = df.index.remove_unused_levels() # removed levels are still present in the index so remove - - return df - -def sync_idx_dfs(df_a:_pd.DataFrame,df_b:_pd.DataFrame): - """Finds common index between the two dataframes and returns filtered dataframes""" - if not df_a.index.is_monotonic_increasing: df_a = df_a.sort_index(axis=0,inplace=False) - if not df_b.index.is_monotonic_increasing: df_b = df_b.sort_index(axis=0,inplace=False) - idx_a, idx_b = df_a.index, df_b.index - - n_levels = len(idx_a.levels) - idx_levels = list(range(n_levels)) - - mask_a, mask_b = [], [] - - for i in range(n_levels): - level_intersect = idx_a.levels[i].intersection(idx_b.levels[i]) - if len(level_intersect) == 0: - raise RuntimeError(f"no common idx for level {i}") - - removed = idx_levels.pop(i) # pop the index that is assessed, so could use droplevel which is more efficient than get_level_values(i) - - mask_a.append(idx_a.droplevel(idx_levels).isin(level_intersect)) - mask_b.append(idx_b.droplevel(idx_levels).isin(level_intersect)) - - idx_levels.insert(removed,i) - - df_a, df_b = df_a[_np.all(mask_a,axis=0)], df_b[_np.all(mask_b,axis=0)] - df_a.index = df_b.index = df_a.index.remove_unused_levels() # sp3a.index equals sp3b.index at this point - return df_a, df_b - -def get_sampling(arr:_np.ndarray)->_Union[int,None]: - """ - Simple function to compute sampling of the J2000 array - - Parameters - ---------- - arr : ndarray of J2000 values - returns a median of all the dt values which is a sampling. Checks if this value is close to integer seconds and returns None if not. - """ - median_dt = _np.median(arr[1:] - arr[:-1]) - return int(median_dt) if (median_dt % 1) == 0 else None - -def array_equal_unordered(a1:_np.ndarray,a2:_np.ndarray)->bool: - """ - True if two arrays have the same shape and elements, False otherwise. Elements can be in any order within the two arrays. - Use only for relatively small arrays as function uses lists sorting. - - Parameters - ---------- - a1, a2 : array_like - Input arrays. - - Returns - ------- - b : bool - Returns True if the arrays are equal. - """ - if a1.shape == a2.shape: - return sorted(a1.tolist()) == sorted(a2.tolist()) - else: - _logging.debug( - msg=f"array_equal_unordered:{a1.shape} and {a2.shape} shapes are different") - return False - - -def rms(arr: _Union[_pd.DataFrame, _pd.Series], axis: _Union[None, int] = 0, level: _Union[None, int] = None)->_Union[_pd.Series,_pd.DataFrame]: - """Trivial function to compute root mean square""" - return (arr**2).mean(axis=axis, level=level)**0.5 - - -def get_std_bounds(a: _np.ndarray, axis: _Union[None,int,_Tuple[int, ...]] = None, sigma_coeff: int = 3): - """ - Returns the bounds across the the flattened array of along the specified axis/axes. - Adds a dimension to if axis is provided for convenience in case a was originally a - pandas DataFrame which could be then filtered using directly the returned bounds. - - Parameters - ---------- - a : array_like - Input array. - axis : None or int, optional - Axis or axes along which to compute the bounds. The default is to - compute bounds over the flattened array. - sigma_coeff : int - Coefficient to multiply the computed sigma - - Returns - ------- - bounds : array_like or scalar - Returns array or single value of the absolute bound (mean + sigma_coeff*sigma) to be used for filtering. - """ - bounds = _np.nanmean(a=a,axis=axis) + sigma_coeff*_np.nanstd(a=a,axis=axis) - return bounds if axis is None else _np.expand_dims(a=bounds,axis=axis) \ No newline at end of file diff --git a/scripts/gn_lib/gn_combi.py b/scripts/gn_lib/gn_combi.py deleted file mode 100644 index ad194ecab..000000000 --- a/scripts/gn_lib/gn_combi.py +++ /dev/null @@ -1,202 +0,0 @@ -import numpy as _np -import pandas as _pd -import logging as _logging - -# from .gn_io.sinex import _get_snx_matrix, _get_snx_vector, get_variance_factor -from gn_lib import gn_io as _gn_io -from gn_lib import gn_transform as _gn_transform - -def cova2neq(cova:_np.ndarray, variance_factor): - """Function to convert COVA matrix to NEQ matrix as per Bernese ADDNEQ""" - neqm = _np.linalg.inv(cova / variance_factor) - # neqv = neqm @ (vec.EST.values - vec.APR.values) - # return neqm, neqv - return neqm - -def corr2cova(corr:_np.ndarray) -> _np.ndarray: - """Converts sinex CORR matrix to COVA using the diagonal STD values""" - D = corr.diagonal() * corr.diagonal()[:,None] - _np.fill_diagonal(corr,1) # fill COVA diagonal with 1 so we only multiply with D to get COVA - return corr * D - - -def get_neq(path_or_bytes): - snx_bytes = _gn_io.common.path2bytes(path_or_bytes) - # TODO read and parse sinex header - - neq = _gn_io.sinex._get_snx_matrix(path_or_bytes=snx_bytes, stypes=["NEQ"], verbose=False) - - vec = b"" # to silence the pylance - if neq is not None: - vec = _gn_io.sinex._get_snx_vector( - path_or_bytes=snx_bytes, stypes=["APR", "EST", "NEQ"], verbose=False,snx_format=None - ) - # revisit this vec thing - return neq[0][0], vec # NEQ matrix and vector are present so just return - # return N and N_vec if they exist, else -> magic - _logging.warning( - msg="No NEQ was found. Generating from COVA/CORR as not strict" - ) - - apr_est = _gn_io.sinex._get_snx_matrix(path_or_bytes=snx_bytes, stypes=["APR", "EST"], verbose=False) - - if apr_est is not None: - matrices, stype_dict = apr_est - else: - raise ValueError - - variance_factor = _gn_io.sinex.get_variance_factor(path_or_bytes) - - if variance_factor is None: - variance_factor = 1 - _logging.warning( - msg="No variance factor found. Considering it 1" - ) - - a_e = _gn_io.sinex._get_snx_vector(path_or_bytes = snx_bytes, stypes=["EST", "APR"], verbose=False,snx_format=None) - if a_e is None: - raise ValueError - - if not 'APR' in stype_dict.keys(): - std = a_e.STD.values - mat_apr = _np.identity(std.shape[0]) - _np.fill_diagonal(mat_apr,std*std) - neq_apr = cova2neq(mat_apr,variance_factor) - else: - if stype_dict['APR'] == 'CORR': - neq_apr = cova2neq(corr2cova(matrices[list(stype_dict.keys()).index('APR')]),variance_factor=variance_factor) - elif stype_dict['APR'] == 'COVA': # K_constr - neq_apr = cova2neq(matrices[list(stype_dict.keys()).index('APR')],variance_factor=variance_factor) - elif stype_dict['APR'] == 'INFO': # N_constr - neq_apr = matrices[list(stype_dict.keys()).index('APR')] - else: - raise ValueError - - if stype_dict['EST'] == 'CORR': - neq_est = cova2neq(corr2cova(matrices[list(stype_dict.keys()).index('EST')]),variance_factor=variance_factor) - elif stype_dict['EST'] == 'COVA': # K_xx - print('cova2neq') - neq_est = cova2neq(corr2cova(matrices[list(stype_dict.keys()).index('EST')]),variance_factor=variance_factor) - elif stype_dict['EST'] == 'INFO': # N_total - neq_est = matrices[list(stype_dict.keys()).index('EST')] - else: - raise ValueError - - neq = neq_est - neq_apr # N_total - N_constr - - neqv = neq @ (a_e.EST.values - a_e.APR.values) # (a.APR + _np.linalg.solve(a=neqm,b=neqv)) - a.EST # to check - a_e['NEQ'] = neqv - return neq, a_e - -def neq_elim_dim(neq_mat: _np.ndarray, neq_vec: _np.ndarray, i: int): - """Eliminates 'i' dimension in NEQ system""" - elim_row = neq_mat[i][_np.newaxis] - elim_col = neq_mat[:, i] - elim_centr = elim_col[i] - neq_mat -= ( - elim_row * (elim_col / elim_centr)[:, _np.newaxis] - ) # division done on 1dim vector first - neq_vec -= elim_col * neq_vec[i] / elim_centr - - -def prepare_neq(neq_m, vec_apr_neq, frame_of_day): - """Eliminate the non-XYZ parameters from the NEQ system and align a priori XYZ values to the frame of choice if frame_of_day is given""" - neq_mat = neq_m.copy() - vec_apr_neq = vec_apr_neq.copy() - neq_vec = vec_apr_neq.NEQ.values - xyz_mask = _np.isin(vec_apr_neq.TYPE.values, ["STAX", "STAY", "STAZ"]) - idx2elim = vec_apr_neq.index.values[~xyz_mask] - - # neq_mat,neq_vec = neq, neq_vec - for i in range( - idx2elim.shape[0] - ): # need to be positive and sorted from bigger to smaller - neq_elim_dim(neq_mat, neq_vec, idx2elim[i]) - - neq_mat_elim = neq_mat[xyz_mask, :][:, xyz_mask] - neq_vec_elim = neq_vec[xyz_mask] - vec_apr_neq = vec_apr_neq[xyz_mask] - - aprioris = vec_apr_neq.APR - index_combo = _pd.MultiIndex.from_arrays( - [vec_apr_neq.CODE.values + "_" + vec_apr_neq.PT.values.astype(str), vec_apr_neq.TYPE] - ) - aprioris.index = index_combo - aprioris = aprioris.unstack(level=1) - aprioris_missing_mask = aprioris.STAX.values == 0 - aprioris_vals_mask = ~aprioris_missing_mask - - if aprioris_missing_mask.sum() > 0: - estimates = vec_apr_neq.EST - estimates.index = index_combo - aprioris[aprioris_missing_mask] += estimates.unstack(level=1).values[aprioris_missing_mask] - - if frame_of_day is not None: - common = _np.intersect1d(aprioris[aprioris_vals_mask].index.values, frame_of_day.index.values) - hlm = _gn_transform.get_helmert7(pt1=frame_of_day.loc[common].iloc[:, :3].values, pt2=aprioris[aprioris_vals_mask].loc[common].values) # could not work if the order of XYZ is changed to YXZ etc - # copy over estimate values to 0-aprioris here and rotate them using the computed hlm coeff - new_aprioris = _pd.DataFrame(data = _gn_transform.transform7(xyz_in=aprioris.values, helmert_list=hlm[0][0] * -1), - index = aprioris.index, columns = aprioris.columns) - else: - new_aprioris = aprioris # we later use substr with a mask and fill_value 0 to make all masked values 0 - - d_apr = new_aprioris.subtract(aprioris[aprioris_vals_mask],fill_value=0).stack()[index_combo].values # the aprioris index is sorted, so need to align with original index - - neq_vec_elim -= neq_mat_elim @ d_apr - vec_apr_neq[["APR", "NEQ"]] = _np.vstack([new_aprioris.stack()[index_combo].values, neq_vec_elim]).T # index_combo is needed to preserve the order that may have been changed by stack() - return neq_mat_elim, vec_apr_neq - - -def insert_neq(master_neq, master_vec_neq, ind, neq, neq_vec): - - bool_arr = _np.zeros(shape=master_neq.shape[0], dtype=bool) - bool_arr[ind] = 1 - mask = bool_arr[_np.newaxis] * bool_arr[:, _np.newaxis] - master_neq[mask] += neq.flatten() # check the flatten order. Could change to +=1 - master_vec_neq[ - bool_arr - ] += neq_vec # Could chage to +=1 for number of solutions plot - - -def vec2comboind(vec): - return vec.CODE.values + vec.PT.values + vec.TYPE.values.astype(str) - - -def get_uniind(vec_list): - buf = [] - for vec in vec_list: - buf.append( - vec.set_index( - vec.CODE.values + vec.PT.values.astype(str) + vec.TYPE.values.astype(str) - ).APR - ) - combo_uni = ( - _pd.concat(buf, axis=1).groupby(level=0, axis=1).mean() - ) # need to specify level to stay in df - combo_uni["IND"] = _np.arange(combo_uni.shape[0]) # for further stacking - return combo_uni, buf - - -def addneq(snx_filelist, frame_of_day): - buf_neq, buf_vec = [], [] - for file in snx_filelist: - neq, vec = get_neq(file) - neq, vec = prepare_neq(neq, vec, frame_of_day) - buf_neq.append(neq) - buf_vec.append(vec) - - combo_uni, combo_list = get_uniind(buf_vec) - arr = _np.zeros(shape=(combo_uni.shape[0], combo_uni.shape[0])) - arr_vec = _np.zeros(shape=(combo_uni.shape[0])) - - for i in range(len(combo_list)): - insert_neq( - master_neq=arr, - master_vec_neq=arr_vec, - ind=combo_uni.IND.loc[combo_list[i].index].values, - neq=buf_neq[i], - neq_vec=buf_vec[i].NEQ.values, - ) - - # return combo_uni,arr,arr_vec - return combo_uni.APR + _np.linalg.lstsq(arr, arr_vec, rcond=None)[0] diff --git a/scripts/gn_lib/gn_const.py b/scripts/gn_lib/gn_const.py deleted file mode 100644 index bf7e94344..000000000 --- a/scripts/gn_lib/gn_const.py +++ /dev/null @@ -1,96 +0,0 @@ -'''Constants to be declared here''' -from numpy import datetime64 as _datetime64 -from pandas import CategoricalDtype as _CategoricalDtype, DataFrame as _DataFrame - -MJD_ORIGIN = _datetime64('1858-11-17 00:00:00') -GPS_ORIGIN = _datetime64('1980-01-06 00:00:00') -J2000_ORIGIN = _datetime64('2000-01-01 12:00:00') - -SEC_IN_WEEK = 604800 -SEC_IN_DAY = 86400 -SEC_IN_YEAR = 31557600 - -C_LIGHT = 299792458.0 # speed of light (m/s) -OMEGA_E = 7.2921151467E-5 # rad/sec WGS84 value of earth's rotation rate - -# https://www.iers.org/SharedDocs/Publikationen/EN/IERS/Documents/ac/sinex/sinex_v201_appendix1_pdf.pdf -TYPE_CATEGORY = object # tmp fix to get rid of Categorical in the future -# TYPE_CATEGORY = _CategoricalDtype(categories = [ -# 'STAX','STAY','STAZ','VELX','VELY','VELZ','XGC','YGC','ZGC','RS_RA','RS_DE','RS_RAR', -# 'RS_DER','RS_PL','LOD','UT','XPO','YPO','XPOR','YPOR','NUT_LN','NUT_OB','NUTRLN','NUTROB', -# 'SAT__X','SAT__Y','SAT__Z','SAT_VX','SAT_VY','SAT_VZ','SAT_RP','SAT_GX','SAT_GZ','SATYBI', -# 'TROTOT','TRODRY','TROWET','TGNTOT','TGNWET','TGNDRY','TGETOT','TGEWET','TGEDRY','RBIAS', -# 'TBIAS','SBIAS','ZBIAS','AXI_OF','SATA_Z','SATA_X','SATA_Y', -# 'ALOG_E','TLOG_E','ALOG_N','TLOG_N','ALOG_H','TLOG_H', -# 'AEXP_E','TEXP_E','AEXP_N','TEXP_N','AEXP_H','TEXP_H']) - -TECHNIQUE_CATEGORY = _CategoricalDtype(categories = ['C','D','L','M','P','R']) - -UNIT_CATEGORY = _CategoricalDtype(categories = ['m','m/y','m/s2','ppb','ms','msd2', - 'mas','ma/d','rad','rd/y','rd/d']) - -PT_CATEGORY = _CategoricalDtype(categories = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']) - -PRN_CATEGORY = _CategoricalDtype(categories = [ - 'G01', 'G02', 'G03', 'G04', 'G05', 'G06', 'G07', 'G08', 'G09', - 'G10', 'G11', 'G12', 'G13', 'G14', 'G15', 'G16', 'G17', 'G18', - 'G19', 'G20', 'G21', 'G22', 'G23', 'G24', 'G25', 'G26', 'G27', - 'G28', 'G29', 'G30', 'G31', 'G32', 'G33', 'G34', 'G35', 'G36', - 'R01', 'R02', 'R03', 'R04', 'R05', 'R06', 'R07', 'R08', 'R09', - 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'R16', 'R17', 'R18', - 'R19', 'R20', 'R21', 'R22', 'R23', 'R24', - 'E01', 'E02', 'E03', 'E04', 'E05', 'E06', 'E07', 'E08', 'E09', - 'E10', 'E11', 'E12', 'E13', 'E14', 'E15', 'E16', 'E17', 'E18', - 'E19', 'E20', 'E21', 'E22', 'E23', 'E24', 'E25', 'E26', 'E27', - 'E28', 'E29', 'E30', 'E31', 'E32', 'E33', 'E34', 'E35', 'E36', - 'C01', 'C02', 'C03', 'C04', 'C05', 'C06', 'C07', 'C08', 'C09', - 'C10', 'C11', 'C12', 'C13', 'C14', 'C15', 'C16', 'C17', 'C18', - 'C19', 'C20', 'C21', 'C22', 'C23', 'C24', 'C25', 'C26', 'C27', - 'C28', 'C29', 'C30', 'C31', 'C32', 'C33', 'C34', 'C35', 'C36', - 'C37', 'C38', 'C39', 'C40', 'C41', 'C42', 'C43', 'C44', 'C45', - 'C46', - 'C57', 'C58', 'C59', 'C60', 'C61']) - -CLK_TYPE_CATEGORY = _CategoricalDtype(categories=['CR','DR','AR','AS','MS']) - -STATE_TYPES_CATEGORY = _CategoricalDtype(categories =[ - 'PHASE_BIAS', 'REC_POS', 'REC_CLOCK', 'REC_SYS_BIAS', 'TROP', 'TROP_GM', 'SAT_CLOCK', 'AMBIGUITY','EOP','EOP_RATE','DCB','IONOSPHERIC']) # 'ONE' removed - -#GeodePy -class Ellipsoid: - __doc__ = 'ellipsoid class doc placeholder' - def __init__(self, semimaj, inversef): - self.semimaj = float(semimaj) # a - self.semimajsq = semimaj * semimaj # a**2 - self.inversef = inversef # inverse of the first flattening factor - self.flatten = 1 / self.inversef # first flattening factor - self.semimin = self.semimaj * (1 - self.flatten) # b - self.semiminsq = self.semimin * self.semimin # b**2 - self.ecc1sq = self.flatten * (2 - self.flatten) - self.ecc2sq = self.ecc1sq / (1 - self.ecc1sq) -# self.ecc1 = sqrt(self.ecc1sq) -# self.n = float(self.f / (2 - self.f)) -# self.n2 = self.n ** 2 -# self.meanradius = (2 * self.semimaj + self.semimin)/3 - -# Geodetic Reference System 1980 -# www.epsg-registry.org/export.htm?gml=urn:ogc:def:ellipsoid:EPSG::7019 -GRS80 = Ellipsoid(6378137, 298.257222101) - -# World Geodetic System 1984 -# www.epsg-registry.org/export.htm?gml=urn:ogc:def:ellipsoid:EPSG::7030 -WGS84 = Ellipsoid(6378137, 298.257223563) - -# Australian National Spheroid -# www.epsg-registry.org/export.htm?gml=urn:ogc:def:ellipsoid:EPSG::7003 -ANS = Ellipsoid(6378160, 298.25) - -# International (Hayford) 1924 -# www.epsg-registry.org/export.htm?gml=urn:ogc:def:ellipsoid:EPSG::7022 -INTL24 = Ellipsoid(6378388, 297) - -SISRE_COEF_DF = _DataFrame( data = [[0.99, 0.98, 0.98, 0.98, 0.98], - [127, 54, 49, 45, 61 ]], - columns=['C_IGSO','C','G','R','E'], - index = ['alpha','beta']) \ No newline at end of file diff --git a/scripts/gn_lib/gn_datetime.py b/scripts/gn_lib/gn_datetime.py deleted file mode 100644 index a6070b236..000000000 --- a/scripts/gn_lib/gn_datetime.py +++ /dev/null @@ -1,260 +0,0 @@ -'''Base time conversion functions''' -from datetime import datetime as _datetime - -import numpy as _np -import pandas as _pd - -from gn_lib.gn_const import ( - MJD_ORIGIN as _MJD_ORIGIN, - GPS_ORIGIN as _GPS_ORIGIN, - J2000_ORIGIN as _J2000_ORIGIN, - SEC_IN_DAY as _SEC_IN_DAY, - SEC_IN_WEEK as _SEC_IN_WEEK, -) - - -def gpsweekD(yr, doy, wkday_suff=False): - """ - Convert year, day-of-year to GPS week format: WWWWD or WWWW - Based on code from Kristine Larson's gps.py - https://github.com/kristinemlarson/gnssIR_python/gps.py - - Input: - yr - year (int) - doy - day-of-year (int) - - Output: - GPS Week in WWWWD format - weeks since 7 Jan 1980 + day of week number (str) - """ - - # Set up the date and time variables - yr = int(yr) - doy = int(doy) - dt = _datetime.strptime(f"{yr}-{doy:03d} 01","%Y-%j %H") - - wkday = dt.weekday() + 1 - - if wkday == 7: - wkday = 0 - - mn, dy, hr = dt.month, dt.day, dt.hour - - if mn <= 2: - yr = yr-1 - mn = mn+12 - - JD = _np.floor(365.25*yr) + _np.floor(30.6001*(mn+1)) + dy + hr/24.0 + 1720981.5 - GPS_wk = _np.int(_np.floor((JD-2444244.5)/7.0)) - - if wkday_suff: - return str(GPS_wk)+str(wkday) - else: - return str(GPS_wk) - - -class GPSDate: - """ - Representation of datetime that provides easy access to - useful properties. - - Usage: - today = GPSDate("today") - tomorrow = today.next - print(f"today year: {today.year}, doy: {today.dy}, GPS week and weekday: {today.gpswkD}") - print(f"tomorrow year: {tomorrow.year}, doy: {tomorrow.dy}, GPS week and weekday: {tomorrow.gpswkD}") - """ - - def __init__(self, ts: _np.datetime64): - if isinstance(ts, str): - ts = _np.datetime64(ts) - - self.ts = ts - - @property - def as_datetime(self): - """Convert to Python `datetime` object.""" - return self.ts.astype(_datetime) - - @property - def yr(self): - """Year""" - return self.as_datetime.strftime("%Y") - - @property - def dy(self): - """Day of year""" - return self.as_datetime.strftime("%j") - - @property - def gpswk(self): - """GPS week""" - return gpsweekD(self.yr, self.dy, wkday_suff=False) - - @property - def gpswkD(self): - """GPS week with weekday suffix""" - return gpsweekD(self.yr, self.dy, wkday_suff=True) - - @property - def next(self): - """The following day""" - return GPSDate(self.ts + 1) - - @property - def prev(self): - """The previous day""" - return GPSDate(self.ts - 1) - - def __str__(self): - """Same string representation as the underlying numpy datetime64 object""" - return str(self.ts) - - -def dt2gpswk(dt,wkday_suff=False,both=False): - ''' - Convert the given datetime object to a GPS week (option to include day suffix) - ''' - yr = dt.strftime('%Y') - doy = dt.strftime('%j') - if not both: - return gpsweekD(yr,doy,wkday_suff=wkday_suff) - else: - return gpsweekD(yr,doy,wkday_suff=False),gpsweekD(yr,doy,wkday_suff=True) - - - -def gpswkD2dt(gpswkD): - ''' - Convert from GPS-Week-Day (WWWWDD) format to datetime object - ''' - if type(gpswkD) != str: - gpswkD = str(gpswkD) - dt_64 = _GPS_ORIGIN + _np.timedelta64(int(gpswkD[:-1]),'W') + _np.timedelta64(int(gpswkD[-1]),'D') - return dt_64.astype(_datetime) - - -def yydoysec2datetime( - snxdate :_np.ndarray or _pd.Series, - recenter:bool=True, - as_j2000:bool=True)->_np.ndarray: - - '''Converts snx YY.DOY.SSSSS object Series to datetime64. - recenter overrirdes day seconds value to midday - as_j2000 outputs int seconds after 2000-01-01 12:00:00, datetime64 otherwise''' - if not isinstance(snxdate,_np.ndarray): - snxdate = snxdate.values #if Series to ndarray - - snxdate = list(_np.char.split(a=snxdate.astype('50) - years = _np.datetime64('2000-01-01').astype('datetime64[Y]') + delta_years - - date = years.astype('datetime64[D]') + (day_of_year - 1) #as years start with day no. 1 - time = _SEC_IN_DAY//2 if recenter else secs_day - datetime = date.astype('datetime64[s]') + time - - if as_j2000: - return datetime2j2000(datetime) - return datetime - - -def datetime2yydoysec(datetime): - '''datetime64[s] -> yydoysecond - NaNs become "" - year 2100 become 00:000:00000''' - nan_mask = _np.isnan(datetime) - datetime_no_nans = datetime[~nan_mask] - date_years = datetime_no_nans.astype('datetime64[Y]') - date_days = datetime_no_nans.astype('datetime64[D]') - doy = _pd.Series((date_days - date_years + 1).astype(int).astype(str)) - seconds = _pd.Series((datetime_no_nans - date_days).astype('timedelta64[s]').astype(int).astype(str)) - yydoysec_no_nans = (_pd.Series(date_years.astype(str)).str.slice(2).values #need U4+1 for [Y] so str - + ':' + doy.str.zfill(3).values - + ':' + seconds.str.zfill(5).values) - yydoysec_no_nans[date_years == _np.datetime64('2100')] = '00:000:00000' - - yydoysec = _np.empty_like(datetime,dtype=object) - yydoysec[~nan_mask] = yydoysec_no_nans - return yydoysec - -def gpsweeksec2datetime(gps_week:_np.ndarray, tow:_np.ndarray, as_j2000:bool=True)->_np.ndarray: - '''trace file date (gps week, time_of_week) to datetime64 conversion''' - ORIGIN = (_GPS_ORIGIN - _J2000_ORIGIN).astype(int) if as_j2000 else _GPS_ORIGIN - datetime = ORIGIN + (gps_week*_SEC_IN_WEEK + tow) - return datetime - - -def datetime2gpsweeksec(array:_np.ndarray, as_decimal = False)->tuple or _np.ndarray: - if array.dtype == int: - ORIGIN = _J2000_ORIGIN.astype(int) - _GPS_ORIGIN.astype(int) - gps_time = (array + ORIGIN) # need int conversion for the case of datetime64 - else: - ORIGIN = _GPS_ORIGIN.astype(int) - gps_time = array.astype('datetime64[s]').astype(int) - ORIGIN #datetime64 converted to int seconds - - weeks_int = (gps_time/_SEC_IN_WEEK).astype(int) - tow = gps_time - weeks_int * _SEC_IN_WEEK # this eliminates rounding error problem - return weeks_int + (tow / 1000000) if as_decimal else (weeks_int, tow) - -def datetime2j2000(datetime:_np.ndarray)->_np.ndarray: - '''datetime64 conversion to int seconds after J2000 (2000-01-01 12:00:00)''' - if not isinstance(datetime,(_np.ndarray,_np.datetime64)): - raise TypeError("input should be numpy ndarray or single datetime64 value") - if datetime.dtype != '_np.ndarray: - '''int64 seconds after J2000 (2000-01-01 12:00:00) conversion to datetime64''' - if j2000secs.dtype == int: - return _J2000_ORIGIN + j2000secs - return _J2000_ORIGIN + j2000secs.astype(int) - -def datetime2mjd(array:_np.ndarray)->tuple: - mjd_seconds = (array - _MJD_ORIGIN).astype(int) # seconds - return mjd_seconds // _SEC_IN_DAY, (mjd_seconds % _SEC_IN_DAY) / _SEC_IN_DAY - -def j20002mjd(array:_np.ndarray)->tuple: - j2000_mjd_bias = (_J2000_ORIGIN - _MJD_ORIGIN).astype(int) # in seconds - mjd_seconds = j2000_mjd_bias + array - return mjd_seconds // _SEC_IN_DAY, (mjd_seconds % _SEC_IN_DAY) / _SEC_IN_DAY - -def j20002j2000days(array:_np.ndarray)->_np.ndarray: - return ((array - _SEC_IN_DAY//2) / _SEC_IN_DAY).astype(int) # SEC_IN_DAY//2 is needed to account for J2000 origin at 12:00 - -def mjd2datetime(mjd:_np.ndarray, seconds_frac:_np.ndarray, pea_partials=False)->_np.ndarray: - seconds = (86400 * seconds_frac).astype(int) if not pea_partials else seconds_frac.astype(int) #pod orb_partials file has a custom mjd date format with frac being seconds - dt = _MJD_ORIGIN + mjd.astype('timedelta64[D]') + seconds - return dt - -def mjd2j2000(mjd:_np.ndarray, seconds_frac:_np.ndarray, pea_partials=False)->_np.ndarray: - datetime = mjd2datetime(mjd=mjd,seconds_frac=seconds_frac,pea_partials=pea_partials) - return datetime2j2000(datetime) - -def j20002rnxdt(j2000secs:_np.ndarray)->_np.ndarray: - ''' - Converts j2000 array to rinex format string representation - 674913600 -> '2021-05-22T00:00:00' -> '* 2021 5 22 0 0 0.00000000\n' - ''' - datetime = j20002datetime(j2000secs) - year = datetime.astype('datetime64[Y]') - month = datetime.astype('datetime64[M]') - day = datetime.astype('datetime64[D]') - hour = datetime.astype('datetime64[h]') - minute = datetime.astype('datetime64[m]') - - date_y = '*' + _pd.Series(year.astype(str)).str.rjust(6).values - date_m = _pd.Series(((month - year).astype(int)+1).astype(str)).str.rjust(3).values - date_d = _pd.Series(((day - month).astype(int) + 1).astype(str)).str.rjust(3).values - - time_h = _pd.Series((hour - day).astype(int).astype(str)).str.rjust(3).values - time_m = _pd.Series((minute - hour).astype(int).astype(str)).str.rjust(3).values - time_s = ((_pd.Series((datetime - minute)).view(int)/1e9) - .apply('{:.8f}\n'.format).str.rjust(13).values) - return date_y + date_m + date_d + time_h + time_m + time_s diff --git a/scripts/gn_lib/gn_diffaux.py b/scripts/gn_lib/gn_diffaux.py deleted file mode 100644 index 3d294afe8..000000000 --- a/scripts/gn_lib/gn_diffaux.py +++ /dev/null @@ -1,454 +0,0 @@ -import logging as _logging -from typing import Union as _Union - -import numpy as _np -import pandas as _pd - -from gn_lib import gn_aux as _gn_aux -from gn_lib import gn_const as _gn_const -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io -from gn_lib import gn_plot as _gn_plot - - -def _valvar2diffstd(valvar1,valvar2,trace=True,std_coeff=1): - """Auxiliary function to efficiently difference two dataframes, - each of them consisting of value-variance pairs""" - df = _pd.concat([valvar1,valvar2],axis=0,keys=['valvar1','valvar2']).unstack(0) #fastest\ - df_nd = df.values - diff = df_nd[:,0] - df_nd[:,1] - nan_mask = ~_np.isnan(diff) - - diff = diff[nan_mask] - std = std_coeff*_np.sqrt((df_nd[:,3] + df_nd[:,2])[nan_mask]) - df_combo = _pd.DataFrame(_np.vstack([diff,std]).T,columns=['DIFF','STD'],index=df.index[nan_mask]) - - if trace: - sats = df.index.get_level_values('SAT') - sats_mask = ~sats.isna() - sats_df = sats[sats_mask].unique() - - df_combo.attrs['SAT_MASK'] = sats_mask[nan_mask] - sats_common = sats[sats_mask & nan_mask]#.unique() - df_combo.attrs['EXTRA_SATS'] = sats_df[~sats_df.isin(sats_common)].to_list() # is [] if none - return df_combo - -def _diff2msg(diff, tol = None, dt_as_gpsweek=False): - _pd.set_option("display.max_colwidth", 10000) - from_valvar = _np.all(_np.isin(['DIFF','STD'],diff.columns.get_level_values(0).values)) - - if from_valvar: #if from_valvar else diff.values - diff_df = diff.DIFF - std_df = diff.STD - std_vals = std_df.values if tol is None else tol - else: - diff_df = diff - if tol is None: - _logging.error(msg="tol can not be None if STD info is missing, skipping for now") - return None - std_vals = tol - - count_total = (~_np.isnan(diff_df.values)).sum(axis=0) - mask2d_over_threshold = _np.abs(diff_df) > std_vals - - diff_count = mask2d_over_threshold.sum(axis=0) - - mask = diff_count.astype(bool) - if mask.sum() == 0: - return None - mask_some_vals = mask[mask.values].index - - diff_over = diff_df[mask2d_over_threshold][mask_some_vals] - idx_max = diff_over.idxmax() - diff_max = _pd.Series(_np.diag(diff_over.loc[idx_max.values].values),index=idx_max.index) - idx_min = diff_over.idxmin() - diff_min = _pd.Series(_np.diag(diff_over.loc[idx_min.values].values),index=idx_min.index) - - if from_valvar: - std_over = std_df[mask2d_over_threshold][mask_some_vals] - std_max = _pd.Series(_np.diag(std_over.loc[idx_max.values].values),index=idx_max.index) - std_min = _pd.Series(_np.diag(std_over.loc[idx_min.values].values),index=idx_min.index) - - msg = _pd.DataFrame() - msg['RATIO'] = (diff_count[mask].astype(str).astype(object) + '/' + count_total[mask].astype(str) - + ('(' + (diff_count[mask]/count_total[mask] * 100).round(2).astype(str)).str.ljust(5,fillchar='0') +'%)') - - msg['DIFF/MIN_DIFF'] = (diff_min.round(4).astype(str) - +('±' + std_min.round(4).astype(str).str.ljust(6,fillchar='0') if from_valvar else '') - +' @' + ( (_gn_datetime.datetime2gpsweeksec(idx_min.values,as_decimal=True)+1E-7).astype('1).sum()>0: - msg['MAX_DIFF'] = (diff_max.round(4).astype(str).str.rjust(7) - +('±' + std_max.round(4).astype(str).str.ljust(6,fillchar='0') if from_valvar else '') - +' @' + ( (_gn_datetime.datetime2gpsweeksec(idx_min.values,as_decimal=True)+1E-7).astype('1) - - msg['MEAN_DIFF'] = (diff_over.mean(axis=0).round(4).astype(str) - +'±' + diff_over.std(axis=0).round(4).astype(str).str.ljust(6,fillchar='0'))* (diff_count[mask]>1) - - return msg - - -def _compare_sv_states(diffstd,log_lvl,tol=None,plot=False): - diff_sv = diffstd[diffstd.attrs['SAT_MASK']].droplevel('NUM',axis=0).unstack(['TYPE','SITE','SAT','BLK']) - if diff_sv.empty: - _logging.warning(msg=f':diffutil SVs states not present. Skipping') - return 0 - if plot: - # a standard scatter plot - _gn_plot.diff2plot(diff_sv.DIFF.PHASE_BIAS) - - # a bar plot of mean values - diffstd_mean = diff_sv.DIFF.PHASE_BIAS.mean(axis=0) - diffstd_mean.index = diffstd_mean.index.to_series().astype(str) - _gn_plot.diff2plot(diffstd_mean,kind='bar') - bad_sv_states = _diff2msg(diff_sv,tol) - if bad_sv_states is not None: - _logging.log(msg=f':diffutil found SV states diffs above {"the extracted STDs" if tol is None else f"{tol:.1E} tolerance"}:\n{bad_sv_states.to_string(justify="center")}\n',level=log_lvl) - return -1 - _logging.log(msg=f':diffutil [OK] SVs states diffs within the {"extracted STDs" if tol is None else f"{tol:.1E} tolerance"}',level=_logging.INFO) - return 0 - -def _compare_nonsv_states(diffstd,log_lvl,tol=None): - diff_nonsv = diffstd[~diffstd.attrs['SAT_MASK']].droplevel('SAT',axis=0).unstack(['TYPE','SITE','NUM','BLK']) - if diff_nonsv.empty: - _logging.warning(msg=f':diffutil non-SVs states not present. Skipping') - return 0 - bad_nonsv_states = _diff2msg(diff_nonsv,tol=tol) - if bad_nonsv_states is not None: - _logging.log(msg=f':diffutil non-SVs states diffs above {"the extracted STDs" if tol is None else f"{tol:.1E} tolerance"}:\n{bad_nonsv_states.to_string(justify="center")}\n',level=log_lvl) - return -1 - _logging.log(msg=f':diffutil [OK] non-SVs states diffs within the {"extracted STDs" if tol is None else f"{tol:.1E} tolerance"}',level=_logging.INFO) - return 0 - -def _compare_sat_postfit_residuals(diffstd,log_lvl,tol=None): - diff_count = diffstd[diffstd.attrs['SAT_MASK']].unstack(['TYPE','SAT','SITE','BLK']) - if diff_count.empty: - _logging.warning(f':diffutil SVs residuals not present. Skipping') - return 0 - bad_sv_residuals = _diff2msg(diff_count,tol=tol) - if bad_sv_residuals is not None: - _logging.log(msg=f':diffutil found SVs residuals diffs above {"the extracted STDs" if tol is None else f"{tol:.1E} tolerance"}:\n{bad_sv_residuals.to_string(justify="center")}\n',level=log_lvl) - return -1 - _logging.log(msg=f':diffutil [OK] SVs residuals diffs within the {"extracted STDs" if tol is None else f"{tol:.1E} tolerance"}',level=_logging.INFO) - return 0 - -def _compare_nonsat_postfit_residuals(diffstd,log_lvl,tol=None): - diff_count = diffstd[~diffstd.attrs['SAT_MASK']] - if diff_count.empty: #no non-sat records found such as Zamb - _logging.warning(f':diffutil non-SVs residuals not present. Skipping') - return 0 - diff_count = diff_count.droplevel('SAT').unstack(['SITE','TYPE','BLK']) - bad_nonsv_residuals = _diff2msg(diff_count,tol=tol) - if bad_nonsv_residuals is not None: - _logging.log(msg=f':diffutil found non-SVs residuals diffs above {"the extracted STDs" if tol is None else f"{tol:.1E} tolerance"}:\n{bad_nonsv_residuals.to_string(justify="center")}\n',level=log_lvl) - return -1 - _logging.log(msg=f':diffutil [OK] non-SVs residuals diffs within the {"extracted STDs" if tol is None else f"{tol:.1E} tolerance"}',level=_logging.INFO) - return 0 - -def _compare_stec(diffstd,log_lvl,tol=None): - stec_diff = diffstd.unstack(level = ('SITE','SAT','LAYER')) - if stec_diff.empty: - _logging.warning(f':diffutil stec states not present. Skipping') - return 0 - bad_sv_states = _diff2msg(stec_diff,tol,dt_as_gpsweek=True) - if bad_sv_states is not None: - _logging.log(msg=f':diffutil found stec states diffs above {"the extracted STDs" if tol is None else f"{tol:.1E} tolerance"}:\n{bad_sv_states.to_string(justify="center")}\n',level=log_lvl) - return -1 - _logging.log(msg=f':diffutil [OK] stec states diffs within the {"extracted STDs" if tol is None else f"{tol:.1E} tolerance"}',level=_logging.INFO) - return 0 - -def difftrace(trace1_path,trace2_path,atol,std_coeff,log_lvl,plot): - '''Compares two trace/sum files''' - trace1 = _gn_io.common.path2bytes(trace1_path) - trace2 = _gn_io.common.path2bytes(trace2_path) - - _logging.log(msg=f':diffutil -----testing trace states-----',level=log_lvl) - states1 = _gn_io.trace._read_trace_states(trace1) - states2 = _gn_io.trace._read_trace_states(trace2) - status = 0 - if (states1 is None) and (states2 is None): - _logging.log(msg=f':diffutil both compared files are missing states data -> OK',level=log_lvl) - elif (states1 is None) or (states2 is None): - status += -1 # don't wait, throw error right away as smth bad happened, errors have been logged - else: - diffstd_states = _valvar2diffstd(states1.iloc[:,:2],states2.iloc[:,:2],std_coeff=std_coeff,trace=True) - if diffstd_states.attrs['EXTRA_SATS'] != []: - _logging.warning(msg=f':diffutil found no counterpart for: {sorted(diffstd_states.attrs["EXTRA_SATS"])}') - status += _compare_sv_states(diffstd_states,tol=atol,log_lvl=log_lvl,plot=plot) - status += _compare_nonsv_states(diffstd_states,tol=atol,log_lvl=log_lvl) - - _logging.log(msg=f':diffutil -----testing trace residuals-----',level=log_lvl) - resids1 = _gn_io.trace._read_trace_residuals(trace1) - resids2 = _gn_io.trace._read_trace_residuals(trace2) - if (resids1 is None) and (resids2 is None): - _logging.log(msg=f':diffutil both compared files are missing residuals data -> OK',level=log_lvl) - elif (resids1 is None) or (resids2 is None): - status += -1 # don't wait, throw error right away as smth bad happened, errors have been logged - else: - diffstd_residuals = _valvar2diffstd(resids1.iloc[:,2:],resids2.iloc[:,2:],std_coeff=std_coeff,trace=True) - status += _compare_sat_postfit_residuals(diffstd_residuals,tol=atol,log_lvl=log_lvl) - status += _compare_nonsat_postfit_residuals(diffstd_residuals,tol=atol,log_lvl=log_lvl) - - return status - -def diffsnx(snx1_path,snx2_path,atol,std_coeff,log_lvl): - '''Compares two sinex files ''' - snx1_df = _gn_io.sinex._get_snx_vector(path_or_bytes=snx1_path,stypes=('EST',),snx_format=True,verbose=True) - snx2_df = _gn_io.sinex._get_snx_vector(path_or_bytes=snx2_path,stypes=('EST',),snx_format=True,verbose=True) - - if (snx1_df is None) or (snx2_df is None): return -1 # don't wait, throw error right away as smth bad happened, errors have been logged - - status = 0 - diff_snx = _valvar2diffstd(snx1_df,snx2_df,trace=False,std_coeff=std_coeff).unstack(['CODE_PT','TYPE']) - assert diff_snx.size != 0, "no corresponding data to compare" - - bad_snx_vals = _diff2msg(diff_snx,tol=atol) - if bad_snx_vals is not None: - _logging.log(msg=f':diffutil found estimates diffs above {"the extracted STDs" if atol is None else f"{atol:.1E} tolerance"}:\n{bad_snx_vals.to_string(justify="center")}\n',level=log_lvl) - status = -1 - else: - _logging.log(msg=f':diffutil [OK] estimates diffs within {"the extracted STDs" if atol is None else f"{atol:.1E} tolerance"}',level=_logging.INFO) - return status - -def diffstec(path1,path2,atol,std_coeff,log_lvl): - '''Compares two stec files ''' - stec1,stec2 = _gn_io.stec.read_stec(path1), _gn_io.stec.read_stec(path2) - status = 0 - diffstd = _valvar2diffstd(stec1,stec2,std_coeff=std_coeff) - status = _compare_stec(diffstd=diffstd,tol=atol,log_lvl=log_lvl) - return status - -def diffionex(ionex1_path,ionex2_path,atol,log_lvl): - '''Compares two ionex files ''' - - ionex1_df = _gn_io.ionex.read_ionex(path_or_bytes=ionex1_path) - ionex2_df = _gn_io.ionex.read_ionex(path_or_bytes=ionex2_path) - - tol = 10**min(ionex1_df.attrs['EXPONENT'],ionex2_df.attrs['EXPONENT']) if atol is None else atol - - status = 0 - diff_ionex = (ionex1_df.unstack(level=('Type','Lat')) - ionex2_df.unstack(level=('Type','Lat'))).swaplevel('Lon','Type',axis=1) # type:ignore output looks cleaner this way - - bad_ionex_vals = _diff2msg(diff_ionex,tol=tol) - if bad_ionex_vals is not None: - _logging.log(msg=f':diffutil found IONEX diffs above {f"10^min(exp1,exp2) = {tol:.1E} tolerance" if atol is None else f"{tol:.1E} tolerance"}:\n{bad_ionex_vals.to_string(justify="center")}\n',level=log_lvl) - status = -1 - else: - _logging.log(msg=f':diffutil [OK] estimates diffs within {f"10^min(exp1,exp2) = {tol:.1E} tolerance" if atol is None else f"{tol:.1E} tolerance"}',level=_logging.INFO) - return status - -def _compare_clk(clk_a:_pd.DataFrame,clk_b:_pd.DataFrame, - norm_type:str='both', - ext_dt :_Union[_np.ndarray,_pd.Index,None]=None, - ext_svs:_Union[_np.ndarray,_pd.Index,None]=None)->_pd.DataFrame: - """ - clk DataFrames are the output of read_clk. sp3_a and sp3_b are the - DataFrames produced by read_sp3 function. Outputs a DataFrame of - signal-in-space range error (SISRE). The SISRE units are meters - """ - - clk_a = _gn_io.clk.get_AS_entries(clk_a) - clk_b = _gn_io.clk.get_AS_entries(clk_b) - - if ext_dt is None: - common_dt = clk_a.index.levels[0] - else: - common_dt = clk_a.index.levels[0].intersection(ext_dt) - if len(common_dt) == 0: raise ValueError("no common epochs between clk_a and external dt") - - common_dt = common_dt.intersection(clk_b.index.levels[0]) - if len(common_dt) == 0:raise ValueError("no common epochs between clk_a and clk_b") - - clk_a_unst = _gn_aux.rm_duplicates_df(clk_a.loc[common_dt]).unstack(1) - clk_b_unst = _gn_aux.rm_duplicates_df(clk_b.loc[common_dt]).unstack(1) - - - if ext_svs is None: - common_svs = clk_a_unst.columns # assuming ext_svs is lots smaller than count of svs in - else: - common_svs = clk_a_unst.columns.intersection(ext_svs) - if not _gn_aux.array_equal_unordered(common_svs,clk_b_unst.columns.values): - common_svs = common_svs.intersection(clk_b_unst.columns) - clk_a_unst = clk_a_unst[common_svs] - clk_b_unst = clk_b_unst[common_svs] - else: - _logging.debug('_compare_clk: skipping svs sync for clk_b_unst as the same as common_svs') - if not _gn_aux.array_equal_unordered(common_svs,clk_a_unst.columns.values): - _logging.debug('_compare_clk: syncing clk_a_unst with common_svs as not equal') - clk_a_unst = clk_a_unst[common_svs] - - - if norm_type == 'sv': - norm_type = _gn_io.clk.select_norm_svs_per_gnss(clk_a_unst=clk_a_unst,clk_b_unst=clk_b_unst) - #get the sv to use for norm and overwrite norm_type value with sv prn code - _gn_io.clk.rm_clk_bias(clk_a_unst,norm_type=norm_type) - _gn_io.clk.rm_clk_bias(clk_b_unst,norm_type=norm_type) - - clk_diff = (clk_a_unst - clk_b_unst)*_gn_const.C_LIGHT - return clk_diff - - -def sisre(sp3_a: _pd.DataFrame, sp3_b: _pd.DataFrame, - clk_a: _Union[_pd.DataFrame, None] = None, - clk_b: _Union[_pd.DataFrame, None] = None, - norm_type: str = 'both', output_mode: str = 'rms', - clean: bool = True, cutoff: _Union[int, float, None] = None, - use_rms: bool = False): - """ - Computes SISRE metric for the combination of orbits and clock offsets. Note, - if clock offsets were not provided computes orbit SISRE. Ignores clock - offset values which could available in the orbit files (sp3). - TODO Add support for sp3 clock offset values, that could be overridden - TODO by proper clk input. Add a 'force' option to use sp3 clock offsets. - - Returns SISRE metric computed using the equation of Steigenberger & - Montenbruck (2020) SISRE = sqrt( (w₁²R² - 2w₁RT + T²) + w₂²(A² + C²) ) - according to which is the same as sqrt((αR - cT)² + (A² + C²)/β), with - w₁ = α and w₂ = sqrt(1/β). - α and β are given in the table below: - BDS(GEO/IGSO) BDS(MEO) GPS GLO GAL - α 0.99 0.98 0.98 0.98 0.98 - β 127 54 49 45 61 - *QZSS (J) is being ignored - *BeiDou different coeffs for MEO/GEO not implemented yet - - Parameters - ---------- - sp3_a : sp3 DataFrame a - Output of read_sp3 function or a similar sp3 DataFrame. - sp3_b : sp3 DataFrame b - Output of read_sp3 function or a similar sp3 DataFrame. - clk_a : clk DataFrame a (optinal) - Output of read_clk function or a similar clk DataFrame. - clk_b : clk DataFrame b (optional) - Output of read_clk function or a similar clk DataFrame. - norm_type : str - a norm_type parameter used for the clk values normalisations before - differencing. - output_mode : str - controls at what stage to output SISRE - clean : bool - switch to use sigma filtering on the data. - cutoff : int or float, default None - A cutoff value in meters that is used to clip the values above it in - both RAC frame values and clk offset differences. Operation is skipped - if None is provided (default). - use_rms : bool, default False - A switch to compute RMS timeseries of RAC and T per each GNSS before - computing SISRE. - - Returns - ------- - sisre : DataFrame or Series depending in the output_mode selection - output_mode = 'rms' : Series of RMS SISRE values, value per GNSS. - output_mode = 'gnss' : DataFrame of epoch-wise RMS SISRE values per GNSS. - output_mode = 'sv' : DataFrame of epoch-wise SISRE values per SV. - """ - if output_mode not in ['rms', 'sv', 'gnss']: - raise ValueError('incorrect output_mode given: %s' % output_mode) - - rac = _gn_io.sp3.diff_sp3_rac(_gn_aux.rm_duplicates_df(sp3_a, rm_nan_level=1), - _gn_aux.rm_duplicates_df(sp3_b, rm_nan_level=1), - hlm_mode=None).EST_RAC.unstack() * 1000 # km to meters, - # sync is being done within the function. - # Filters with std over XYZ separately and all satellites together - if clean: - if cutoff is not None: - rac = rac[rac.abs() < cutoff] - rac = rac[rac.abs() < _gn_aux.get_std_bounds( - rac, axis=0, sigma_coeff=3)] - - if (clk_a is not None) & (clk_b is not None): # check if clk data is present - clk_diff = _compare_clk(clk_a, clk_b, norm_type=norm_type, - ext_dt=rac.index, ext_svs=rac.columns.levels[1]) # units are meters - if clean: - if cutoff is not None: - clk_diff = clk_diff[clk_diff.abs() < cutoff] - clk_diff = clk_diff[clk_diff.abs() < _gn_aux.get_std_bounds( - clk_diff, axis=0, sigma_coeff=3)] - common_epochs_RAC_T = rac.index.intersection( - clk_diff.index.values) # RAC epochs not present in clk_diff - common_svs = rac.columns.levels[1].intersection( - clk_diff.columns) # RAC SVs not present in clk_diff - # common_epochs_RAC_T here might be not required. TODO - clk_diff = clk_diff.loc[common_epochs_RAC_T][common_svs] - rac = rac.loc[common_epochs_RAC_T].loc(axis=1)[:, common_svs] - else: - clk_diff = 0 - _logging.debug(msg='computing orbit SISRE as clk offsets not given') - - if use_rms: # compute rms over each constellation svs at each epoch before moving on - rac.columns = [rac.columns.droplevel( - 1), rac.columns.droplevel(0).values.astype(' date_J2000)] - - comboindex = _pd.Index(output.CODE.values + '_' + output.PT.values.astype(object) - + output.SOLN.values.astype(object)) - - itrf_code_pt = _pd.Index(output.CODE.values + '_' + - output.PT.values.astype(object), name=None).unique() - soln_series = _pd.Series(index=itrf_code_pt, data='1') - - # clean discontinuities file from stations missing in the frame - comboindex_dv = _pd.Index( - discon_valid.CODE.values + '_' + discon_valid.PT.values) - dv_mask = comboindex_dv.isin(itrf_code_pt) - - # overwrite indices on discont - soln_series.loc[comboindex_dv[dv_mask]] = discon_valid[dv_mask].SOLN - out = output[_pd.Index(comboindex).isin( - soln_series.index.values + soln_series.values)] - - if list_path_or_df is not None: - if isinstance(list_path_or_df,_pd.DataFrame): - core_df = list_path_or_df - core_list = core_df.CODE.values - elif isinstance(list_path_or_df,str): - core_df = _get_core_list(list_path_or_df) - core_list = core_df.CODE.values - elif isinstance(list_path_or_df,_np.ndarray) or isinstance(list_path_or_df,list): - core_list = list_path_or_df - else: - logging.error(msg='check list_path_or_df') - out_mask = out.CODE.isin(core_list) - if out_mask.sum()>0: - out = out[out_mask] - else: - logging.error(msg='list stations are not in frame') - return None - - # test3 = test3[~test3.index.str.contains(pat='P\d{3}.')] #remove thise weird sites P104 etc - - combo_index = out.CODE.values + '_' + out.PT.values.astype(object) - combo_index = _pd.MultiIndex.from_arrays([combo_index,out.TYPE]) - - duplicated_mask = combo_index.duplicated() - if duplicated_mask.sum() > 0: - logging.warning(msg=f'Removed duplicates of stations: {combo_index[duplicated_mask].get_level_values(0).unique().tolist()}') - out_xyzvel = out.EST[~duplicated_mask].copy() - out_xyzvel.index = combo_index[~duplicated_mask] - else: - out_xyzvel = out.EST.copy() - out_xyzvel.index = combo_index - - out_xyzvel = out_xyzvel.unstack(level=1) - itrf_reference = out['REF_EPOCH'].unique()[0] - time_seconds = date_J2000 - itrf_reference - - position = out_xyzvel.iloc[:, :3] - velocities = out_xyzvel.iloc[:, 3:6] - out = position + velocities.values * (time_seconds/_SEC_IN_YEAR) - out.columns = out.columns.astype(str) - out['SOLN'] = '' - out['SOLN'] += soln_series - out.attrs['REF_EPOCH'] = date_J2000 - - if psd_path_or_df is not None: - if isinstance(psd_path_or_df,_pd.DataFrame): - psd_df = psd_path_or_df - elif isinstance(psd_path_or_df,str): - psd_df = _gn_io.psd._get_psd_df(psd_path_or_df) - else: - logging.error(msg='check psd_path_or_df') - out = psd2frame(frame_of_day=out, psd_df=psd_df) - return out - - -def psd2frame(frame_of_day, psd_df): - '''ref_epoch is extracted from frame_of_day attribute - Outputs EST - |STAX|STAY|STAZ|''' - psd_df_ref = _get_psd_enu(psd_df=psd_df, - date_J2000=frame_of_day.attrs['REF_EPOCH']) - frame_codes = frame_of_day.index.str.split( - '_', expand=True).get_level_values(level=0) - - # if site has more than one monument - all monuments use same psd - psd_enu = _pd.DataFrame(index=frame_codes).join( - other=psd_df_ref).set_index(frame_of_day.index) - # select only those sites that have psd event - psd_enu = psd_enu[psd_enu.any(axis=1)] - - llh = _gn_transform.xyz2llh_heik(xyz_array=frame_of_day[['STAX','STAY','STAZ']].loc[psd_enu.index].values) - phi, lam = llh[:, 0], llh[:, 1] - rot = _gn_transform.llh2rot(phi=phi, lamb=lam) - - psd_xyz = _pd.DataFrame(data=_np.squeeze(psd_enu.values[:, _np.newaxis] @ rot, axis=1), - index=psd_enu.index, columns=['STAX', 'STAY', 'STAZ']) - psd_xyz['SOLN'] = '' - frame_of_day.loc[psd_xyz.index] += psd_xyz - return frame_of_day - - -def _get_psd_enu(psd_df, date_J2000): - '''Reads psd file and computes psd values at each of east, north and up components for the data_J2000 - Ignores the monument information as should be the same for different monuments of the same stations''' - ref_epochs = psd_df.index.get_level_values(level=1) - valid_mask = ref_epochs < date_J2000 - - psd_coeff = psd_df[valid_mask].copy() - psd_coeff['dt_years'] = (date_J2000 - ref_epochs[valid_mask])/_SEC_IN_YEAR - - log_part = psd_coeff['ALOG'] * \ - _np.log(1 + psd_coeff[['dt_years']].values / psd_coeff['TLOG'].values) - exp_part = psd_coeff['AEXP'] * \ - (1 - _np.exp(-(psd_coeff[['dt_years'] - ].values / psd_coeff['TEXP'].values))) - log_part_grouped = log_part.groupby(axis=0, level=0).sum() - exp_part_grouped = exp_part.groupby(axis=0, level=0).sum() - - out = log_part_grouped.add(exp_part_grouped, fill_value=0)/1000 - # if log or exp part is missing for the component, .add should take care of the nans being added - # .rename(columns={'E':'EAST','N':'NORTH','H':'UP'}) - return out[['E', 'N', 'H']] - -# gather_reader -def read_frame_snx_all(*file_paths,core_sites=None): - buf=[] - for path in file_paths: - buf.append(_gn_io.sinex._get_snx_vector_gzchunks(filename=path,block_name='SOLUTION/ESTIMATE')) - all_frame = _pd.concat(buf) - if core_sites is not None: - return all_frame[all_frame.CODE.isin(core_sites)] - return all_frame - -def read_disc_all(*file_paths,core_sites=None): - buf=[] - for path in file_paths: - buf.append(_gn_io.discon._read_discontinuities(path)) - all_discon = _pd.concat(buf) - all_discon = all_discon[all_discon.MODEL.values =='P'] - - if core_sites is not None: - return all_discon[all_discon.CODE.isin(core_sites)] - return all_discon - -def read_psd_all(*file_paths,core_sites=None): - buf=[] - for path in file_paths: - buf.append(_gn_io.psd._get_psd_df(path)) - all_psd = _pd.concat(buf) - if core_sites is not None: - psd_sites = all_psd.index.levels[0] - return all_psd.loc[psd_sites[psd_sites.isin(core_sites)]] - return all_psd diff --git a/scripts/gn_lib/gn_io/__init__.py b/scripts/gn_lib/gn_io/__init__.py deleted file mode 100644 index fa1f05ff5..000000000 --- a/scripts/gn_lib/gn_io/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -from . import ( - aux_dicts, - clk, - common, - discon, - igslog, - ionex, - pea, - pod, - psd, - rinex, - sinex, - sp3, - stec, - trace, - trop, -) - -__all__ = [ - "aux_dicts", - "clk", - "common", - "discon", - "igslog", - "ionex", - "pea", - "pod", - "psd", - "rinex", - "sinex", - "sp3", - "stec", - "trace", - "trop", -] \ No newline at end of file diff --git a/scripts/gn_lib/gn_io/aux_dicts.py b/scripts/gn_lib/gn_io/aux_dicts.py deleted file mode 100644 index c9c488dca..000000000 --- a/scripts/gn_lib/gn_io/aux_dicts.py +++ /dev/null @@ -1,328 +0,0 @@ -'''Radomes, Antennas and Receiver names tables and translation dicts for typos''' - -translation_country = {'NA':'N/A', - '':'N/A', - 'US':'USA', - 'UNITED STATES':'USA', - 'UNITED STATES OF AMERICA':'USA', - 'U.S.':'USA', - 'U.S.A':'USA', - 'U.S.A.':'USA', - 'UNITED KINGDOM OF GREAT BRITAIN AND NORTHERN':'UK', - 'UNITED KINGDOM OF GREAT BRITAIN AND NORTHERN IRELAND':'UK', - 'ENGLAND':'UK', - 'ANTIGUA & BARBUDA':'ANTIGUA', - 'ANTIGUA AND BARBUDA':'ANTIGUA', - 'I.R.IRAN':'IRAN', - 'DANMARK':'DENMARK', - 'MÉXICO':'MEXICO', - 'CZECH REPUBLIC':'CZECHIA', - 'REPUBLIC OF INDONESIA':'INDONESIA', - 'REPUBLIC OF MALDIVES':'MALDIVES', - 'REPUBLIC OF MOLDOVA':'MOLDOVA', - 'REPUBLIC OF NAURU':'NAURU', - 'REPUBLIC OF SINGAPORE':'SINGAPORE', - 'REPUBLIC OF SOUTH AFRICA':'SOUTH AFRICA', - 'REPUBLICA DOMINICANA':'DOMINICANA', - 'RUSSIAN FEDERATION':'RUSSIA', - 'UNITED ARAB EMIRATES':'UAE', - 'CA':'CANADA', - 'ANTARCTIC PENINSULA':'ANTARCTICA', - 'ANTARTIDA':'ANTARCTICA', - 'BRASIL':'BRAZIL', - 'CAPE VERDE':'CABO VERDE', - 'DOMINICAN REPUBLIC': 'DOMINICANA', - 'BOSNIA AND HERZEGOVINA':'BOSNIA', - 'BRITISH VIRGIN ISLANDS':'VIRGIN ISL', - 'BRUNEI DARUSSALAM':'BRUNEI', - 'CAYMAN ISLANDS':'CAYMAN ISL', - 'COOK ISLANDS':'COOK ISL', - 'FALKLAND ISLANDS':'FALKLAND ISL', - 'FAROE ISLANDS':'FAROE ISL', - 'FRENCH GUIANA':'FR GUIANA', - 'FRENCH GUYANA':'FR GUYANA', - 'FRENCH POLYNESIA':'FR POLYNESIA', - 'FRENCH SOUTHERN TERRITORIES':'FR SOUTHERN', - 'NETHERLANDS ANTILLES':'ANTILLES', - 'MARSHALL ISLANDS':'MARSHALL ISL', - 'SAINT HELENA':'ST HELENA', - 'SAINT VINCENT AND THE GRENADINES':'ST VINCENT', - 'ST. LUCIA':'ST LUCIA', - 'THE BAHAMAS':'BAHAMAS', - 'TRINIDAD AND TOBAGO':'TRINIDAD', - 'TURKS AND CAICOS ISLANDS':'TURKS ISL', - 'VIET NAM':'VIETNAM', - 'VIRGIN ISLANDS':'VIRGIN ISL', - 'US VIRGIN ISLANDS':'VIRGIN ISL', - 'WALLIS AND FUTUNA':'WALLIS', - 'WEST ANTARCTICA':'W AFRICA' - } - -translation_rec = {'3S NAVIGATION R100-40T':'3SNAV R100-40T 4', - 'LEICA GRX1200 PRO' :'LEICA GRX1200PRO', - 'LEICA GRX1200 +GNSS' :'LEICA GRX1200+GNSS', - 'LEICA GRX1200 GNSS' :'LEICA GRX1200+GNSS', - 'LEICA GRX1200+ GNSS' :'LEICA GRX1200+GNSS', - 'LEICA GRX1200GG PRO' :'LEICA GRX1200GGPRO', - 'GRX1200 GG PRO' :'LEICA GRX1200GGPRO', - 'ASHTECH UZ_12' :'ASHTECH UZ-12', - 'ASHTECH Z-12' :'ASHTECH Z-XII3', - 'ASHTECH MICROZ' :'ASHTECH UZ-12', - 'SEPTENTRIO POLARX5' :'SEPT POLARX5', - 'TOPCON NET-G3A' :'TPS NET-G3A', - 'TOPCON NET-G5' :'TPS NET-G5', - 'TOPCON NET-G3' :'TPS NETG3', - 'TOPCON NETG3' :'TPS NETG3', - 'TRIMBLE 4000 SSE' :'TRIMBLE 4000SSE', - 'TRIMBLE 4000 SSI' :'TRIMBLE 4000SSI', - 'E_GGD' :'JPS E_GGD', - 'NOVATEL EURO4' :'NOV EURO4-1.00-222'} - -translation_ant = {'AERAT1675-120' :'AERAT1675_120', - 'AERAT2775-42' :'AERAT2775_42', - 'LEIAR25.3' :'LEIAR25.R3', - 'JAV_GRANT-G3T+G':'JAV_GRANT-G3T', - 'TPSPG_F1+GP' :'TPSPG_A1+GP'} - -translation_rad = { '' :'NONE', #this is done after radome2 field check - 'N/A' :'NONE', - ' NONE':'NONE', - ' NON' :'NONE',} - -atx_rad_tbl =['ARFC','ARFS','CHCD','CONE','DUTD','HITS','HITZ', -'HXCG','HXCS','JAVC','JAVD','JVDM','JVGR','JVSD','LEIC', -'LEIM','LEIS','LEIT','MMAC','NONE','NOVC','NOVS','OLGA', -'PFAN','RADM','SCIS','SCIT','SNOW','SPKE','STHC','TCWD', -'TPSD','TPSH','TZGD','UNAV', - -'GSI4','UNKN','DOME','EMRA','AUST','JPLA','ENCL','CAFG',#non-atx -'SCPL','CNTS','STXG','OSOD','BEVA'] #non-atx - - -atx_ant_tbl = [ -'3S-02-TSADM', '3S-02-TSATE', 'ACC123CGNSSA_XN', 'ACCG8ANT_52A4TC', -'ACC_G5ANT_52AT1', 'AERAT1675_120', 'AERAT2775_42', 'AERAT2775_43', 'AOAD/M_B', -'AOAD/M_T', 'AOAD/M_TA_NGS', 'APSAPS-3', 'ARFAS13DFS', 'ARFAS1FS', 'ASH110454', -'ASH111661', 'ASH700228A', 'ASH700228A+EX', 'ASH700228B', 'ASH700228C', -'ASH700228D', 'ASH700228E', 'ASH700699.L1', 'ASH700700.A', 'ASH700700.B', -'ASH700700.C', 'ASH700718A', 'ASH700718B', 'ASH700829.2', 'ASH700829.3', -'ASH700829.A', 'ASH700829.A1', 'ASH700936A_M', 'ASH700936B_M', 'ASH700936C_M', -'ASH700936D_M', 'ASH700936E', 'ASH700936E_C', 'ASH700936F_C', 'ASH701008.01B', -'ASH701023.A', 'ASH701073.1', 'ASH701073.3', 'ASH701933A_M', 'ASH701933B_M', -'ASH701933C_M', 'ASH701941.1', 'ASH701941.2', 'ASH701941.A', 'ASH701941.B', -'ASH701945B_M', 'ASH701945C_M', 'ASH701945D_M', 'ASH701945E_M', 'ASH701945G_M', -'ASH701946.2', 'ASH701946.3', 'ASH701975.01A', 'ASH701975.01AGP', 'CHAPS9017', -'CHCA220GR', 'CHCC220GR', 'CHCC220GR2', 'CHCI80', 'CHCX90D-OPUS', 'CHCX91+S', -'CHCX91B', 'GMXZENITH10', 'GMXZENITH15', 'GMXZENITH20', 'GMXZENITH25', -'GMXZENITH25PRO', 'GMXZENITH35', 'GMXZENITH40', 'HEMA42', 'HEMA52_WB', -'HITAT35101CP', 'HITAT35101CR', 'HITAT35101H', 'HITAT45101CP', 'HITAT45101CR', -'HXCCG7601A', 'HXCCG7602A', 'HXCCGX601A', 'HXCCSX601A', 'HXCGG486A', -'HXCGS488A', 'IGAIG8', 'ITT3750323', 'JAVGRANT_G5T', 'JAVGRANT_G5T+GP', -'JAVRINGANT_DM', 'JAVRINGANT_G5T', 'JAVTRIUMPH_1M', 'JAVTRIUMPH_1MR', -'JAVTRIUMPH_2A', 'JAVTRIUMPH_2A+G', 'JAVTRIUMPH_2A+P', 'JAVTRIUMPH_LSA', -'JAV_GRANT-G3T', 'JAV_RINGANT_G3T', 'JAV_TRIUMPH-1', 'JAV_TRIUMPH-1R', -'JNSCHOKERING_DM', 'JNSCR_C146-22-1', 'JNSMARANT_GGD', 'JPLD/M_R', -'JPLD/M_RA_SOP', 'JPSLEGANT_E', 'JPSODYSSEY_I', 'JPSREGANT_DD_E', -'JPSREGANT_DD_E1', 'JPSREGANT_DD_E2', 'JPSREGANT_SD_E', 'JPSREGANT_SD_E1', -'JPSREGANT_SD_E2', 'LEIAR10', 'LEIAR20', 'LEIAR25', 'LEIAR25.R3', 'LEIAR25.R4', -'LEIAS05', 'LEIAS10', 'LEIAT202+GP', 'LEIAT202-GP', 'LEIAT302+GP', -'LEIAT302-GP', 'LEIAT303', 'LEIAT502', 'LEIAT503', 'LEIAT504', 'LEIAT504GG', -'LEIATX1230', 'LEIATX1230+GNSS', 'LEIATX1230GG', 'LEIAX1202', 'LEIAX1202A', -'LEIAX1202GG', 'LEIAX1203+GNSS', 'LEICGA60', 'LEIGG02PLUS', 'LEIGG03', -'LEIGG04', 'LEIGG04PLUS', 'LEIGS08', 'LEIGS08PLUS', 'LEIGS09', 'LEIGS12', -'LEIGS14', 'LEIGS15', 'LEIGS15.R2', 'LEIGS16', 'LEIGS18', 'LEIICG60', -'LEIICG70', 'LEIMNA950GG', 'LEISR299_INT', 'LEISR399_INT', 'LEISR399_INTA', -'MAC4647942', 'MAG111406', 'MPLL1/L2_SURV', 'MPL_WAAS_2224NW', -'MPL_WAAS_2225NW', 'MVECR152GNSSA', 'MVEGA152GNSSA', 'NAVAN2004T', 'NAVAN2008T', -'NAV_ANT3001BR', 'NAX3G+C', 'NOV501', 'NOV501+CR', 'NOV502', 'NOV502+CR', -'NOV503+CR', 'NOV531', 'NOV531+CR', 'NOV533', 'NOV533+CR', 'NOV600', 'NOV702', -'NOV702GG', 'NOV702_2.02', 'NOV702_3.00', 'NOV703GGG.R2', 'NOV750.R4', -'NOV750.R5', 'NOV850', 'NOV_WAAS_600', 'RNG80971.00', 'SEN67157596+CR', -'SEPALTUS_NR3', 'SEPCHOKE_B3E6', 'SEPCHOKE_MC', 'SEPPOLANT_X_MF', 'SJTTL111', -'SOK502', 'SOK600', 'SOK702', 'SOKGCX2', 'SOKGCX3', 'SOKGRX2', 'SOKGSX2', -'SOKSA500', 'SOK_GSR2700ISX', 'SOK_RADIAN_IS', 'SPP571212238+GP', -'SPP571908273+CR', 'SPP68410_10', 'SPP91564_1', 'SPP91564_2', 'STHCR3-G3', -'STHS82_7224V3.0', 'STHS86_7224V3.1', 'STXS10SX017A', 'STXS800', 'STXS800A', -'STXS8PX003A', 'STXS900', 'STXS9I', 'STXS9PX001A', 'STXS9SA7224V3.0', -'THA800961+REC', 'THA800961+RTK', 'THA800961RECUHF', 'THA800961RTKUHF', -'TIAPENG2100B', 'TIAPENG2100R', 'TIAPENG3100R1', 'TIAPENG3100R2', 'TOP700779A', -'TOP72110', 'TPSCR.G3', 'TPSCR.G5', 'TPSCR.G5C', 'TPSCR3_GGD', 'TPSCR4', -'TPSG3_A1', 'TPSG5_A1', 'TPSGR3', 'TPSGR5', 'TPSHIPER_GD', 'TPSHIPER_GGD', -'TPSHIPER_HR', 'TPSHIPER_HR+PS', 'TPSHIPER_II', 'TPSHIPER_II+10', -'TPSHIPER_LITE', 'TPSHIPER_PLUS', 'TPSHIPER_SR', 'TPSHIPER_VR', 'TPSLEGANT2', -'TPSLEGANT3_UHF', 'TPSLEGANT_G', 'TPSODYSSEY_I', 'TPSPG_A1', 'TPSPG_A1+GP', -'TPSPG_A1_6+GP', 'TPSPG_S1', 'TPSPN.A5', 'TRM105000.10', 'TRM115000.00', -'TRM115000.10', 'TRM14177.00', 'TRM14532.00', 'TRM14532.10', 'TRM159800.00', -'TRM159900.00', 'TRM22020.00+GP', 'TRM22020.00-GP', 'TRM23903.00', -'TRM27947.00+GP', 'TRM27947.00-GP', 'TRM29659.00', 'TRM33429.00+GP', -'TRM33429.00-GP', 'TRM33429.20+GP', 'TRM36569.00+GP', 'TRM39105.00', -'TRM41249.00', 'TRM41249USCG', 'TRM4800', 'TRM55970.00', 'TRM55971.00', -'TRM57970.00', 'TRM57971.00', 'TRM5800', 'TRM59800.00', 'TRM59800.00C', -'TRM59800.80', 'TRM59900.00', 'TRMR10', 'TRMR10-2', 'TRMR2', 'TRMR4-2', -'TRMR4-3', 'TRMR6', 'TRMR6-2', 'TRMR6-3', 'TRMR6-4', 'TRMR8-4', 'TRMR8S', -'TRMR8_GNSS', 'TRMR8_GNSS3', 'TRMSPS985', 'TRMSPS986', 'TRM_R6', 'TRM_R8', -'TWIVP6000', 'TWIVP6050_CONE' -] + [ -'TSA-100', 'MP-1372FW+REGP', 'TRM59800.99', 'TRM5797100.00', -'TWIVC6150', 'TRM115000.00+S', 'TRM26738.00', 'TPSCR.3G', -'CNTAT350', 'AOAD/M_T_RFI_T', 'TPSPG_A1+M', -'ASH701975.02A', 'STXSA1500', 'SPP135000.00', 'LEAT504', -'ACC72CGNSSA', 'AERAT1675-7M', 'ASH700936E_M', -'TRM27256.00', 'TRM29659', 'LEIAR24.R4', -'TRM77971.00', 'TRM57971', '3S-02-1AERO+CR', -'ASH701945H_M' -] + [ -'ADVNULLANTENNA', 'NULLANTENNA', 'GPPNULLANTENNA'] - - -igs_rec_tbl = [ -'3SNAV GNSS-300','3SNAV GNSS-300T','3SNAV R100 OLD','3SNAV R101 OLD','3SNAV R100-30', -'3SNAV R100-30T 2','3SNAV R100-30T 12','3SNAV R100-40','3SNAV R100-40T 4','3SNAV R100-40T 12', - -'ALERTGEO RESOLUTE', - -'ALTUS APS-3','ALTUS APS-3L','ALTUS APS-GEOPOD','ALTUS APS-NR2', - -'ASHTECH 3DF-XXIV','ASHTECH 802147_A','ASHTECH D-XII','ASHTECH G-XII','ASHTECH GG24C', -'ASHTECH L-XII','ASHTECH LCS-XII','ASHTECH LM-XII3','ASHTECH M-XII','ASHTECH MS-XII', -'ASHTECH P-XII3','ASHTECH PF500','ASHTECH PF800','ASHTECH RANGER','ASHTECH S-XII', -'ASHTECH SUPER-CA','ASHTECH UZ-12','ASHTECH Z-X','ASHTECH Z-XII3','ASHTECH Z-XII3GETT', -'ASHTECH Z-XII3T','ASHTECH Z18', - -'CHAMPION PRO','CHAMPION QB1','CHAMPION WR1', - -'CHC B20','CHC I80','CHC LT500H','CHC LT500N','CHC LT500T','CHC LT500U','CHC N71','CHC N72', -'CHC P5E','CHC X20+','CHC X20I+DGNSS','CHC X20I+RTK','CHC X360','CHC X90+','CHC X900+', -'CHC X900+S','CHC X900B','CHC X900R','CHC X90D-OPUS','CHC X91+','CHC X91+S','CHC X91B', -'CHC X91R', - -'COMNAV M300 PRO','COMNAV M300 MINI','COMNAV T30','COMNAV T300','COMNAV T300+', - -'EMLID REACH RS2', - -'FOIF A30','FOIF A90 GNSS', - -'GEOMAX ZENITH10','GEOMAX ZENITH15','GEOMAX ZENITH16','GEOMAX ZENITH20','GEOMAX ZENITH25', -'GEOMAX ZENITH25PRO','GEOMAX ZENITH35','GEOMAX ZENITH40', - -'GINTEC CYF90', - -'HEMISPHERE S631', - -'IFEN NX_NTR_303_D','IFEN NX_NTR_500_D','IFEN NX_NTR_600_D','IFEN SX_NSR_RT_200', -'IFEN SX_NSR_RT_300','IFEN SX_NSR_RT_400','IFEN SX_NSR_RT_401','IFEN SX_NSR_RT_402', -'IFEN SX_NSR_RT_700','IFEN SX_NSR_RT_800', - -'IGAGE IG8', - -'ITT 3750300', - - -'JAVAD DUO_G2','JAVAD DUO_G2 DELTA','JAVAD DUO_G2 SIGMA','JAVAD DUO_G2D','JAVAD DUO_G2D DELTA', -'JAVAD DUO_G2D SIGMA','JAVAD DUO_G3D','JAVAD DUO_G3D DELTA','JAVAD DUO_G3D SIGMA','JAVAD GISMORE', -'JAVAD OMEGA','JAVAD QUA_G3D','JAVAD QUA_G3D DELTA','JAVAD QUA_G3D SIGMA','JAVAD TR_3N', -'JAVAD TR_3N ALPHA','JAVAD TR_3N ALPHA2','JAVAD TR_G2','JAVAD TR_G2 ALPHA2','JAVAD TR_G2T', -'JAVAD TR_G2T ALPHA','JAVAD TR_G2TH','JAVAD TR_G2TH ALPHA','JAVAD TR_G2TH ALPHA2','JAVAD TR_G3', -'JAVAD TR_G3 ALPHA','JAVAD TR_G3H','JAVAD TR_G3H ALPHA','JAVAD TR_G3H ALPHA2','JAVAD TR_G3T', -'JAVAD TR_G3T ALPHA','JAVAD TR_G3TH','JAVAD TR_G3TH ALPHA','JAVAD TR_G3TH ALPHA2','JAVAD TR_LS', -'JAVAD TR_VS','JAVAD TRE_3','JAVAD TRE_3 DELTA','JAVAD TRE_3 SIGMA','JAVAD TRE_3L SIGMA', -'JAVAD TRE_3L','JAVAD TRE_3L DELTA','JAVAD TRE_3N','JAVAD TRE_3N DELTA','JAVAD TRE_3N SIGMA', -'JAVAD TRE_DUO','JAVAD TRE_DUO DELTA','JAVAD TRE_DUO SIGMA','JAVAD TRE_G2T','JAVAD TRE_G2T DELTA', -'JAVAD TRE_G2T SIGMA','JAVAD TRE_G2TH','JAVAD TRE_G2TH DELTA','JAVAD TRE_G2TH SIGMA', -'JAVAD TRE_G3T','JAVAD TRE_G3T DELTA','JAVAD TRE_G3T SIGMA','JAVAD TRE_G3TAJ', -'JAVAD TRE_G3TAJ DELT','JAVAD TRE_G3TAJ SIGM','JAVAD TRE_G3TH','JAVAD TRE_G3TH DELTA', -'JAVAD TRE_G3TH SIGMA','JAVAD TRE_QUA','JAVAD TRE_QUA DELTA','JAVAD TRE_QUA SIGMA', -'JAVAD TRIUMPH_1M','JAVAD TRIUMPH1','JAVAD TRIUMPH2','JAVAD TRIUMPH3','JAVAD TRIUMPH4', - -'JPS E_GGD','JPS EGGDT','JPS EUROCARD','JPS LEGACY','JPS ODYSSEY','JPS REGENCY', - -'LEICA ATX1230','LEICA ATX1230+GNSS','LEICA CRS1000','LEICA FLX100','LEICA GG02PLUS','LEICA GG03', -'LEICA GG04','LEICA GG04PLUS','LEICA GM30','LEICA GMX901','LEICA GMX902','LEICA GMX910', -'LEICA GMX902GG','LEICA GR10','LEICA GR25','LEICA GR30','LEICA GR50','LEICA GRX1200', -'LEICA GRX1200+','LEICA GRX1200+GNSS','LEICA GRX1200GGPRO','LEICA GRX1200LITE', -'LEICA GRX1200PRO','LEICA GS07','LEICA GS08','LEICA GS08PLUS','LEICA GS09','LEICA GS10', -'LEICA GS12','LEICA GS14','LEICA GS15','LEICA GS16','LEICA GS18','LEICA GS25','LEICA GX1210', -'LEICA GX1210+','LEICA GX1220','LEICA GX1220+','LEICA GX1220+GNSS','LEICA GX1230','LEICA GX1230+', -'LEICA GX1230+GNSS','LEICA GX1230GG','LEICA ICG30','LEICA ICG60','LEICA ICG70','LEICA ICG81', -'LEICA ICG82','LEICA MC1000','LEICA MC500','LEICA MNA950GG','LEICA MNS1250GG','LEICA RS500', -'LEICA SR260','LEICA SR261','LEICA SR299','LEICA SR299E','LEICA SR399','LEICA SR399E', -'LEICA SR510','LEICA SR520','LEICA SR530','LEICA SR9400','LEICA SR9500','LEICA SR9600', - -'MAGELLAN PM-500', - -'MINIMAC 2816','MINIMAC 2816AT', - -'NAVCOM NCT-2000D','NAVCOM NCT-2030M','NAVCOM RT-3010S','NAVCOM RT-3020M','NAVCOM RT-3020S', -'NAVCOM SF-2000','NAVCOM SF-2040G','NAVCOM SF-2050G','NAVCOM SF-2050M','NAVCOM SF-2050R', - - -'NOV 15A','NOV EURO4-1.00-222','NOV MILLEN-RT2','NOV MILLEN-RT2OS','NOV MILLEN-STD', -'NOV MILLEN-STDW','NOV OEM4-G2','NOV OEM6','NOV OEM7','NOV OEMV1','NOV OEMV1G', -'NOV OEMV2','NOV OEMV3','NOV OEMV3-RT2','NOV WAASGII', - -'PANDA PD318','PANDA PD51A','PANDA PD9', - -'PREXISO G4','PREXISO G5', - -'QIANXUN ISTATION18', - -'RAYMAND IRNET-G3B','RAYMAND IRO-G3B', - -'AOA BENCHMARK ACT','AOA ICS-4000Z','AOA ICS-4000Z ACT','AOA RASCAL-12','AOA RASCAL-8', -'AOA SNR-12 ACT','AOA SNR-8000 ACT','AOA SNR-8100 ACT','AOA TTR-12','AOA TTR-4P', - -'ROGUE SNR-12','ROGUE SNR-12 RM','ROGUE SNR-8','ROGUE SNR-800','ROGUE SNR-8000','ROGUE SNR-8100', -'ROGUE SNR-8A','ROGUE SNR-8C', - -'RNG FASA+','RNG FAZA2','RNG SMAXGEO', - -'SANDING T3 GNSS','SANDING T66PRO GNSS', - -'SEPT ALTUS NR3','SEPT ASTERX SB','SEPT ASTERX-M','SEPT ASTERX-U','SEPT ASTERX1','SEPT ASTERX2', -'SEPT ASTERX2E','SEPT ASTERX2EH','SEPT ASTERX2EL','SEPT ASTERX3','SEPT ASTERX4','SEPT POLARX2', -'SEPT POLARX2C','SEPT POLARX2E','SEPT POLARX3','SEPT POLARX3E','SEPT POLARX3EG','SEPT POLARX3ETR', -'SEPT POLARX3G','SEPT POLARX3TR','SEPT POLARX4','SEPT POLARX4TR','SEPT POLARX5','SEPT POLARX5E', -'SEPT POLARX5S','SEPT POLARX5TR','SEPT POLARXS', - -'SETTOP M1-V1', - -'SOK GCX3','SOK GSR2600','SOK GSR2700 RS','SOK GSR2700 RSX','SOK RADIAN','SOK RADIAN_IS', - -'SOUTH 660N GNSS','SOUTH G1 GNSS','SOUTH G1PLUS GNSS','SOUTH G6 GNSS','SOUTH NET-S8', -'SOUTH NET-S8+','SOUTH NET-S9','SOUTH S82-2013 GNSS','SOUTH S82T GNSS','SOUTH S82V GNSS', -'SOUTH S82V2 GNSS','SOUTH S86 GNSS','SOUTH S86-2013 GNSS','SOUTH S86T GNSS', - -'SPECTRA SP60','SPECTRA SP80','SPECTRA SP85','SPECTRA SP90M', - -'SPP 68410_10','SPP GEODIMETER-L1','SPP GEOTRACER100','SPP GEOTRACER3220','SPP GEOTRACER3320', -'SPP PROMARK700', - - -'STONEX S10','STONEX S700A','STONEX S8+ GNSS','STONEX S800','STONEX S800A','STONEX S850A', -'STONEX S900','STONEX S900A','STONEX S900A NEW','STONEX S900T','STONEX S980','STONEX S980A', -'STONEX S990A','STONEX S9I','STONEX S9II GNSS','STONEX S9III+ GNSS','STONEX SC200','STONEX SC2000', -'STONEX SC2200','STONEX SC600','STONEX SC600A', - -'TI4100', - -'TIASAHI PENG2100B','TIASAHI PENG2100R','TIASAHI PENG3100-R1','TIASAHI PENG3100-R2', -'TIASAHI PENG6J2','TIASAHI PENSMT888-3G', - - -'TOPCON GP-DX1','TOPCON GP-R1','TOPCON GP-R1D','TOPCON GP-R1DP','TOPCON GP-R1DY','TOPCON GP-S1', -'TOPCON GP-SX1','TOPCON TT4000SSI','TOPCON TURBO-SII','TPS E_GGD','TPS EUROCARD','TPS GB-1000', -'TPS GB-500','TPS GR3','TPS GR5','TPS HIPER_GD','TPS HIPER_GGD','TPS HIPER_HR','TPS HIPER_VR', -'TPS HIPER_LITE','TPS HIPER_PLUS','TPS LEGACY','TPS NET-G3A','TPS NET-G5','TPS NETG3', -'TPS ODYSSEY_E','TPS ODYSSEY_I', - -'TRIMBLE 4000S','TRIMBLE 4000SE','TRIMBLE 4000SL','TRIMBLE 4000SLD','TRIMBLE 4000SSE', -'TRIMBLE 4000SSI','TRIMBLE 4000SSI-SS','TRIMBLE 4000SST','TRIMBLE 4000ST','TRIMBLE 4000ST S', -'TRIMBLE 4000SX','TRIMBLE 4400','TRIMBLE 4600','TRIMBLE 4700','TRIMBLE 4800','TRIMBLE 5700', -'TRIMBLE 5800','TRIMBLE 7400MSI','TRIMBLE ALLOY','TRIMBLE GEODESIST P','TRIMBLE MS750', -'TRIMBLE NETR3','TRIMBLE NETR5','TRIMBLE NETR8','TRIMBLE NETR9','TRIMBLE NETRS','TRIMBLE R10', -'TRIMBLE R10-2','TRIMBLE R12','TRIMBLE R12I','TRIMBLE R2','TRIMBLE R4','TRIMBLE R4-2', -'TRIMBLE R4-3','TRIMBLE R5','TRIMBLE R6','TRIMBLE R6-2','TRIMBLE R6-3','TRIMBLE R6-4','TRIMBLE R7', -'TRIMBLE R7 GNSS','TRIMBLE R8','TRIMBLE R8 GNSS','TRIMBLE R8 GNSS3','TRIMBLE R8-4','TRIMBLE R8S', -'TRIMBLE R9S','TRIMBLE SPS852','TRIMBLE SPS855','TRIMBLE SPS985','TRIMBLE SPS986', - -'JPL BLACKJACK','ASHTECH Z-MAX','TRIMBLE SPS851'] #extra non-igs diff --git a/scripts/gn_lib/gn_io/clk.py b/scripts/gn_lib/gn_io/clk.py deleted file mode 100644 index 644a22fa1..000000000 --- a/scripts/gn_lib/gn_io/clk.py +++ /dev/null @@ -1,123 +0,0 @@ -'''RINEX CLK file parsing function''' -import re as _re -import sys as _sys -from io import BytesIO as _BytesIO -from typing import Union as _Union - -import numpy as _np -import pandas as _pd - -from gn_lib import gn_const as _gn_const -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io - -_RE_LINE = _re.compile(rb'(AS[ ]G.+)') # GPS SV line (other GNSS may not have STD) - -def read_clk(clk_path): - content = _gn_io.common.path2bytes(str(clk_path)) - data_b = content.find(b'END OF HEADER')+13 - data_b += content[data_b:data_b+20].find(b'\n') + 1 - - data = content[data_b:] - data_line = _RE_LINE.search(data) - assert data_line is not None - - len_line = len(data_line.groups()[0]) # need to get a line and check the length - - clk_cols = [0,1,2,3,4,5,6,7,9] - clk_names =['A','CODE','Y','M','D','h','m','s','EST'] - if len_line > 59: # if len over 59 -> expect STD column presence - clk_cols += [10] - clk_names +=['STD'] - - clk_df = _pd.read_csv(_BytesIO(data), - delim_whitespace=True,header=None,usecols=clk_cols,names = clk_names,# type:ignore - dtype = {'A':_gn_const.CLK_TYPE_CATEGORY,'CODE':object, - 'Y':_np.uint16,'M':_np.uint16,'D':_np.uint16, - 'h':_np.int32,'m':_np.int32,'s':_np.float_,}) - - date = (((clk_df.Y.values - 1970).astype('datetime64[Y]').astype('datetime64[M]') - + clk_df.M.values - 1).astype('datetime64[D]') - + clk_df.D.values - 1) - - time = (clk_df.h.values * 3600 + clk_df.m.values * 60 + clk_df.s.values).astype('timedelta64[s]') - - j2000time = _gn_datetime.datetime2j2000(date + time) - clk_df.drop(columns=['Y','M','D','h','m','s'],inplace=True) - clk_df.set_index(['A',j2000time,'CODE'],inplace=True) - clk_df.index.names = (['A','J2000','CODE']) - return clk_df - -def get_AS_entries(clk_df): - # fastest method to grab a specific category!same as clk_df.EST.loc['AS'] but >6 times faster - AS_cat_code = clk_df.index.levels[0].categories.get_loc('AS') - mask = clk_df.index.codes[0] == AS_cat_code - return _pd.Series(data=clk_df.values[:,0][mask],index=clk_df.index.droplevel(0)[mask]) - -def rm_epoch_gnss_bias(clk_df_unst:_pd.DataFrame): - cols_original = clk_df_unst.columns.values - cols_gnss = cols_original.astype('_np.ndarray: - """ - Selects best common SVs per GNSS across two unstacked clk DataFrames e.g., G01 for GPS, R01 for GLO, E01 for GAL etc. - Procedure is based on the sum of STDs of each satellite clk offsets over the two DataFrames. - In addition, the selected SVs must not have gaps. - TODO might select SVs with smallest number of gaps if no single SV with continuous data is present. - - Parameters - ---------- - clk_a_unst : unstacked clk dataframe a - Input DataFrame a. - clk_b_unst : unstacked clk dataframe b - Input DataFrame b. - - Returns - ------- - bounds : ndarray - Returns array of single SV per constellation which are the best for normalisation. - """ - sum_std = clk_a_unst.std() + clk_b_unst.std() - sum_std.index = [sum_std.index,sum_std.index.values.astype('bytes: - _logging.info(f'computing checksum of "{path2file}"') - with open(path2file,'rb') as file: - filehash = _hashlib.md5() - while True: - data = file.read(8 * MB) - if len(data) == 0: - break - filehash.update(data) - checksum = _base64.b64encode(filehash.digest()).decode() - _logging.info(f'Got "{checksum}"') - return checksum \ No newline at end of file diff --git a/scripts/gn_lib/gn_io/discon.py b/scripts/gn_lib/gn_io/discon.py deleted file mode 100644 index 797cc5a46..000000000 --- a/scripts/gn_lib/gn_io/discon.py +++ /dev/null @@ -1,37 +0,0 @@ -'''Parser of frame discontinuity file''' -from io import BytesIO as _BytesIO - -import pandas as _pd -from pandas import CategoricalDtype as _CategoricalDtype - -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io - -MODEL_CATEGORY = _CategoricalDtype(categories = ['P','V','A','S','E','X']) - -def _read_discontinuities(path): - snx_bytes = _gn_io.common.path2bytes(path) - block = _gn_io.sinex._snx_extract_blk( - snx_bytes=snx_bytes, blk_name='SOLUTION/DISCONTINUITY', remove_header=True)[0] - out_df = _pd.read_csv(filepath_or_buffer=_BytesIO(block), - usecols=[0, 1, 2, 4, 5, 6], - delim_whitespace=True, - header=None, - names=['CODE', 'PT', 'SOLN', - 'BEGIN', 'END', 'MODEL'], - dtype={ - 0: object, 1: object, 2: object, - 4: object, 5: object, 6: MODEL_CATEGORY}) - - begin_j2000 = _gn_datetime.yydoysec2datetime(out_df['BEGIN'],as_j2000=True,recenter=False) - begin_j2000[begin_j2000 == -129600] = -999999999 - #overwriting 00:000:00000 values with new boundaries - - end_j2000 = _gn_datetime.yydoysec2datetime(out_df['END'],as_j2000=True,recenter=False) - end_j2000[end_j2000 == -129600] = 999999999 - - out_df['BEGIN'] = begin_j2000 - out_df['END'] = end_j2000 - # return out_df - # return out_df.set_index(out_df.CODE.values + out_df.PT.values + out_df.SOLN.values.astype(str)) - return out_df.set_index(out_df.CODE.values + '_' + out_df.PT.values) diff --git a/scripts/gn_lib/gn_io/igslog.py b/scripts/gn_lib/gn_io/igslog.py deleted file mode 100644 index ca1037dc1..000000000 --- a/scripts/gn_lib/gn_io/igslog.py +++ /dev/null @@ -1,467 +0,0 @@ -'''IGS log files parser''' -import glob as _glob -import re as _re -from multiprocessing import Pool as _Pool - -import numpy as _np -import pandas as _pd -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_frame as _gn_frame -from gn_lib import gn_io as _gn_io -from gn_lib import gn_transform as _gn_transform -from tqdm import tqdm - -_REGEX_ID = _re.compile(rb''' - (?:Four\sCharacter\sID|Site\sID)\s+\:\s*(\w{4}).*\W+ - .*\W+ - (?:\s{25}.+\W+|) - IERS.+\:\s*(\w{9}|) - ''', _re.IGNORECASE|_re.VERBOSE) - -_REGEX_LOC = _re.compile(rb''' - 2.+\W+City\sor\sTown\s+\:\s*(\w[^\(\n\,/\?]+|).*\W+ - State.+\W+Country\s+\:\s*([^\(\n\,\d]+|).*\W+(?:\s{25}.+\W+|) - Tectonic.+\W+(?:\s{25}.+\W+|).+\W+ - X.{22}\:?\s*([\d\-\+\.\,]+|).*\W+ - Y.{22}\:?\s*([\d\-\+\.\,]+|).*\W+ - Z.{22}\:?\s*([\d\-\+\.\,]+|).*\W+ - Latitude.+\:\s*([\d\.\,\-\+]+|).*\W+ - Longitud.+\:\s*([\d\.\,\-\+]+|).*\W+ - Elevatio.+\:\s*([\d\.\,\-\+]+|).* - ''', _re.IGNORECASE|_re.VERBOSE) - - -_REGEX_REC = _re.compile( rb''' - 3\.\d+[ ]+Receiver[ ]Type\W+\:[ ]*([\+\-\w\ ]+|)\W+ # Receiver Type line - (?:Satellite[ ]System[ ]+\:[ ]*(?:(.+|)[ ]*[\r\n ]+[ ]+)|) # Satellite System (normally present) - Serial[ ]Number[ ]+\:[ ]*(\w+|).*\W+ # Receiver S/N line - Firmware[ ]Version[ ]+\:[ ]*([\w\.\/ ]+|).*\W+ # Receiver Firmware Version line - ()()() # 3 empty groups to align with antenna block - (?:Elevation[ ]Cutoff\sSetting[ ]*\:[ ]*(?:.+|)|)\W+ # Elevation Cutoff Setting (normally present) - Date[ ]Installed\W+\:[ ]*(\d{4}.+|).*\W+ # Date Installed line - (?:Date[ ]Removed\W+\:(?:[ ]*(\d{4}.+|))|) # Date Removed line (normally present) - ''', _re.IGNORECASE|_re.VERBOSE) - -_REGEX_ANT = _re.compile( rb''' - 4\.\d+[ ]+Antenna[ ]Type\W+:[\t ]*([\/\_\S]+|)[ \t]*(\w+|)[\,?.]*\W+ # Antenna Type line - Serial[ ]Number[ ]+:[ ]*(\S+|\S+[ ]\S+|\S+[ ]\S+[ ]\S+|).*\W+ # Antenna S/N line - (?:Antenna[ ]Height.+\W+|) # Antenna H (normally present) - (?:Antenna[ ]Ref.+\W+|) # Antenna Ref. Point (normally present) - (?:Degree.+\W+|) # Degree offset line (rarely used) - (?:Marker->ARP[ ]Up.+\:[ ]*([\-\d\.]+|).*\W+ - Marker->ARP[ ]North.+\:[ ]*([\-\d\.]+|).*\W+ - Marker->ARP[ ]East.+\:[ ]*([\-\d\.]+|).*\W+|) # Marker Ecc block (normally present) - (?:Alignment.+[\n\r](?:[ ]{25}.+[\r\n]+|)\W+|) # Alignment from True N line (normally present) - Antenna[ ]Rad.+\:[ ]?(.+|)(?:\(.+\)|)\W+ # Antenna Radome Type line - (?:(?:(?:Rad|Antenna[ ]Rad).+\W+|) # Radome S/N or Antenna Radome S/N (normally present) - Ant.+[\n\r]+(?:[ ]{25}.+[\r\n]+|)\W+ # Antenna Cable Type line - Ant.+[\n\r]+(?:[ ]{25}.+[\r\n]+|)\W+|) # Antenna Cable Length line - Date[ ]Installed[ ]+\:[ ]*(\d{4}.+|).*\W+ # Date Installed line - (?:Date[ ]Removed[ ]+\:(?:[ ]*(\d{4}.+|))|) # Date Removed line (normally present) - ''', _re.IGNORECASE|_re.VERBOSE) - -_REGEX_LOGNAME = r'(?:.*\/)(\w{4})(?:\w+_(\d{8})|_(\d{8})\-?\w?|(\d{8})|_.*|\d+|)' - -def find_recent_logs(logs_glob_path:str,rnx_glob_path=None)->_pd.DataFrame: - '''Takes glob expression to get the list of log files, - parses names into site and date and selects the ones - with most recent date - /data/station_logs/station_logs_IGS/*/*.log - /data/acs/pea/proc/exs/data/*.rnx''' - paths = _pd.Series(_glob.glob(pathname=logs_glob_path,recursive=False),name='PATH') - - logs_df = paths.str.extract(expand=True,pat=_REGEX_LOGNAME) - logs_df = _pd.concat([ logs_df[0].str.upper(), - logs_df.iloc[:,1:].astype(float).sum(axis=1), - paths],axis=1) - logs_df.columns = ['CODE','DATE','PATH'] - logs_df = logs_df[~logs_df.CODE.isna()].sort_values(['CODE','DATE']) - recent_logs_df = logs_df[~logs_df.CODE.duplicated(keep='last')] - if rnx_glob_path is not None: - if isinstance(rnx_glob_path,list): - rnx_stations = rnx_glob_path - if isinstance(rnx_glob_path,str): - rnx_files = sorted(_glob.glob(rnx_glob_path)) - assert len(rnx_files)!=0, f"No rnx files were found using '{rnx_glob_path}'" - rnx_stations = _pd.Series(rnx_files).str.extract(r'(\w{4})[^\/]+$',expand=False).to_list() - return recent_logs_df[recent_logs_df.CODE.isin(rnx_stations).values] - return recent_logs_df - -def parse_igs_log(filename_array:_np.ndarray)->_np.ndarray: - '''Parses igs log and outputs ndarray with parsed data - Expects ndarray of the form [CODE DATE PATH]''' - file_code, __, file_path = filename_array - - with open(file_path, 'rb') as file: - data = file.read() - - blk_id = _REGEX_ID.search(data) - if blk_id is None: - tqdm.write(f'ID rejected from {file_path}') - return _np.array([]).reshape(0,12) - - blk_id = [blk_id[1].decode().upper(),blk_id[2].decode().upper()] #no .groups() thus 1 and 2 - code = blk_id[0] - if code!=file_code: - tqdm.write(f'{code}!={file_code} at {file_path}') - return _np.array([]).reshape(0,12) - - blk_loc = _REGEX_LOC.search(data) - if blk_loc is None: - tqdm.write(f'LOC rejected from {file_path}') - return _np.array([]).reshape(0,12) - - blk_rec = _REGEX_REC.findall(data) - if blk_rec == []: - tqdm.write(f'REC rejected from {file_path}') - return _np.array([]).reshape(0,12) - - blk_ant = _REGEX_ANT.findall(data) - if blk_ant == []: - tqdm.write(f'ANT rejected from {file_path}') - return _np.array([]).reshape(0,12) - - blk_loc = [group.decode(encoding='utf8',errors='ignore') for group in blk_loc.groups()] - blk_rec = _np.asarray(blk_rec,dtype=str) - blk_ant = _np.asarray(blk_ant,dtype=str) - - len_recs = blk_rec.shape[0] - len_ants = blk_ant.shape[0] - - blk_id_loc = _np.asarray([0] + blk_id + blk_loc,dtype=object)[_np.newaxis] - - code = [code] - blk_rec = _np.concatenate([_np.asarray([1]*len_recs,dtype=object)[:,_np.newaxis], - _np.asarray(code*len_recs,dtype=object)[:,_np.newaxis], - blk_rec,],axis=1) - blk_ant = _np.concatenate([_np.asarray([2]*len_ants,dtype=object)[:,_np.newaxis], - _np.asarray(code*len_ants,dtype=object)[:,_np.newaxis], - blk_ant,],axis=1) - blk_uni = _np.concatenate([blk_id_loc,blk_rec,blk_ant],axis=0) - file_path_arr = _np.asarray([file_path]*(1+len_ants+len_recs))[:,_np.newaxis] - return _np.concatenate([blk_uni,file_path_arr],axis=1) - - -def igslogdate2datetime64(stacked_rec_ant_dt:_np.ndarray): - '''2010-01-01T00:00 - - can be any non-space character. If parsing fails - None''' - dt_array_float = (_pd.Series(stacked_rec_ant_dt) - .str.extract(pat=r'(\d{4})\S?(\d{2})\S?(\d+)\D?(?:(\d{1,2})\:(\d{1,2})\D?|)') - .values.astype(float)) - - dt_array_float[_np.isnan(dt_array_float[:,0])] = [2100.,1.,1.,0.,0.] - hh_mm = dt_array_float[:,[3,4]] - hh_mm[_np.isnan(hh_mm[:,0])] = [0,0] - dt_array_float[:,[3,4]] = hh_mm - dt_array_int = dt_array_float.astype(int) - - wrong_31 = (_pd.Series(dt_array_int[:,1]).isin([4,6,9,11]).values) & (dt_array_int[:,2] > 30) - wrong_30 = (dt_array_int[:,1]==2) & (_pd.Series(dt_array_int[:,2]) > 29) - - valid_mask = ((dt_array_int[:,3]<24) - & (dt_array_int[:,4] < 60) - & (dt_array_int[:,2] < 32) - & (dt_array_int[:,2] > 0) - & (dt_array_int[:,1] < 13) - & (dt_array_int[:,1] > 0) - & ~wrong_31 - & ~wrong_30).values - - - dt_datetime64 = _np.empty(dt_array_int.shape[0],dtype='datetime64[m]') - dt_datetime64.fill(_np.NaN) - - df_dt_valid = _pd.DataFrame(dt_array_int[valid_mask],dtype=str) - dt_datetime64[valid_mask] = (df_dt_valid[0].str.zfill(4) - + '-'+ df_dt_valid[1].str.zfill(2) - + '-'+ df_dt_valid[2].str.zfill(2) - + ' '+ df_dt_valid[3].str.zfill(2) - + ':'+ df_dt_valid[4].str.zfill(2) ).values.astype('datetime64') - return dt_datetime64 - - - -def translate_series(series,translation): - '''changes values in the series according to the dictionary of old_value-new_value''' - series = series.copy() - series.index = series.values - series.update(translation) - return series - -def gather_metadata(logs_glob_path = '/data/station_logs/station_logs_IGS/*/*.log', - rnx_glob_path=None, - num_threads=1): - '''parses logiles found with glob expression''' - parsed_filenames = find_recent_logs(logs_glob_path=logs_glob_path, - rnx_glob_path=rnx_glob_path).values - - total = parsed_filenames.shape[0] - if num_threads == 1: - gather = [] - for file in tqdm(parsed_filenames,miniters=total//100,total=total): - gather.append(parse_igs_log(file)) - else: - with _Pool(processes=num_threads) as pool: - gather = list(tqdm(pool.imap_unordered(parse_igs_log, parsed_filenames), - total=total, miniters=total//100)) - - gather_raw = _np.concatenate(gather) - - rec_ant_mask = gather_raw[:, 0] != 0 # id_loc = 0, rec = 1, ant = 2 - gather_id_loc = gather_raw[~rec_ant_mask][:, 1:] - gather = gather_raw[rec_ant_mask] - - stacked_rec_ant_dt = _np.concatenate( - [gather[:, -3], gather[:, -2]], axis=0) - - stacked_rec_ant_dt = igslogdate2datetime64(stacked_rec_ant_dt) - snx_date = _gn_datetime.datetime2yydoysec(stacked_rec_ant_dt) - - gather = _np.concatenate([gather, snx_date.reshape(2, gather.shape[0]).T], axis=1) - stacked_rec_ant_dt_beg_end = stacked_rec_ant_dt.reshape(2, gather.shape[0]) # also deals with nans as no equal sign - # same foes for station start being empty as it becomes year 2100 - valid_mask_dt = stacked_rec_ant_dt_beg_end[0] < stacked_rec_ant_dt_beg_end[1] - - bad_dt_stations = _np.unique(gather[~valid_mask_dt][:, 1]) - - rec_mask = gather[:, 0] == 1 - rec_df = _pd.DataFrame( _np.delete(arr=gather[rec_mask], axis=1, obj=[0, 6, 7, 8]), - columns=['CODE','RECEIVER','GNSS','S/N','FW','BEGIN_RAW','END_RAW', - 'PATH','BEGIN_SNX','END_SNX']) - ant_df = _pd.DataFrame( gather[~rec_mask][:, 1:], - columns=['CODE','ANTENNA','RADOME','S/N','EccU','EccN','EccE', - 'RADOME2','BEGIN_RAW','END_RAW','PATH','BEGIN_SNX', 'END_SNX']) - - # ID LOC - id_loc_df = _pd.DataFrame(gather_id_loc,columns=['CODE','DOMES_N','CITY','COUNTRY', - 'X','Y','Z','LAT','LON','HEI','PATH']) - - id_loc_df.CITY[id_loc_df.CITY == ''] = 'N/A' - id_loc_df.CITY = id_loc_df.CITY.str.rstrip().str.upper() - id_loc_df.COUNTRY = translate_series(id_loc_df.COUNTRY.str.rstrip().str.upper(), - _gn_io.aux_dicts.translation_country).values - id_loc_df.DOMES_N[id_loc_df.DOMES_N == ''] = '---------' - - - xyz_array = (id_loc_df[['X','Y','Z']].stack() - .str.replace(',','.') - .replace({'':None}) - .unstack().values.astype(float)) - - - valid_mask = _np.all((( xyz_array != 0) & ~_np.isnan(xyz_array)),axis=1) - - xyz_norm = (xyz_array[valid_mask] ** 2).sum(axis=1) **0.5 - valid_mask[valid_mask] = (xyz_norm > 6000000) &(xyz_norm < 6500000) - - - llh = _gn_transform.xyz2llh_heik(xyz_array[valid_mask],deg=True) - llh_snx = _gn_io.sinex.llh2snxdms(llh) - - llh2 = id_loc_df[~valid_mask][['LAT','LON','HEI']] - llh2_snx = _gn_io.sinex.logllh2snxdms(llh2) - snxdms = _np.empty(valid_mask.shape,dtype=object) - snxdms[valid_mask] = llh_snx - # snxdms[valid_mask] =' 000 00 00.0 00 00 00.0 000.0' - snxdms[~valid_mask] = llh2_snx# - # snxdms[~valid_mask] = ' 000 00 00.0 00 00 00.0 000.0'#llh2_snx - # bad_loc_stations = id_loc_df.CODE[snxdms == ''].values - id_loc_df['LOC'] = snxdms - - ecc = ant_df[['EccU','EccN','EccE']].values - ecc[ecc == ''] = 0 - ant_df[['EccU','EccN','EccE']] = ecc.astype(float) - - rec_df.RECEIVER = rec_df.RECEIVER.str.rstrip().str.upper() - ant_df.ANTENNA = ant_df.ANTENNA.str.rstrip().str.upper() - ant_df.RADOME = ant_df.RADOME.str.rstrip().str.upper() - ant_df.RADOME2 = ant_df.RADOME2.str.rstrip().str.upper() - - no_rad2_mask = ~ant_df.RADOME.isin(_gn_io.aux_dicts.atx_rad_tbl) - ant_df.RADOME[no_rad2_mask] = ant_df.RADOME2[no_rad2_mask] - # translation_ant.index.name= None - antennas = translate_series(ant_df.ANTENNA,_gn_io.aux_dicts.translation_ant) - invalid_ant_mask = ~antennas.index.isin(_gn_io.aux_dicts.atx_ant_tbl) - bad_antenna_stations = ant_df[invalid_ant_mask]['CODE'].unique() - - receivers = translate_series(rec_df.RECEIVER,_gn_io.aux_dicts.translation_rec) - invalid_rec_mask = ~receivers.index.isin(_gn_io.aux_dicts.igs_rec_tbl) - bad_rec_stations = rec_df[invalid_rec_mask]['CODE'].unique() - - radomes = translate_series(ant_df.RADOME,_gn_io.aux_dicts.translation_rad) - - invalid_radomes_mask = ~radomes.index.isin(_gn_io.aux_dicts.atx_rad_tbl) - bad_radome_stations = ant_df[invalid_radomes_mask]['CODE'].unique() - - ant_df.ANTENNA = antennas.values - ant_df.RADOME = radomes.values - rec_df.RECEIVER = receivers.values - - bad_stations = _np.unique(bad_dt_stations.tolist() - + bad_radome_stations.tolist() - + bad_antenna_stations.tolist() - + bad_rec_stations.tolist()) - - rec_df = rec_df[~rec_df.CODE.isin(bad_stations)].copy() - ant_df = ant_df[~ant_df.CODE.isin(bad_stations)].copy() - id_loc_df = id_loc_df[~id_loc_df.CODE.isin(bad_stations)].copy() - - return id_loc_df,rec_df,ant_df - -def frame2snx_string(frame_of_day): - '''frame_of_day dataframe to ESTIMATE sinex block''' - code_pt =frame_of_day.index.to_series().str.split('_',expand=True)#.to_frame().values - code_pt.columns = ['CODE','PT'] - frame_dt = _gn_datetime.j20002datetime(frame_of_day.attrs['REF_EPOCH']) - frame = _pd.concat([frame_of_day,code_pt],axis=1)#.reindex() - frame_est = frame[['STAX','STAY','STAZ']].stack(0).to_frame().reset_index(level=1) - frame_est.columns = ['TYPE','EST'] - frame = frame_est.join(frame[['SOLN','CODE','PT']]) - - dt_snx = _gn_datetime.datetime2yydoysec(frame_dt) - - frame.reset_index(drop=True,inplace=True) - frame['STD'] = 0 - frame['INDEX'] = (frame.index +1) - frame.SOLN = frame.SOLN.apply(r'{:>4}'.format) - - epoch_str_series = (' ' + frame.CODE + ' ' + frame.PT + ' ' + frame.SOLN - + ' C 00:000:00000 00:000:00000 ' + dt_snx + '\n').to_list() - - frame_str_series =(frame.INDEX.apply(r'{:6} '.format) - + frame.TYPE + ' ' + frame.CODE + ' ' + frame.PT + ' ' - + frame.SOLN + ' ' + dt_snx + ' m 2 ' - + frame.EST.apply(r'{:>21.14E}'.format) + ' 0.00000E+00\n').to_list() - - buf = ( - ['*-------------------------------------------------------------------------------\n'] - + ['+SOLUTION/EPOCHS\n'] - + ['*CODE PT SOLN T _DATA_START_ __DATA_END__ _MEAN_EPOCH_\n'] - + epoch_str_series - + ['-SOLUTION/EPOCHS\n'] - + ['*-------------------------------------------------------------------------------\n'] - + ['+SOLUTION/ESTIMATE\n'] - + ['*INDEX _TYPE_ CODE PT SOLN _REF_EPOCH__ UNIT S ___ESTIMATED_VALUE___ __STD_DEV__\n'] - + frame_str_series - + ['-SOLUTION/ESTIMATE\n']) - - return buf - -def meta2sting(id_loc_df,rec_df,ant_df): - '''Converts three metadata dataframe to sinex blocks (string)''' - rec_df['S/N'] = rec_df['S/N'].str.slice(0,5) - rec_df['FW'] = rec_df['FW'].str.slice(0,11) - - ant_df['S/N'] = ant_df['S/N'].str.slice(0,5) - ant_df.ANTENNA = ant_df.ANTENNA.str.ljust(15)#(r'{:15s}'.format) - ant_df.RADOME = ant_df.RADOME.str.ljust(4) - ant_df[['EccU','EccN','EccE']] = ant_df[['EccU','EccN','EccE']].applymap(r'{0:8.4f}'.format) - - location = (id_loc_df.CITY.str.slice(0,16).str.rstrip() + ', ' - + id_loc_df.COUNTRY).str.slice(0,22).str.ljust(22,' ').values - - id_str_list = (' ' + id_loc_df.CODE.values + ' A ' + id_loc_df.DOMES_N.values + ' P ' - + location + id_loc_df.LOC.values + '\n').tolist() - - rec_str_list = (' ' + rec_df.CODE + ' A ---- P ' - + rec_df.BEGIN_SNX + ' ' + rec_df.END_SNX + ' ' + - + rec_df.RECEIVER.str.ljust(20,' ') + ' ' - + rec_df['S/N'].str.ljust(5,' ') + ' ' + rec_df.FW+'\n').to_list() - - ant_str_list = (' ' + ant_df.CODE + ' A ---- P ' - + ant_df.BEGIN_SNX + ' ' + ant_df.END_SNX + ' ' - + ant_df.ANTENNA + ' ' + ant_df.RADOME + ' ' - + ant_df['S/N'] +'\n').to_list() - - ecc_str_list = (' ' + ant_df.CODE + ' A ---- P ' - + ant_df.BEGIN_SNX + ' ' + ant_df.END_SNX - + ' UNE ' + ant_df.EccU +' '+ ant_df.EccN +' ' + ant_df.EccE +'\n').to_list() - - buf = ( - ['*-------------------------------------------------------------------------------\n'] - + ['+SITE/ID\n'] - + ['*CODE PT __DOMES__ T _STATION DESCRIPTION__ APPROX_LON_ APPROX_LAT_ _APP_H_\n'] - + id_str_list + ['-SITE/ID\n'] - - + ['*-------------------------------------------------------------------------------\n'] - + ['+SITE/RECEIVER\n'] - + ['*SITE PT SOLN T DATA_START__ DATA_END____ DESCRIPTION_________ S/N__ FIRMWARE___\n'] - + rec_str_list + ['-SITE/RECEIVER\n'] - - + ['*-------------------------------------------------------------------------------\n'] - + ['+SITE/ANTENNA\n' ] - + ['*SITE PT SOLN T DATA_START__ DATA_END____ DESCRIPTION_________ S/N__\n'] - + ant_str_list + ['-SITE/ANTENNA\n' ] - - + ['*-------------------------------------------------------------------------------\n'] - + ['+SITE/ECCENTRICITY\n'] - + ['*SITE PT SOLN T DATA_START__ DATA_END____ AXE UP______ NORTH___ EAST____\n'] - + ecc_str_list + ['-SITE/ECCENTRICITY\n']) - - return buf - -def write_meta_gather_master(logs_glob_path='/data/station_logs/*/*.log', - rnx_glob_path='/data/acs/pea/proc/exs/data/*.rnx', - frame_datetime=None, - frame_snx_path='/data/ITRF/itrf2014/ITRF2014-IGS-TRF.SNX.gz', - frame_soln_path='/data/ITRF/itrf2014/ITRF2014-soln-gnss.snx', - frame_psd_path='/data/ITRF/itrf2014/ITRF2014-psd-gnss.snx', - out_path = '/data/meta_gather.snx', - num_threads = None): - - if frame_datetime is None: - frame_datetime = _np.datetime64('today') - else: frame_datetime =_np.datetime64(frame_datetime) - - id_loc_df, rec_df, ant_df = gather_metadata(logs_glob_path=logs_glob_path, - rnx_glob_path=rnx_glob_path, - num_threads=num_threads) - - sites_meta = rec_df.CODE.unique() - - gather_itrf = None - if (frame_snx_path is not None) and (frame_soln_path is not None): - gather_itrf = _gn_frame.get_frame_of_day(frame_datetime, - itrf_path_or_df=frame_snx_path, - list_path_or_df=sites_meta, - discon_path_or_df = frame_soln_path, - psd_path_or_df = frame_psd_path) - - - buf = [] - #gen header - gather_dt = _gn_datetime.datetime2yydoysec(frame_datetime) - trf_header = '' - if gather_itrf is not None: - trf_header += ( - f'of which {gather_itrf.shape[0]} were projected to {frame_datetime} using:\n' - +f'Frame: {frame_snx_path}\n' - +f'Discon:{frame_soln_path}\n' - +f'PSD: {frame_psd_path}\n') - - - buf.extend([f'%=SNX 2.01 IGS {gather_dt} IGS 00:000:00000 00:000:00000 P 00000 0\n' - +'+FILE/REFERENCE\n' - +'DESCRIPTION merged metadata\n' - +'OUTPUT historical sinex header file\n' - +'CONTACT bogdan.matviichuk@ga.gov.au\n' - +'SOFTWARE LOG2SNX v0.1.2\n' - +'HARDWARE AWS\n' - +'INPUT igs ftp site logs\n' - +'-FILE/REFERENCE\n' - +'+FILE/COMMENT\n' - +f'Metadata extracted from {sites_meta.shape[0]} station logs\n' - + trf_header - +'-FILE/COMMENT\n' - +'+INPUT/ACKNOWLEDGMENTS\n' - +'IGS International GNSS Service, GA\n' - +'-INPUT/ACKNOWLEDGMENTS\n']) - #ant/rec - buf.extend(meta2sting(id_loc_df,rec_df,ant_df)) - #projected coordinates - if gather_itrf is not None: - buf.extend(frame2snx_string(gather_itrf)) - buf.extend([f'%ENDSNX\n']) - - with open(out_path,'w') as file: - file.write(''.join(buf)) \ No newline at end of file diff --git a/scripts/gn_lib/gn_io/ionex.py b/scripts/gn_lib/gn_io/ionex.py deleted file mode 100644 index 30438b0e5..000000000 --- a/scripts/gn_lib/gn_io/ionex.py +++ /dev/null @@ -1,73 +0,0 @@ -import re as _re - -import numpy as _np -import pandas as _pd - -from gn_lib import gn_io as _gn_io -from gn_lib import gn_datetime as _gn_datetime - -_RE_BLKS= _re.compile(rb'H\n((?:[ \-\d]+\n)+)',_re.MULTILINE) - -def gen_range(head,param_name): - '''Extracts a group of three parameters as "LAT1 / LAT2 / DLAT" and constructs a range''' - head_lon = head.find(param_name) - head_lon_lineb = head[:head.find(param_name)].rfind(b'\n') + 1 - lon1, lon2, dlon = head[head_lon_lineb:head_lon].split() - lon1 = float(lon1); lon2 = float(lon2); dlon = float(dlon) - return _np.arange(lon1,lon2+(0.1 if dlon>0 else -0.1),dlon) - -def get_param(head,param_name): - '''Extracts single parameter (first) from the header''' - param_loc = head.find(param_name) - param_line_begin = head[:head.find(param_name)].rfind(b'\n') + 1 - return float(head[param_line_begin:param_loc].split()[0]) - -def read_ionex(path_or_bytes): - '''Exponent is extracted into dataframe attribute''' - data = _gn_io.common.path2bytes(path_or_bytes) - end_of_head = data.find(b'END OF HEADER') + 13 - - head = data[:end_of_head] - data = data[end_of_head:] - - maps_heads = find_all(data,b'START',window=[9,60]) # type + epoch info - maps_heads_arr = _np.asarray(b''.join(maps_heads).split()).reshape(len(maps_heads),-1) - # return maps_heads - datetime = strdatetime2datetime(maps_heads_arr[:,2:],as_j2000=True) - maps_type = maps_heads_arr[:,0].astype(str) - - exp = get_param(head,b'EXPONENT') - - maps_arr = _np.asarray(b''.join(_RE_BLKS.findall(data)).replace(b'\n',b''))[_np.newaxis].view('S5').astype(int) * 10**exp - - lon_arr = gen_range(head,b'LON1 ') - lat_arr = gen_range(head,b'LAT1 ') - df = _pd.DataFrame(data = maps_arr.reshape(-1,lon_arr.shape[0]), - index = [_np.repeat(datetime,lat_arr.shape[0]),_np.repeat(maps_type,lat_arr.shape[0]),_np.tile(lat_arr,maps_type.shape[0])], - columns = lon_arr) - df.index.names = ['DateTime','Type','Lat'] #for convenience + nice to have in the diff util output - df.columns.names = ['Lon'] - df.attrs['EXPONENT'] = exp - return df - -def find_all(data,pat,window): - buf = [] - find = data.find(pat) - while find!=-1: - buf.append(data[find+window[0]:find+window[1]]) - find = data.find(pat,find+len(pat)) - return buf - -def strdatetime2datetime(dt_arr, as_j2000=True): - '''ndarray of Y M D h m s to datetime64''' - datetime = (dt_arr[:,0].astype('datetime64[M]') - + (dt_arr[:,1].astype('timedelta64[M]') - 1) - + (dt_arr[:,2].astype('timedelta64[D]') - 1) - - + (dt_arr[:,3].astype('timedelta64[h]')) - + (dt_arr[:,4].astype('timedelta64[m]')) - + (dt_arr[:,5].astype('timedelta64[s]'))) - - if as_j2000: - return _gn_datetime.datetime2j2000(datetime) - return datetime \ No newline at end of file diff --git a/scripts/gn_lib/gn_io/pea.py b/scripts/gn_lib/gn_io/pea.py deleted file mode 100644 index 81e7b99d3..000000000 --- a/scripts/gn_lib/gn_io/pea.py +++ /dev/null @@ -1,16 +0,0 @@ -from io import BytesIO as _BytesIO - -import pandas as _pd -from gn_lib import gn_const as _gn_const -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io - - -def read_pea_partials(path): - partials = _gn_io.common.path2bytes(path) - begin = partials.find(b"End_of_Header") + 13 - df = _pd.read_csv(_BytesIO(partials[begin:]),header=None,delim_whitespace=True,usecols=[0,1,2,9,10,11],names=[None,'MJD','TOD','X','Y','Z']) - df_done = df[['X','Y','Z']].set_index([_gn_datetime.mjd2j2000(df.MJD.values,df.TOD.values,pea_partials=True),df.iloc[:,0].astype(_gn_const.PRN_CATEGORY)]) - df_partials = _pd.concat([df_done],keys=['EST'],axis=1)/1000 - df_partials.attrs['path'] = path - return df_partials diff --git a/scripts/gn_lib/gn_io/pod.py b/scripts/gn_lib/gn_io/pod.py deleted file mode 100644 index 3f027982b..000000000 --- a/scripts/gn_lib/gn_io/pod.py +++ /dev/null @@ -1,27 +0,0 @@ -import re as _re - -import numpy as _np -import pandas as _pd - -from gn_lib import gn_const as _gn_const -from gn_lib import gn_io as _gn_io - -_POD_ITRF_RMS = _re.compile(r"RMS-XYZ ITRF CMP[ ]*([A-Z\d]+)[ ]+([\d\.]+)[ ]+([\d\.]+)[ ]+([\d\.]+)") - -def pod_get_IC_dt(pod_out:bytes)->int: - begin = pod_out.find(b"IC Epoch:") + 9 - end = pod_out.find(b"\n",begin) - date = _pd.Series(pod_out[begin:end].strip().decode()).str.split(pat=r"\s+") - year,month,day,frac = date.tolist()[0] - dt_value = (_np.datetime64('-'.join([year,month.zfill(2),day])) - _gn_const.J2000_ORIGIN).astype(int) - return dt_value + int(86400*float(frac)) - -def read_pod_out(path): - """reads pod.out file. No SV categories implemented as file is small""" - content = _gn_io.common.path2bytes(path) - df = _pd.DataFrame( - data=_POD_ITRF_RMS.findall(content.decode()), #working with string not bytes - columns=['SV','X','Y','Z'] - ) - return df.set_index([[pod_get_IC_dt(content)]*df.shape[0],'SV']).astype(float) - diff --git a/scripts/gn_lib/gn_io/psd.py b/scripts/gn_lib/gn_io/psd.py deleted file mode 100644 index 071a6143c..000000000 --- a/scripts/gn_lib/gn_io/psd.py +++ /dev/null @@ -1,13 +0,0 @@ -'''ITRF2014+ postseismic deformation file''' -from gn_lib import gn_io as _gn_io - -def _get_psd_df(psd_snx_path): - '''we ignore the monument''' - psd_df = _gn_io.sinex._get_snx_vector(path_or_bytes=psd_snx_path,stypes=['EST'],snx_format=None) - # a['CODE_PT']=a.CODE.values + '_' + a.PT.values.astype(object) - #monument is always A in psd file, cumcount is used as index if n - # parameters of the same type are present for the same event - psd_df['key']=psd_df.groupby(['CODE','REF_EPOCH','TYPE']).cumcount() - psd_df = psd_df.set_index(['TYPE','CODE','REF_EPOCH','key'])['EST'].unstack(0) - psd_df.columns = psd_df.columns.astype(object).str.split('_',expand=True) - return psd_df diff --git a/scripts/gn_lib/gn_io/rinex.py b/scripts/gn_lib/gn_io/rinex.py deleted file mode 100644 index ceb7a032f..000000000 --- a/scripts/gn_lib/gn_io/rinex.py +++ /dev/null @@ -1,85 +0,0 @@ -'''IO functions for reading RINEX files ''' - -import re as _re -from io import BytesIO as _BytesIO - -import numpy as _np -import pandas as _pd -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io - -_RE_RNX = _re.compile(rb'^\>(.+)\n((?:[^\>]+)+)',_re.MULTILINE) -_RE_RNX_HEADER = _re.compile(rb'\n(\w)\s+(\d+)(.+)OBS\sTYPES((?:\W\s{6}.+|))') -_RE_RNX_POSITION = _re.compile(rb'\n(.+)APPROX\sPOSITION\sXYZ') - -def _read_rnx(rnx_path): - '''Read RINEX file into pandas DataFrame taking into account - the signal strength and loss-of-lock field keys. - Assumes that rinex had been previously Hatanaka decompressed''' - rnx_content = _gn_io.common.path2bytes(str(rnx_path)) - data_blocks = _np.asarray(_RE_RNX.findall(string=rnx_content)) - header_blocks = _RE_RNX_HEADER.findall(string=rnx_content) - - header_blocks = _pd.DataFrame(_np.asarray(header_blocks).astype(str)) - rnx_head = (header_blocks[2] + header_blocks[3]).str.extractall(pat=r'(\w\d\w)',).squeeze() - - cols = rnx_head.count(level=0).max() - - rnx_head = rnx_head.unstack().set_index(header_blocks[0]) - dates = data_blocks[:,0] - data = data_blocks[:,1] - counts = _np.char.count(data, b'\n') - - epochs_dt = _pd.to_datetime(_pd.Series(dates).str.slice(1,20).values.astype(str), - format=r'%Y %m %d %H %M %S') - - dt_index = _np.repeat(a=_gn_datetime.datetime2j2000(epochs_dt),repeats=counts) - b_string = b''.join(data.tolist()) - - b_series = _pd.Series(b_string.splitlines()) - - data_raw = b_series.str[3:] - missing = (16*cols - data_raw.str.len()).values.astype(object) #has to be square for method to work - - m = (data_raw.values + missing*b' ').astype(bytes).view('S16').reshape((cols,-1)) - rnx_df = rnx_vals2df(m) - prn = b_series.str[:3].values.astype(str) - prn_code = prn.astype('U1') - rnx_df = rnx_df.set_index([dt_index,prn]) - rnx_df.columns = _pd.MultiIndex.from_product([list(range(cols)),['EST','STRG']]) - - buf = [] - for constel in rnx_head.index: - gnss_df = rnx_head.loc[constel] - n_cols_gnss = gnss_df[~gnss_df.isna()].shape[0] - gnss_rnx_df = rnx_df[(prn_code == gnss_df.name)] - valid_columns = (gnss_rnx_df.loc(axis=1)[:,'EST'] - .columns.get_level_values(0)[:n_cols_gnss]) - - gnss_rnx_df = gnss_rnx_df[valid_columns].copy() - gnss_rnx_df.columns = _pd.MultiIndex.from_product([gnss_df[~gnss_df.isna()].to_list(),['EST','STRG']]) - buf.append(gnss_rnx_df) - return _pd.concat(buf,keys=rnx_head.index,axis=0) - -def rnx_vals2df(m): - m_flat = m.flatten() - t1 = m_flat.astype('S14')[:,_np.newaxis] - t1[t1 == b' ']= b'' - t2 = m_flat.astype(bytes).view(('S1')).reshape(m_flat.shape[0],-1)[:,15:16] - t2[t2 == b' '] = b'' - t3 = _np.hstack([t1,t2]).astype(object) - t3[t3 == b'']= _np.NaN - rnx_df = _pd.DataFrame(t3.astype(float,).reshape([m.shape[1], m.shape[0]*2])) - return rnx_df - -def _rnx_pos(rnx_path): - '''Read RINEX file and output APPROX POSITION''' - rnx_content = _gn_io.common.path2bytes(str(rnx_path)) - pos_line = _RE_RNX_POSITION.findall(string=rnx_content) - coords = [] - for val in pos_line[0].decode("utf-8").split(' '): - try: - coords.append(float(val)) - except ValueError: - continue - return _np.array(coords).reshape(3,1) \ No newline at end of file diff --git a/scripts/gn_lib/gn_io/sinex.py b/scripts/gn_lib/gn_io/sinex.py deleted file mode 100644 index 5ad91c5e4..000000000 --- a/scripts/gn_lib/gn_io/sinex.py +++ /dev/null @@ -1,478 +0,0 @@ -'''IO functions for various formats used: trace, sinex etc ''' - -import logging as _logging -import re as _re -import zlib as _zlib -from io import BytesIO as _BytesIO - -import numpy as _np -import pandas as _pd - -from gn_lib import gn_const as _gn_const -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io - -_RE_BLK_HEAD = _re.compile(rb"\+S\w+\/\w+(\s[LU]|)\s*(CORR|COVA|INFO|)[ ]*\n(?:\*[ ].+\n|)(?:\*\w.+\n|)") -_RE_STATISTICS = _re.compile(r"^[ ]([A-Z (-]+[A-Z)])[ ]+([\d+\.]+)", _re.MULTILINE) - -def _get_valid_stypes(stypes): - '''Returns only stypes in allowed list - Fastest if stypes size is small''' - allowed_stypes = ['EST','APR', 'NEQ'] - stypes = set(stypes) if not isinstance(stypes,set) else stypes - ok_stypes = sorted(stypes.intersection(allowed_stypes),key=allowed_stypes.index) # need EST to always be first - if len(ok_stypes) != len(stypes): - not_ok_stypes = stypes.difference(allowed_stypes) - _logging.error(f'{not_ok_stypes} not supported') - return ok_stypes - -def _snx_extract_blk(snx_bytes, blk_name, remove_header=False): - ''' - Extracts a blk content from a sinex databytes using the + and - blk_name bounds - Works for both vector and matrix blks. - Returns blk content (with or without header), count of content lines (ignooring the header), - matrix form [L or U] and matrix content type [INFO, COVA, CORR]. - The latter two are empty in case of vector blk''' - blk_begin = snx_bytes.find(f'+{blk_name}'.encode()) - blk_end = snx_bytes.find(f'-{blk_name}'.encode(), blk_begin) - if blk_begin == -1: - _logging.info(f'{blk_name} blk missing') - return None #if there is no block begin bound -> None is returned - if blk_end == -1: - _logging.info(f'{blk_name} blk corrupted') - return None - - head_search = _RE_BLK_HEAD.search(string=snx_bytes, pos=blk_begin) - ma_form, ma_content = head_search.groups() - - blk_content = snx_bytes[head_search.end():blk_end] - # blk content without header (usual request) - lines_count = blk_content.count(b'\n') - if lines_count == 0: - _logging.error(f'{blk_name} blk is empty') - return None - - #may be skipped for last/first block (TODO) - if not remove_header: - blk_content = snx_bytes[head_search.span(2)[1]:blk_end] - # if header requested (1st request only) - return blk_content, lines_count, ma_form.decode(), ma_content.decode() - # ma_form, ma_content only for matrix - -def _snx_extract(snx_bytes, stypes, obj_type, verbose=True): - # obj_type= matrix or vector - if obj_type == 'MATRIX': - stypes_dict = { - 'EST': 'SOLUTION/MATRIX_ESTIMATE', - 'APR': 'SOLUTION/MATRIX_APRIORI', - 'NEQ': 'SOLUTION/NORMAL_EQUATION_MATRIX' - } - elif obj_type == 'VECTOR': - stypes_dict = { - 'EST': 'SOLUTION/ESTIMATE', - 'APR': 'SOLUTION/APRIORI', - 'NEQ': 'SOLUTION/NORMAL_EQUATION_VECTOR', - 'ID' : 'SITE/ID' - } - - snx_buffer = b'' - stypes_form, stypes_content, stypes_rows = {}, {}, {} - objects_in_buf = 0 - for stype in stypes: - if stype in stypes_dict.keys(): - remove_header = objects_in_buf != 0 - if (objects_in_buf == 0) & (obj_type == 'MATRIX'): # override matrix header as comments may be present - snx_buffer+=b'*PARA1 PARA2 ____PARA2+0__________ ____PARA2+1__________ ____PARA2+2__________\n' - remove_header = True - stype_extr = _snx_extract_blk(snx_bytes=snx_bytes, - blk_name=stypes_dict[stype], - remove_header= remove_header) - if stype_extr is not None: - snx_buffer += stype_extr[0] - stypes_rows[stype] = stype_extr[1] - stypes_form[stype] = stype_extr[2] #dict of forms - stypes_content[stype] = stype_extr[3] #dict of content - objects_in_buf += 1 - else: - _logging.error(f'{stype} ({stypes_dict[stype]}) blk not found') - # return None - objects_in_buf += 1 - - else: - if verbose: - _logging.error(f'{stype} blk not supported') - stypes = list(stypes_rows.keys()) - n_stypes = len(stypes) #existing stypes only - if n_stypes == 0: - if verbose: - _logging.error('nothing found') - return None - return _BytesIO(snx_buffer), stypes_rows, stypes_form, stypes_content - -def get_variance_factor(path_or_bytes): - snx_bytes = _gn_io.common.path2bytes(path_or_bytes) - stat_bytes = _snx_extract_blk( - snx_bytes=snx_bytes, blk_name="SOLUTION/STATISTICS", remove_header=True - ) - if stat_bytes is not None: - stat_dict = dict(_RE_STATISTICS.findall(stat_bytes[0].decode())) - if "VARIANCE FACTOR" in stat_dict.keys(): - return float(stat_dict["VARIANCE FACTOR"]) - wsqsum = ( - float(stat_dict["WEIGHTED SQUARE SUM OF O-C"]) - if "WEIGHTED SQUARE SUM OF O-C" in stat_dict.keys() - else float(stat_dict["SQUARED SUM OF RESIDUALS"]) - ) - if "DEGREES OF FREEDOM" in stat_dict.keys(): - return wsqsum / float(stat_dict["DEGREES OF FREEDOM"]) - else: - return wsqsum / ( - float(stat_dict["NUMBER OF OBSERVATIONS"]) - - float(stat_dict["NUMBER OF UNKNOWNS"])) - -def _get_snx_matrix(path_or_bytes, - stypes=('APR', 'EST'), - verbose=True): - ''' - stypes = "APR","EST","NEQ" - APRIORY, ESTIMATE, NORMAL_EQUATION - Would want ot extract apriori in the very same run with only single parser call - If you use the INFO type this block should contain the normal equation matrix of the - constraints applied to your solution in SOLUTION/ESTIMATE. - n_elements is useful for the igs sinex files when matrix has missing end rows.\ - Fetch it from estimates vector - ''' - if isinstance(path_or_bytes, str): - snx_bytes = _gn_io.common.path2bytes(path_or_bytes) - else: - snx_bytes = path_or_bytes - - n_elements = int(snx_bytes[60:65]) - - extracted = _snx_extract(snx_bytes=snx_bytes, - stypes=stypes, - obj_type='MATRIX', - verbose=verbose) - if extracted is not None: - snx_buffer, stypes_rows, stypes_form, stypes_content = extracted - else: - return None # not found - - matrix_raw = _pd.read_csv(snx_buffer, - delim_whitespace=True, - dtype={0: _np.int16, 1: _np.int16}) - #can be 4 and 5 columns; only 2 first int16 - - output = [] - prev_idx = 0 - for i in stypes_rows.keys(): - idx = stypes_rows[i] - # Where to get the n-elements for the apriori matrix? Should be taken from estimates matrix - ma_sq = _matrix_raw2square( - matrix_raw=matrix_raw[prev_idx:prev_idx + idx], - stypes_form=stypes_form[i], - n_elements=n_elements) - output.append(ma_sq) - prev_idx += idx - return output,stypes_content - -def snxdf2xyzdf(snxdf,unstack=True): - types_mask = snxdf.TYPE.isin(['STAX','STAY', 'STAZ', 'VELX', 'VELY', 'VELZ',]).values - snxdf.drop(index = snxdf.index.values[~types_mask],inplace=True) - snxdf['CODE_PT'] = snxdf.CODE.values + '_' + snxdf.PT.values.astype(object) - snx_df = snxdf.drop(columns=['CODE','PT','SOLN']).set_index(['CODE_PT', 'REF_EPOCH','TYPE']) - return snx_df.unstack(2) if unstack else snx_df - -def _get_snx_vector(path_or_bytes, stypes=('EST','APR'), snx_format=True,verbose=True): - '''stypes = "APR","EST","NEQ" - APRIORY, ESTIMATE, NORMAL_EQUATION - ''' - path = None - if isinstance(path_or_bytes, str): - path = path_or_bytes - snx_bytes = _gn_io.common.path2bytes(path) - elif isinstance(path_or_bytes, list): - path, stypes, snx_format,verbose = path_or_bytes - snx_bytes = _gn_io.common.path2bytes(path) - else: - snx_bytes = path_or_bytes - - n_header = int(snx_bytes[60:65]) - - if stypes == ('NEQ'): - stypes = ('APR','NEQ') - #should always return NEQ vector with APR above it - if verbose: - _logging.info('Prepending APR') - - stypes = _get_valid_stypes(stypes) # EST is always first as APR may have skips - - extracted = _snx_extract(snx_bytes=snx_bytes, stypes=stypes, obj_type='VECTOR', verbose=verbose) - if extracted is None: - return None - snx_buffer, stypes_rows, stypes_form, stypes_content = extracted - - try: - vector_raw = _pd.read_csv( - snx_buffer, - delim_whitespace=True, - comment=b'*', - header=None, - usecols=[0,1, 2, 3, 4, 5, 8, 9], - names=['INDEX','TYPE', 'CODE', 'PT', 'SOLN', 'REF_EPOCH', 'EST', 'STD'], - dtype={ - 0:int, - 1: _gn_const.TYPE_CATEGORY, - 2: object, - 3: _gn_const.PT_CATEGORY, - 4: 'category', #can not be int as may be '----' - 5: object, - 8: _np.float_, - 9: _np.float_ - }, - index_col='INDEX' - ) - - except ValueError as _e: - if _e.args[0][:33] == 'could not convert string to float': - _logging.error(f'{path} data corrupted. Skipping') - return None - else: - raise _e - - if path is not None: - del snx_buffer #need to test this better - - vector_raw.index = vector_raw.index.values-1 #start with 0 - - output = [] - prev_idx = 0 - for i in range(len(stypes_rows)): - stype = stypes[i] - idx = stypes_rows[stype] - vec_df = (vector_raw[prev_idx:prev_idx + idx]).copy() - if i == 0: - vec_df.REF_EPOCH = _gn_datetime.yydoysec2datetime(vec_df.REF_EPOCH, - recenter=True, - as_j2000=True) - else: - vec_df = vec_df.iloc[:, 5:] - if vec_df.shape[0]!=n_header: - vec_df = vec_df.reindex(_np.arange(start=0, stop=n_header),fill_value=0) - if stype in ['APR', 'NEQ']: - vec_df.rename(columns={'EST': stype}, inplace=True) - vec_df.drop(columns='STD', inplace=True) - output.append(vec_df) - prev_idx += idx - output = _pd.concat(output, axis=1) - if snx_format is None: - return output - if snx_format: - return snxdf2xyzdf(output,unstack=False) - return snxdf2xyzdf(output,unstack=True) - -def _matrix_raw2square(matrix_raw,stypes_form,n_elements=None): - if stypes_form == b'U': - _logging.info('U matrix detected. Not tested!') - idx = matrix_raw.iloc[:,:2].values - 1 - #last element of first index column. Should be specified for IGS APR matrices (?) - n_elements = idx[-1,0] + 1 if n_elements is None else n_elements - - rows = idx[:,0] - cols = idx[:,1] - - values = matrix_raw.iloc[:,2:].values.flatten(order='F') - nanmask = ~_np.isnan(values) - - rows = _np.concatenate([rows]*3) - cols = _np.concatenate([cols,cols+1,cols+2]) - - matrix = _np.ndarray((n_elements,n_elements),dtype=values.dtype) - matrix.fill(0) - matrix[rows[nanmask],cols[nanmask]] = values[nanmask] - # shouldn't care if lower or upper triangle - matrix_square = matrix.T + matrix - # CORR diagonal elements are std values. Dropping as it is a copy of EST block std - _np.fill_diagonal(matrix_square,matrix.diagonal()) # Doesn't matter which matrix type - we resolve this later - # here need to convert CORR to COVA. No problem as std values are already present COVA = CORR*STD*STD.T - return matrix_square - -def _unc_snx_neq(path_or_bytes): - vector = _get_snx_vector(path_or_bytes=path_or_bytes,stypes=['APR','EST','NEQ'],verbose=False) - matrix = _get_snx_matrix(path_or_bytes=path_or_bytes,stypes=['NEQ'], - n_elements=vector.shape[0],verbose=False) - - neqm = matrix[0][0] - neqv = vector.NEQ.values - aprv = vector.APR.values - vector.drop(columns='NEQ',inplace=True) - vector['UNC'] = aprv + _np.linalg.solve(a=neqm,b=neqv) - return vector - -def _unc_snx_cova(path_or_bytes): - vector = _get_snx_vector(path_or_bytes=path_or_bytes,stypes=['APR','EST'],verbose=False) - matrix = _get_snx_matrix(path_or_bytes=path_or_bytes,stypes=['APR','EST'], - n_elements=vector.shape[0],verbose=False) - - aprm = matrix[0][0] - estm = matrix[0][1] - aprv = vector.APR.values - estv = vector.EST.values - - vector['UNC'] = aprv + (_np.linalg.solve(aprm,aprm-estm) @ (estv - aprv)) - return vector - -def unc_snx(path,snx_format=True): - '''removes constrains from snx estimates using either COVA or NEQ method''' - snx_bytes = _gn_io.common.path2bytes(path) - if snx_bytes.find(b'NORMAL_EQUATION_MATRIX') == -1: - output = _unc_snx_cova(snx_bytes) - else: - output = _unc_snx_neq(snx_bytes) - if snx_format: - return output - return snxdf2xyzdf(output) - -def _read_snx_solution(path_or_bytes): - '''_get_snx_vector template to get a df with multiIndex columns as: - | APR | EST | STD | - |X|Y|Z|X|Y|Z|X|Y|Z|''' - return _get_snx_vector(path_or_bytes=path_or_bytes, - stypes=('APR', 'EST'), - snx_format=False, - verbose=False) - -# TODO get rid of p_tqdm. Need to rewrite hte loop with multiprocessing Pool -# def gather_sinex(glob_expr, n_threads=4, unconstrain=False): -# '''Expects a glob.glob() expression (e.g. '/data/cddis/*/esa*.snx.Z')''' - -# files = sorted(_glob.glob(glob_expr)) -# n_files = len(files) -# if not unconstrain: -# data = _p_map(_get_snx_vector, -# files, [('APR', 'EST')] * n_files, -# [True] * n_files, [False] * n_files, -# num_cpus=n_threads) -# else: -# data = _p_map(unc_snx, files, [False] * n_files, num_cpus=4) -# return data -# # return _pd.concat(data, axis=0).pivot(index=['CODE','TYPE'],columns='REF_EPOCH').T - -def _get_snx_vector_gzchunks(filename,block_name='SOLUTION/ESTIMATE',size_lookback=100): - '''extract block from a large gzipped sinex file e.g. ITRF2014 sinex''' - block_open = False - block_bytes = b'' - stop = False - - gzip_file = filename.endswith('.gz') - if gzip_file: - decompressor_zlib = _zlib.decompressobj(16+_zlib.MAX_WBITS) - - with open(file=filename,mode='rb') as compressed_file: - i=0 - while not stop: # until EOF - uncompressed = compressed_file.read(8192) - if gzip_file: - uncompressed = decompressor_zlib.decompress(uncompressed) - if i==0: - block_bytes+=uncompressed[:uncompressed.find(b'\n')+1] # copy header first - if i>0: - old_chunk = chunk[-size_lookback:] - chunk = old_chunk + uncompressed - else: - chunk = uncompressed - if chunk.find(f'+{block_name}'.encode()) != -1: - block_open = True - if block_open: - block_bytes += chunk[size_lookback if i>0 else 0:] - - if chunk.find(f'-{block_name}'.encode()) != -1: - block_open = False - stop=True - i+=1 - - return _get_snx_vector(path_or_bytes=block_bytes,stypes=['EST'],snx_format=None) - - -#SINEX ID BLOCK -def degminsec2decdeg(series): - '''Converts degrees/minutes/seconds to decimal degrees''' - _deg = series.str[:-8].values.astype(float) - _min = series.str[-8:-5].values.astype(float) - _sec = series.str[-5:].values.astype(float) - sign = _np.sign(_deg) - return _deg + sign*_min/60 + sign*_sec/3600 - -def _get_snx_id(path, sites_only=False): - snx_bytes = _gn_io.common.path2bytes(path) - site_id = _snx_extract_blk(snx_bytes=snx_bytes,blk_name='SITE/ID',remove_header=True)[0] - if sites_only: - return _np.char.strip(_np.asarray(site_id.splitlines()).astype('U5')) - - id_df = _pd.read_fwf(_BytesIO(site_id),header=None, - colspecs=[(0,5),(5,8),(8,18),(18,20),(44,55),(55,68),(68,76)]) - - id_df.columns = ['CODE','PT','DOMES','T','LON','LAT','H'] # location may have non-unicode chars - id_df.LON = degminsec2decdeg(id_df.LON) - id_df.LAT = degminsec2decdeg(id_df.LAT) - return id_df - -def llh2snxdms(llh): - '''converts llh ndarray to degree-minute-second snx id block format - LAT LON HEI - ''' - ll_dd = llh[:,:2] - ll_dd[:,1] %=360 - - sign = _np.sign(ll_dd) - ll_dd = _np.abs(ll_dd) - hei = llh[:,2] - - minutes,seconds = _np.divmod(ll_dd*3600,60) - degrees,minutes = _np.divmod(minutes,60) - - degrees *= sign - array = _np.concatenate([degrees,minutes,seconds.round(1),llh[:,[2,]].round(1)],axis=1) - - llh_dms_df = _pd.DataFrame(array,dtype=object, - columns=[['LAT','LON','LAT','LON','LAT','LON','HEI'], - ['D','D','M','M','S','S','']]) - llh_dms_df.iloc[:,:4] = llh_dms_df.iloc[:,:4].astype(int) - llh_dms_df = llh_dms_df.astype(str) - n_rows = llh_dms_df.shape[0] - - ll_stack = _pd.concat([llh_dms_df.LON, llh_dms_df.LAT],axis=0) - ll_stack = ( ll_stack.D.str.rjust(4).values - + ll_stack.M.str.rjust(3).values - + ll_stack.S.str.rjust(5).values) - buf = ll_stack[:n_rows] + ll_stack[n_rows:] + llh_dms_df.HEI.str.rjust(8).values - - buf[(hei>8000) | (hei<-2000) ] = ' 000 00 00.0 00 00 00.0 000.0' #| zero_mask - return buf - -def logllh2snxdms(llh): - '''Converts igs logfile-formatted lat-lon-height to the format needed for sinex ID block''' - n_rows = llh.shape[0] - latlon = _pd.concat([llh.LON,llh.LAT],axis=0) - step1 = latlon.str.extract(pat=r'([\+\-]?\d{2,3})(\d{2})(\d{2}\.\d)') - step1_mask = ( ~step1.iloc[:n_rows,0].isna().values - & ~step1.iloc[n_rows:,0].isna().values - & ~llh.HEI.isna()) - - step1_mask_stack = _np.tile(step1_mask,2) - - step2 = step1[step1_mask_stack].copy().values - n_rows = step2.shape[0]//2 - - dd = degminsec2decdeg(_pd.Series(step2[:,0] + ' ' +step2[:,1] + ' '+step2[:,2])) - hei = llh[step1_mask].HEI.values - hei[hei == ''] = 9999 - - llh_dec = _np.vstack([ dd[n_rows:], dd[:n_rows],hei.astype(float)]).T - - buf = llh2snxdms(llh_dec) - - out = _np.empty(llh.shape[0],dtype='= 999999 - nans = nan_mask.astype(float) - nans[nan_mask] = _np.NAN - sp3_df.iloc[:,1:5] = sp3_df.iloc[:,1:5].values+nans - -def mapparm(old,new): - """scipy function f map values """ - oldlen = old[1] - old[0] - newlen = new[1] - new[0] - off = (old[1]*new[0] - old[0]*new[1])/oldlen - scl = newlen/oldlen - return off, scl - -def read_sp3(sp3_path,pOnly=True): - '''Read SP3 file - Returns STD values converted to proper units (mm/ps) also if present. - by default leaves only P* values (positions), removing the P key itself - ''' - content = _gn_io.common.path2bytes(sp3_path) - header_end = content.find(b'/*') - - header = content[:header_end] - content = content[header_end:] - - parsed_header = parse_sp3_header(header) - - fline_b = header.find(b'%f') + 2 #TODO add to header parser - fline = header[fline_b:fline_b+24].strip().split(b' ') - base_xyzc = _np.asarray([float(fline[0])]*3 + [float(fline[1])]) # exponent base - - data_blocks = _np.asarray(_RE_SP3.findall(string=content[:content.rfind(b'EOF')])) - - dates = data_blocks[:,0] - data = data_blocks[:,1] - if not data[-1].endswith(b"\n"): data[-1]+=b"\n" - - counts = _np.char.count(data, b'\n') - - epochs_dt = _pd.to_datetime(_pd.Series(dates).str.slice(2,21).values.astype(str), - format=r'%Y %m %d %H %M %S') - - dt_index = _np.repeat(a=_gn_datetime.datetime2j2000(epochs_dt.values),repeats=counts) - b_string = b''.join(data.tolist()) - - series = _pd.Series(b_string.splitlines()) - data_width = series.str.len() - missing = b' '*(data_width.max() - data_width).values.astype(object) - series += missing # rows need to be of equal len - data_test = series.str[4:60].values.astype('S56').view(('S14')).reshape(series.shape[0],-1).astype(float) - - if parsed_header.HEAD.ORB_TYPE in ["FIT",'INT']: - sp3_df = _pd.DataFrame(data_test).astype(float) - sp3_df.columns = ([['EST','EST','EST','EST'], - ['X','Y','Z','CLK',]]) - - else: # parsed_header.HEAD.ORB_TYPE == 'HLM': - # might need to output log message - std = (series.str[60:69].values+series.str[70:73].values).astype('S12').view('S3').astype(object) - std[std == b' '] = None - std = std.astype(float).reshape(series.shape[0],-1) - - ind = (series.str[75:76].values + series.str[79:80].values).astype('S2').view('S1') - ind[ind == b' '] = b'' - ind = ind.reshape(series.shape[0],-1).astype(str) - - sp3_df = _pd.DataFrame(_np.column_stack([data_test,std,ind]),).astype( - {0:float,1:float,2:float,3:float,4:float,5:float,6:float,7:float,8:"category",9:"category"}) - sp3_df.columns = ([['EST','EST','EST','EST','STD','STD','STD','STD','P_XYZ','P_CLK'], - ['X','Y','Z','CLK','X','Y','Z','CLK','','']]) - sp3_df.STD = base_xyzc ** sp3_df.STD.values - - nanflags2nans(sp3_df) # 999999* None value flag to None - if pOnly or parsed_header.HEAD.loc['PV_FLAG']=='P': - pMask = series.astype('S1') == b'P' - sp3_df = sp3_df[pMask].set_index([dt_index[pMask],series.str[1:4].values[pMask].astype(str).astype(object)]) - else: - sp3_df = sp3_df.set_index([dt_index, - series.values.astype('U1'), - series.str[1:4].values.astype(str).astype(object)]) - - sp3_df.attrs['HEADER'] = parsed_header # writing header data to dataframe attributes - sp3_df.attrs['path'] = sp3_path - return sp3_df - -def parse_sp3_header(header): - sp3_heading = _pd.Series( data = _np.asarray(_RE_SP3_HEAD.search(header).groups() - + _RE_SP3_HEAD_FDESCR.search(header).groups()).astype(str), - index = ['VERSION','PV_FLAG','DATETIME','N_EPOCHS','DATA_USED','COORD_SYS','ORB_TYPE','AC', - 'FILE_TYPE','TIME_SYS']) - - head_svs = (_np.asarray(b''.join(_RE_SP3_HEAD_SV.findall(header))) - [_np.newaxis].view('S3').astype(str)) - head_svs_std = (_np.asarray(b''.join(_RE_SP3_ACC.findall(header))) - [_np.newaxis].view('S3')[:head_svs.shape[0]].astype(int)) - sv_tbl = _pd.Series(head_svs_std,index=head_svs) - - return _pd.concat([sp3_heading,sv_tbl],keys=['HEAD','SV_INFO'],axis=0) - -def getVelSpline(sp3Df): - """returns in the same units as intput, e.g. km/s (needs to be x10000 to be in cm as per sp3 standard""" - sp3dfECI = sp3Df.EST.unstack(1)[['X','Y','Z']] #_ecef2eci(sp3df) - datetime = sp3dfECI.index.values - spline = _interpolate.CubicSpline(datetime, sp3dfECI.values) - velDf = _pd.DataFrame( data = spline.derivative(1)(datetime), - index = sp3dfECI.index,columns = sp3dfECI.columns).stack(1) - return _pd.concat([sp3Df,_pd.concat([velDf],keys=['VELi'],axis=1)],axis=1) - -def getVelPoly(sp3Df,deg=35): - '''takes sp3_df, interpolates the positions for -1s and +1s and outputs velocities''' - est = sp3Df.unstack(1).EST[['X','Y','Z']] - x = est.index.values - y = est.values - - off,scl = mapparm([x.min(), x.max()],[-1,1]) # map from input scale to [-1,1] - - x_new = off + scl*(x) - coeff = _np.polyfit(x=x_new,y=y,deg=deg) - - x_prev = off + scl*(x-1) - x_next = off + scl*(x+1) - - xx_prev_combined = _np.broadcast_to((x_prev)[None],(deg+1,x_prev.shape[0])) - xx_next_combined = _np.broadcast_to((x_next)[None],(deg+1,x_prev.shape[0])) - - inputs_prev = xx_prev_combined ** _np.flip(_np.arange(deg+1))[:,None] - inputs_next = xx_next_combined ** _np.flip(_np.arange(deg+1))[:,None] - - res_prev = coeff.T.dot(inputs_prev) - res_next = coeff.T.dot(inputs_next) - vel_i = _pd.DataFrame( (((y-res_prev.T)+(res_next.T-y))/2), - columns=est.columns, - index=est.index).stack() - - vel_i.columns = [['VELi']*3] + [vel_i.columns.values.tolist()] - - return _pd.concat([sp3Df,vel_i],axis=1) - -def gen_sp3_header(sp3_df): - - sp3_j2000 = sp3_df.index.levels[0].values - sp3_j2000_begin = sp3_j2000[0] - - header = sp3_df.attrs['HEADER'] - head = header.HEAD - sv_tbl = header.SV_INFO - - - #need to update DATETIME outside before writing - line1 = ([f'#{head.VERSION}{head.PV_FLAG}{_gn_datetime.j20002rnxdt(sp3_j2000_begin)[0][3:-2]}' - + f'{sp3_j2000.shape[0]:>9}{head.DATA_USED:>6}' - + f'{head.COORD_SYS:>6}{head.ORB_TYPE:>4}{head.AC:>5}\n']) - - - gpsweek, gpssec = _gn_datetime.datetime2gpsweeksec(sp3_j2000_begin) - mjd_days, mjd_sec = _gn_datetime.j20002mjd(sp3_j2000_begin) - - line2 = [f'##{gpsweek:5}{gpssec:16.8f}{sp3_j2000[1] - sp3_j2000_begin:15.8f}{mjd_days:6}{mjd_sec:16.13f}\n'] - - sats = sv_tbl.index.to_list() - n_sats = sv_tbl.shape[0] - - sats_rows = (n_sats//17)+1 if n_sats>(17*5) else 5 #should be 5 but MGEX need more lines (e.g. CODE sp3) - sats_header = _np.asarray(sats + [' 0']*(17*sats_rows - n_sats),dtype=object).reshape(sats_rows,-1).sum(axis=1) + '\n' - - sats_header[0] = '+ {:4} '.format(n_sats) + sats_header[0] - sats_header[1:] = '+ ' + sats_header[1:] - - - sv_orb_head = _np.asarray(sv_tbl.astype(str).str.rjust(3).to_list() + [' 0']*(17*sats_rows - n_sats),dtype=object).reshape(sats_rows,-1).sum(axis=1) + '\n' - - sv_orb_head[0] = '++ '+ sv_orb_head[0] - sv_orb_head[1:] = '++ '+ sv_orb_head[1:] - - head_c = ( [f'%c {head.FILE_TYPE} cc {head.TIME_SYS} ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc\n'] - +['%c cc cc ccc ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc\n']) - - head_fi = ( ['%f 1.2500000 1.025000000 0.00000000000 0.000000000000000\n'] - +['%f 0.0000000 0.000000000 0.00000000000 0.000000000000000\n'] - +['%i 0 0 0 0 0 0 0 0 0\n'] - +['%i 0 0 0 0 0 0 0 0 0\n']) - - comment = ['/*\n']*4 - - return ''.join( line1 + line2 - + sats_header.tolist() + sv_orb_head.tolist() - + head_c + head_fi + comment) - -def gen_sp3_content(sp3_df): - est = sp3_df.EST.values - est[_np.isnan(est)] = 999999.999999 - sp3_df.EST = est #None to 999999 - a_str = sp3_df.EST.round(6).astype(str) - - sp3_content = ('P' + sp3_df.index.get_level_values(1).values.astype(object) + ' ' - + a_str.X.str.rjust(13).values + ' ' - + a_str.Y.str.rjust(13).values + ' ' - + a_str.Z.str.rjust(13).values + ' ' - + a_str.CLK.str.rjust(13).values + '\n') - - dt_uniques = sp3_df.index.levels[0].values - - dt_s = _pd.Series(_gn_datetime.j20002rnxdt(dt_uniques),index = dt_uniques-1) - data_s = _pd.Series(sp3_content,index=sp3_df.index.get_level_values(0)) - - return ''.join((_pd.concat([dt_s,data_s]).sort_index()).to_list()) - -def write_sp3(sp3_df,path): - """sp3 writer, dataframe to sp3 file""" - content = gen_sp3_header(sp3_df) + gen_sp3_content(sp3_df) + 'EOF' - with open(path,'w') as file: - file.write(content) - -def merge_attrs(df_list): - """Merges attributes of a list of sp3 dataframes into a single set of attributes""" - df = _pd.concat(list(map(lambda obj: obj.attrs['HEADER'], df_list)),axis=1) - - mask_mixed = ~_gn_aux.unique_cols(df.loc['HEAD']) - values_if_mixed = _np.asarray(['MIX','MIX','MIX',None,'M',None,'MIX','P','MIX','d']) - head = df[0].loc['HEAD'].values - head[mask_mixed] = values_if_mixed[mask_mixed] - sv_info = df.loc['SV_INFO'].max(axis=1).values.astype(int) - - return _pd.Series(_np.concatenate([head,sv_info]),index=df.index) - -def merge_sp3(sp3_paths,clk_paths=None): - '''Reads in a list of sp3 files and optianl list of clk file and merges them into a single sp3 file''' - sp3_dfs = [read_sp3(sp3_file) for sp3_file in sp3_paths] - merged_sp3 = _pd.concat(sp3_dfs) - merged_sp3.attrs['HEADER'] = merge_attrs(sp3_dfs) - - if clk_paths is not None: - clk_dfs = [_gn_io.clk.read_clk(clk_file) for clk_file in clk_paths] - merged_sp3.EST.CLK = _pd.concat(clk_dfs).EST.AS * 1000000 - - return merged_sp3 - -def sp3_hlm_trans(a:_pd.DataFrame,b:_pd.DataFrame)->tuple((_pd.DataFrame,tuple((_np.ndarray,_pd.DataFrame)))): - '''Rotates sp3_b into sp3_a. Returns a tuple of updated sp3_b and HLM array with applied computed parameters and residuals''' - hlm = _gn_transform.get_helmert7(pt1=a.EST[['X','Y','Z']].values, - pt2=b.EST[['X','Y','Z']].values) - - hlm = (hlm[0],_pd.DataFrame(hlm[1],columns=[['RES']*3,['X','Y','Z']],index = a.index)) - - b.iloc[:,:3] = _gn_transform.transform7(xyz_in=b.EST[['X','Y','Z']].values,helmert_list=hlm[0][0]) - return b, hlm - -def diff_sp3_rac(sp3_a,sp3_b,hlm_mode=None,use_cubic_spline = True): - """ - Computes the difference between the two sp3 files in the radial, along-track and cross-track coordinates - the interpolator used for computation of the velocities can be based on cubic spline (default) or polynomial - Breaks if NaNs appear on unstack in getVelSpline function - """ - hlm_modes = [None, 'ECF', 'ECI'] - if hlm_mode not in hlm_modes: - raise ValueError(f"Invalid hlm_mode. Expected one of: {hlm_modes}") - - hlm = None #init hlm var - sp3_a, sp3_b = _gn_aux.sync_idx_dfs(sp3_a, sp3_b) # produces common sp3 dfs with sorted index - if hlm_mode == 'ECF': - sp3_b, hlm = sp3_hlm_trans(sp3_a,sp3_b) - - sp3_a_eci = _gn_transform.ecef2eci(sp3_a) - if use_cubic_spline: - sp3_a_eci_vel = getVelSpline(sp3Df=sp3_a_eci) - else: - sp3_a_eci_vel = getVelPoly(sp3Df=sp3_a_eci,deg=35) - sp3_b_eci = _gn_transform.ecef2eci(sp3_b) - - if hlm_mode == 'ECI': - sp3_b_eci, hlm = sp3_hlm_trans(sp3_a_eci,sp3_b_eci) - - xyz_cols_a = _np.argwhere(sp3_a_eci.columns.isin([('EST','X'),('EST','Y'),('EST','Z')])).ravel() # get indices of EST X Y Z cols - xyz_cols_b = _np.argwhere(sp3_b_eci.columns.isin([('EST','X'),('EST','Y'),('EST','Z')])).ravel() - - diff_eci = sp3_a_eci.iloc[:,xyz_cols_a] - sp3_b_eci.iloc[:,xyz_cols_b] - nd_rac = diff_eci.values[:,_np.newaxis] @ _gn_transform.eci2rac_rot(sp3_a_eci_vel) - df_rac = _pd.DataFrame(nd_rac.reshape(-1,3), - index = sp3_a.index, - columns=[['EST_RAC']*3,['Radial','Along-track','Cross-track']]) - - df_rac.attrs['sp3_a'] = _os.path.basename(sp3_a.attrs['path']) - df_rac.attrs['sp3_b'] = _os.path.basename(sp3_b.attrs['path']) - df_rac.attrs['hlm'] = hlm - df_rac.attrs['hlm_mode'] = hlm_mode - return df_rac diff --git a/scripts/gn_lib/gn_io/stec.py b/scripts/gn_lib/gn_io/stec.py deleted file mode 100644 index 3e9e8b180..000000000 --- a/scripts/gn_lib/gn_io/stec.py +++ /dev/null @@ -1,13 +0,0 @@ -from io import BytesIO as _BytesIO - -import pandas as _pd -from gn_lib import gn_const as _gn_const -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io - - -def read_stec(path_or_bytes): - stec = _pd.read_csv(_BytesIO(_gn_io.common.path2bytes(path_or_bytes)),comment='#',header=None,usecols=[1,2,3,4,5,6,7],names=['WEEK','TOW','SITE','SAT','VAL','VAR','LAYER'], # type:ignore - dtype={1:int,2:int,3:object,4:_gn_const.PRN_CATEGORY,5:float,6:float,7:int}) # type:ignore - datetime = _gn_datetime.gpsweeksec2datetime(stec.WEEK.values,stec.TOW.values,as_j2000=True) - return stec.drop(columns=['WEEK','TOW']).set_index([datetime,'SITE','SAT','LAYER']) diff --git a/scripts/gn_lib/gn_io/trace.py b/scripts/gn_lib/gn_io/trace.py deleted file mode 100644 index 9adc2180c..000000000 --- a/scripts/gn_lib/gn_io/trace.py +++ /dev/null @@ -1,156 +0,0 @@ -'''TRACE file parser. Note the separate functions for values and residuals''' -import logging as _logging -import os as _os -import re as _re -from io import BytesIO as _BytesIO - -import numpy as _np -import pandas as _pd - -from gn_lib import gn_const as _gn_const -from gn_lib import gn_datetime as _gn_datetime -from gn_lib import gn_io as _gn_io - -def _trace_extract(path_or_bytes,blk_name): - trace_bytes = _gn_io.common.path2bytes(path_or_bytes) #path2bytes passes through bytes - - begin = end = 0 - buf=[] - - blk_begin = (f'+{blk_name}').encode() - blk_end = (f'-{blk_name}').encode() - - while True: - begin = trace_bytes.find(blk_begin,end) - begin_full = trace_bytes.find(b'\n',begin) - if begin==-1: - break - end = trace_bytes.find(blk_end,begin_full) - - blk_content = trace_bytes[begin_full+1:end] # needs +1 not to start with '\n' - blk_type = b'\t' + trace_bytes[begin+1:begin_full] + b'\n' # needs +2 to remove ' +' - blk_content_w_type = blk_type.join(blk_content.splitlines()) + blk_type - buf.append(blk_content_w_type) - - content = b''.join(buf) - if len(content) == 0: - _logging.error(f'"{blk_name}" data not found') - return None - return content - -def _read_trace_states(path_or_bytes): - states = _trace_extract(path_or_bytes,blk_name='STATES') - if states is None: - return None - df = _pd.read_csv(_BytesIO(states),delimiter='\t',usecols=[1,2,3,4,5,6,7,8,10],skipinitialspace=True,dtype={'SAT':_gn_const.PRN_CATEGORY,'TYPE':_gn_const.STATE_TYPES_CATEGORY},keep_default_na=False, - comment='#',header=None,names = ['TIME','TYPE','SITE','SAT','NUM','EST','VAR','ADJ','BLK'],parse_dates=['TIME']) # type:ignore - - if df.size == 0: - _logging.error("STATES* blocks present but empty") - return None - - df.TIME = _gn_datetime.datetime2j2000(df.TIME.values) - - empty_mask = df.TYPE.values.notna() # dropping ONE type - if (~empty_mask).sum()>0: - df = df[empty_mask] - - return df.set_index(['TIME','SITE','TYPE','SAT','NUM','BLK']) - -def _read_trace_residuals(path_or_bytes,it_max_only=True): - residuals = _trace_extract(path_or_bytes,blk_name='RESIDUALS') - if residuals is None: - return None - df = _pd.read_csv(_BytesIO(residuals),delimiter='\t',comment='#',header=None,usecols=[1,2,3,4,5,6,7,8,9],skipinitialspace=True,keep_default_na=False, - names = ['It','TIME','SITE','SAT','TYPE','PREFIT','POSTFIT','STD','BLK'],parse_dates=['TIME'],dtype={'It':int,'SAT':_gn_const.PRN_CATEGORY}) # type:ignore - - if df.size == 0: # blocks are present bu empty - _logging.error("RESIDUALS* blocks present but empty") - return None - - df.TIME = _gn_datetime.datetime2j2000(df.TIME.values) - - empty_mask = df.SITE.values.astype(bool) # may be removed in the future when the pivot is removed from PEA - if (~empty_mask).sum()>0: - df = df[empty_mask] - - if not it_max_only: - return df.set_index(['TIME','SITE','TYPE','SAT','BLK']) - # to get max_ind values pandas >= 1.1 is required - it_max_ind=df[['TIME','It']].groupby(['TIME']).max().reset_index().values.tolist() - return df.set_index(['TIME','It']).loc[it_max_ind].reset_index().set_index(['TIME','SITE','TYPE','SAT','BLK']) - - - -_RE_TRACE_HEAD = _re.compile( - rb'station\s*\:\s*(.{4})\n\w+\s*\:\s*(.+|)\n\w+\s*\:\s*(.+|)\n\w+\s*\:\s*(\d)\n\w+\s*\:\s*(.+)') -_RE_TRACE_LC = _re.compile(rb'PDE\sform\sLC.+((?:\n.+)+)') -_RE_EL = _re.compile(rb'\*2 PDE-CS GPST\s+\w+\s+(\d+)\s+(\d+).0\s+(\w\d\d)\s+(\d+.\d+)') - -def _find_trace(output_path: str) -> tuple: - '''Scans output path for TRACE files''' - station_names = set() - trace_paths = [] - _re_station_name = _re.compile(r'\-(.{4})\d+.TRACE') - - for file in _os.scandir(path=output_path): - if file.path.endswith('TRACE'): - station_names.add(_re_station_name.findall(file.path)[0]) - trace_paths.append(file.path) - - station_names = sorted(station_names) - trace_paths = sorted(trace_paths) - return station_names, trace_paths - -def _read_trace_LC(path_or_bytes): - '''Parses the LC combo block of the trace files producing - a single dataframe. WORK-IN-PROGRESS''' - # regex search string - if isinstance(path_or_bytes, str): - trace_content = _gn_io.common.path2bytes(path_or_bytes) # will accept .trace.Z also - else: - trace_content = path_or_bytes - trace_LC_list = _RE_TRACE_LC.findall(string=trace_content) - LC_bytes = b''.join(trace_LC_list) - LC_bytes = LC_bytes.replace(b'=',b'') #getting rif of '=' - - df_LC = _pd.read_csv(_BytesIO(LC_bytes),delim_whitespace=True,header=None,usecols=[1,2,4,6,8,9,10,11,12,13]).astype( - { - 1: _np.int16, 2:_np.int32, 4: ' _pd.DataFrame: - '''Parses tro snx file into a dataframe. - Enabling recenter overrides the default SOD values to 43200 s''' - snx_bytes = _gn_io.common.path2bytes(path) - tro_estimate = _gn_io._snx_extract_blk(snx_bytes=snx_bytes,blk_name='TROP/SOLUTION',remove_header=True) - if tro_estimate is None: - _tqdm.write(f'bounds not found in {path}. Skipping.', end=' | ') - return None - tro_estimate = tro_estimate[0] #only single block is in tro so bytes only - - try: - solution_df = _pd.read_csv(_BytesIO(tro_estimate), delim_whitespace=True, - comment=b'*', index_col=False, header=None, - names=['CODE', 'REF_EPOCH', - 2, 3, 4, 5, 6, 7], - dtype={0: 'category', 1: object, - 2: _np.float_, 3: _np.float32, - 4: _np.float32, 5: _np.float32, - 6: _np.float32, 7: _np.float32, }) - except ValueError as _e: - if _e.args[0][:33] == 'could not convert string to float': - _tqdm.write(f'{path} data corrupted. Skipping', end=' | ') - return None - - solution_df.REF_EPOCH = _gn_datetime.yydoysec2datetime( - solution_df.REF_EPOCH, recenter=recenter, as_j2000=True) - solution_df.set_index(['CODE', 'REF_EPOCH'], inplace=True) - solution_df.columns = _pd.MultiIndex.from_product( - [['TROTOT', 'TGNTOT', 'TGETOT'], ['VAL', 'STD']]) - return solution_df \ No newline at end of file diff --git a/scripts/gn_lib/gn_plot.py b/scripts/gn_lib/gn_plot.py deleted file mode 100644 index b60f25c67..000000000 --- a/scripts/gn_lib/gn_plot.py +++ /dev/null @@ -1,80 +0,0 @@ -import matplotlib.dates as _mdates -import matplotlib.units as _munits -import numpy as _np -import pandas as _pd -import plotext as plx -from matplotlib import cm as _cm - -from gn_lib.gn_const import J2000_ORIGIN as _J2000_ORIGIN -from gn_lib.gn_datetime import j20002datetime as _j20002datetime - - -def plot_vec(df:_pd.DataFrame, axes:list, axes_idx:list,legend:bool=True): - '''Function to plot columnar (single-lvl column names) dataframe to axes list - according to axes index provided (needed in case of non-alphabetic order of column names and axes desired). - Example snippet below: - - fig = plt.figure(figsize=(10,5) - gs = fig.add_gridspec(3, hspace=0.2) - ax = gs.subplots(sharex=True, sharey=False) - plot_vec(axes=ax,df=a,axes_idx=[1,2,0]) - fig.savefig('blah.png') - ''' - converter = _mdates.DateConverter() - _munits.registry[_np.datetime64] = converter - hours = (df.index.values[-1] - df.index.values[0])//3600 - locator = _mdates.HourLocator(interval=(hours//24 + 1)*3) - formatter = _mdates.ConciseDateFormatter(locator,show_offset=True) # offset with date at the bottom - formatter.zero_formats[3] = '%d-%b' # the 00:00 label formatter - - df.index = _j20002datetime(df.index.values) # converting J2000 seconds to datetime64 - components = df.columns.levels[0] - sv_list = df.columns.levels[1] - - styl_list=['solid','dotted','dashed','dashdot'] - - cmap = _cm.gist_rainbow #hsv in the original plotting script - for i in range(len(axes_idx)): - df_c = df[components[i]] - for j in range(len(sv_list)): - axes[axes_idx[i]].plot(df_c[sv_list[j]],label=sv_list[j] if (i==0 and legend)else '', - ls=styl_list[j % 4],color=cmap(j/len(sv_list))) - - axes[axes_idx[i]].set_ylabel(f'{components[i]} (cm)') - - axes[0].xaxis.set_major_locator(locator) - axes[0].xaxis.set_major_formatter(formatter) - -def diff2plot(diff, kind=None,title='Unnamed plot'): - """Function to plot graph to the terminal. Can be scatter or bar plot (Initial test functionality) - Works only with plotext 4.2, not above""" - # try: - # import plotext as plt - # except ModuleNotFoundError: - # # Error handling - # pass - plx.clear_plot() - diff = diff.round(2) - if kind == 'bar': - # expects a series with index being string names - mask0 = (diff.values != 0) & ~_np.isnan(diff.values) - if mask0.any(): - plx.bar(diff.index.values[mask0].tolist(), diff.values[mask0].tolist(),orientation = "h",width=0.3) - plx.vertical_line(coordinate = 0) - plx.plotsize(100,diff.shape[0]*2 + 3) - else: - return None - else: - mask0 = ((diff.values != 0) & ~_np.isnan(diff.values)).any(axis=0) - if mask0.any(): - cols = diff.columns[mask0] - x1 = plx.datetime.datetime_to_string(diff.index.astype('timedelta64[ns]')*1000000000 + _J2000_ORIGIN) - for i in range(cols.shape[0]): - plx.scatter_date(x1, diff[cols[i]].to_list(), color=i,marker = "hd",label=diff.columns[i]) - plx.plotsize(100,30 + 3) - else: - return None - - plx.title(title) - plx.limit_size(limit_xsize=False,limit_ysize=False) - plx.show() diff --git a/scripts/gn_lib/gn_transform.py b/scripts/gn_lib/gn_transform.py deleted file mode 100644 index 254860206..000000000 --- a/scripts/gn_lib/gn_transform.py +++ /dev/null @@ -1,253 +0,0 @@ -'''Helmert inversion and transformation functions''' -import numpy as _np -import pandas as _pd -from gn_lib.gn_const import WGS84, OMEGA_E - - -def gen_helm_aux(pt1,pt2): - '''aux function for helmert values inversion.''' - pt1 = pt1.astype(float) - pt2 = pt2.astype(float) - n_points=pt1.shape[0] - - unity_blk = _np.tile(_np.eye(3),reps=n_points).T - - xyz_blk = _np.zeros((n_points,3,3)) - xyz_blk[:,1,2] = pt1[:,0] #x[1,2] - xyz_blk[:,2,1] = -pt1[:,0] #x[2,1] - - xyz_blk[:,2,0] = pt1[:,1] #y[2,0] - xyz_blk[:,0,2] = -pt1[:,1] #y[0,2] - - xyz_blk[:,0,1] = pt1[:,2] #z[0,1] - xyz_blk[:,1,0] = -pt1[:,2] #z[1,0] - - xyz = pt1.reshape((-1,1)) - A = _np.column_stack([unity_blk,xyz_blk.reshape((-1,3)),xyz]) #matrix - rhs = pt2.reshape((-1,1)) - xyz #right-hand side - return A, rhs - -def get_helmert7(pt1,pt2): - '''inversion of 7 Helmert parameters between 2 sets of points''' - A, rhs = gen_helm_aux(pt1,pt2) - sol = _np.linalg.lstsq(A, rhs,rcond=None) # parameters - res = rhs - A@sol[0] - # sol[0] = [Tx, Ty, Tz, Rx, Ry, Rz, μ] - return sol,res.reshape(-1,3) - -def gen_rot_matrix(v): - '''creates rotation matrix for transform7 - from a list of [Rx, Ry, Rz] as in Altamimi''' - x, y, z = v - mat = _np.empty((3,3),dtype=float) - mat[0] = [ 0, -z, y] - mat[1] = [ z, 0, -x] - mat[2] = [-y, x, 0] - return mat + _np.eye(3) - -def transform7(xyz_in,helmert_list): - '''transformation of xyz vector with 7 helmert parameters''' - translation = helmert_list[0:3] - rotation = gen_rot_matrix(helmert_list[3:6].flatten()) - scale = helmert_list[6] - - xyz_out = ((xyz_in @ rotation)*(1+scale) + translation.T) - return xyz_out - -def xyz2llh_larson(xyz_array,ellipsoid=WGS84,tolerance = 1e-10,deg=False): - '''vectorized version of xyz2llh function as in Larson's gnssIR''' - x_arr,y_arr,z_arr = xyz_array[:,0],xyz_array[:,1],xyz_array[:,2] - llh_array = _np.empty_like(xyz_array) - - _r = (x_arr*x_arr+y_arr*y_arr)**(1/2) - phi0 = _np.arctan((z_arr/_r)/(1-ellipsoid.ecc1sq)) - phi = _np.empty_like(phi0,dtype=_np.float_) - error_mask = phi0!=_np.nan # quick init of mask with all True - - for __ in range(10): #10 iterations cap as per Larson - # prime vertical radius of curvature - _n = ellipsoid.semimaj/(1-ellipsoid.ecc1sq*_np.sin(phi0[error_mask])**2)**(1/2) - hei = _r[error_mask]/_np.cos(phi0[error_mask])-_n - phi[error_mask] = _np.arctan((z_arr[error_mask]/_r[error_mask])/\ - (1-ellipsoid.ecc1sq*_n/(_n+hei))) - error_mask = _np.abs(phi-phi0) > tolerance - if error_mask.sum() == 0: #if all Falls - break - phi0 = phi.copy()#need to copy here otherwise it's a pointer - - # lam = _np.arctan2(y_arr, x_arr) - - llh_array[:,0] = phi #phi - llh_array[:,1] = _np.arctan2(y_arr, x_arr) # lam - llh_array[:,2] = hei #hei - if deg: - llh_array[:,:2] = _np.rad2deg(llh_array[:,:2]) - return llh_array - -def xyz2llh_heik(xyz_array: _np.ndarray, ellipsoid=WGS84, deg=False): - '''Heikkinen, M. (1982) - This is exact transformation and is pretty fast - Output - phi: latitude rad - lam: longitude rad - hei: height meters - ''' - x_arr,y_arr,z_arr = xyz_array[:,0],xyz_array[:,1],xyz_array[:,2] - llh_array = _np.empty_like(xyz_array) - - z_sq = z_arr*z_arr - r_sq = x_arr*x_arr + y_arr*y_arr - _r = (r_sq)**(1/2) - - _f = 54 * ellipsoid.semiminsq * z_sq - _g = r_sq + (1 - ellipsoid.ecc1sq)*z_sq - \ - ellipsoid.ecc1sq*(ellipsoid.semimajsq - ellipsoid.semiminsq) - _c = ellipsoid.ecc1sq*ellipsoid.ecc1sq*_f*r_sq/(_g*_g*_g) - _s = (1 + _c + (_c*_c + _c + _c)**(1/2))**(1/3) - _p = _f/(3*(_s + 1/_s + 1)**2*(_g*_g)) - _q = (1 + 2*(ellipsoid.ecc1sq*ellipsoid.ecc1sq*_p))**(1/2) - r_0 = -(_p*ellipsoid.ecc1sq*_r)/(1+_q) + (ellipsoid.semimajsq/2*(1+1/_q)\ - - _p*(1 - ellipsoid.ecc1sq)*(z_sq)/(_q*(1+_q)) - _p*r_sq/2)**(1/2) - - r_ecc1sq_r0_sq = (_r - ellipsoid.ecc1sq*r_0)**2 - _u = (r_ecc1sq_r0_sq + z_sq)**(1/2) - _v = (r_ecc1sq_r0_sq + (1-ellipsoid.ecc1sq)*z_sq)**(1/2) - - bsq_av = ellipsoid.semiminsq/(ellipsoid.semimaj*_v) - z_0 = bsq_av*z_arr - - llh_array[:,0] = _np.arctan((z_arr+ellipsoid.ecc2sq*z_0)/_r) #phi - llh_array[:,1] = _np.arctan2(y_arr, x_arr) # lam - llh_array[:,2] = _u*(1 - bsq_av) #hei - if deg: - llh_array[:,:2] = _np.rad2deg(llh_array[:,:2]) - return llh_array - -def xyz2llh_zhu(xyz_array,ellipsoid=WGS84,deg=False): - '''Zhu, J. (1993) - Output - phi: latitude rad - lam: longitude rad - hei: height meters - ''' - x_arr,y_arr,z_arr = xyz_array[:,0],xyz_array[:,1],xyz_array[:,2] - llh_array = _np.empty_like(xyz_array) - - _l=ellipsoid.ecc1sq/2 - l_sq = _l*_l - r_sq = x_arr*x_arr + y_arr*y_arr - _r = r_sq**(1/2) - _m = r_sq/ellipsoid.semimajsq - ec1sq_z = (1-ellipsoid.ecc1sq)*z_arr - _n = (ec1sq_z/ellipsoid.semimin)**2 - _i = -(2*l_sq + _m + _n)/2 - _k = l_sq*(l_sq - _m - _n) - _q = (_m + _n - 4*l_sq)**3/216 + _m*_n*l_sq - _d = ((2*_q - _m*_n*l_sq)*_m*_n*l_sq)**(1/2) - - beta = _i/3 - (_q+_d)**(1/3) - (_q-_d)**(1/3) - _t = ((beta*beta - _k)**(1/2) - (beta+_i)/2)**(1/2) - _np.sign(_m-_n) * ((beta - _i)/2)**(1/2) - - r_0 = _r/(_t+_l) - z_0 = ec1sq_z/(_t-_l) - - llh_array[:,0] = _np.arctan(z_0/((1 - ellipsoid.ecc1sq)*r_0)) #phi - llh_array[:,1] = _np.arctan2(y_arr, x_arr) # lam - llh_array[:,2] = _np.sign(_t - 1 + _l) * ((_r - r_0)**2 + (z_arr - z_0)**2)**(1/2) #hei - if deg: - llh_array[:,:2] = _np.rad2deg(llh_array[:,:2]) - return llh_array - -def llh2xyz(lat,lon,hei,ellipsoid): - '''Converts lat, lon and height to XYZ - phi is geodetic latitude - lam is geodetic longitude - hei is the altitude normal to ellipsoid''' - cos_phi = _np.cos(lat) - sin_phi = _np.sin(lat) - _rp = ellipsoid.semimaj/(1 - ellipsoid.ecc1sq*sin_phi*sin_phi)**(1/2) - rp_h = _rp + hei - - x_arr = rp_h * cos_phi * _np.cos(lon) - y_arr = rp_h * cos_phi * _np.sin(lon) - z_arr = (rp_h - ellipsoid.ecc1sq*_rp) * sin_phi - return x_arr,y_arr,z_arr - - -def llh2rot(phi, lamb): - '''Creates R rotation matrices for n sites stacked - on the 3d dimension from phi (lat) and lamb (lon).''' - sin_lamb = _np.sin(lamb) - cos_lamb = _np.cos(lamb) - sin_phi = _np.sin(phi) - cos_phi = _np.cos(phi) - - rot = _np.zeros((phi.shape[0],3,3),dtype=_np.float_) - rot[:,0,0] =-sin_lamb - rot[:,0,1] = cos_lamb - - rot[:,1,0] =-sin_phi*cos_lamb - rot[:,1,1] =-sin_phi*sin_lamb - rot[:,1,2] = cos_phi - - rot[:,2,0] = cos_phi*cos_lamb - rot[:,2,1] = cos_phi*sin_lamb - rot[:,2,2] = sin_phi - return rot - - -def norm(a:_np.ndarray,axis:int=1)->_np.ndarray: - '''Computes norm of every vector in the input array''' - return _np.sqrt((a * a).sum(axis=axis)) - - -def ecef2eci(sp3_in): - '''Simplified conversion of sp3 posiitons from ECEF to ECI''' - xyz_idx = _np.argwhere(sp3_in.columns.isin([('EST','X'),('EST','Y'),('EST','Z')])).ravel() - theta = OMEGA_E * (sp3_in.index.get_level_values(0).values) - - cos_theta = _np.cos(theta) - sin_theta = _np.sin(theta) - - sp3_nd = sp3_in.iloc[:,xyz_idx].values - x = sp3_nd[:,0] - y = sp3_nd[:,1] - z = sp3_nd[:,2] - - x_eci = x*cos_theta - y*sin_theta - y_eci = x*sin_theta + y*cos_theta - return _pd.DataFrame(_np.concatenate([x_eci,y_eci,z]).reshape(3,-1).T,index = sp3_in.index,columns=[['EST','EST','EST'],['X','Y','Z']]) - - -def eci2rac_rot(a): - '''Computes rotation 3D stack for sp3 vector rotation into RAC/RTN - RAC conventions of POD (to be discussed) - {u} = |{P}| - [T] = {v} = {w}x{u} * -1 # x of two orthogonal unit-vectors gives a unit vector so no need for || - {w} = |{P}x{V}| * -1''' - - # position - pos = a.EST[['X','Y','Z']].values - # velocity - vel = a.VELi[['X','Y','Z']].values # units should be km/s if XYZ are in km - - # radial component - u_u = pos / norm(pos)[:,_np.newaxis] - - # ------------------------- - # General implementation - # # cross-track component - # w = _np.cross(pos,vel) - # w_u = w / norm(w)[:,_np.newaxis] - # # along-track component - # v_u = _np.cross(w_u,u_u) - # ------------------------- - - # Simplified implementation - # along-track component - v_u = vel / norm(vel)[:,_np.newaxis] - # cross-track component - w_u = _np.cross(u_u,v_u) # || not needed as u_v and v_u are orthogonal - - rot = _np.dstack([u_u,-v_u,-w_u]) # negative v_u and w_u are to be consistent with POD - return rot \ No newline at end of file diff --git a/scripts/log2snx.py b/scripts/log2snx.py deleted file mode 100755 index a65e0acf2..000000000 --- a/scripts/log2snx.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python3 - -''' -install rclone with curl https://rclone.org/install.sh | sudo bash -s beta - -rclone config file (content from rclone.conf): - -[cddis] -type = ftp -host = gdc.cddis.eosdis.nasa.gov -user = anonymous -pass = somerandomrandompasswordhash -explicit_tls = true - -[itrf] -type = ftp -host = itrf-ftp.ign.fr -user = anonymous -pass = somerandomrandompasswordhash - -[igs] -type = ftp -host = igs-rf.ign.fr -user = anonymous -pass = somerandomrandompasswordhash -''' - -import argparse -import os as _os - -from gn_lib.gn_io.igslog import write_meta_gather_master -description = ( -'''IGS log files parsing utility. Globs over log files using LOGGLOB expression and outputs SINEX metadata file. -If provided with frame and frame discontinuity files (soln), - will project the selected stations present in the frame to the datetime specified. -How to get the logfiles: -rclone sync igs:pub/sitelogs/ /data/station_logs/station_logs_IGS -vv -How to get the frame files: -rclone sync itrf:pub/itrf/itrf2014 /data/ITRF/itrf2014/ -vv --include "*{gnss,IGS-TRF}*" --transfers=10 -rclone sync igs:pub/ /data/TRF/ -vv --include "{IGS14,IGb14,IGb08,IGS08}/*" -see rclone config options inside this script file -Alternatively, use s3 bucket link to download all the files needed s3://peanpod/aux/''') - -def parse_arguments(): - parser = argparse.ArgumentParser(description=description) - parser.add_argument('-l', '--logglob', help='logs glob path (required)',required=True) - parser.add_argument('-r', '--rnxglob', help='rinex glob path (optional)',default=None,nargs="+") - parser.add_argument('-o', '--outfile', help='output file path (optional)',default= './meta_gather.snx') - parser.add_argument('-fs', '--frame_snx', type=file_path, help='frame sinex file path (optional)',default=None) - parser.add_argument('-fd', '--frame_dis', type=file_path, help='frame discontinuities file path (required with --frame_snx)',default=None) - parser.add_argument('-fp', '--frame_psd', type=file_path, help='frame psd file path (optional)',default=None) - parser.add_argument('-d', '--datetime', help='date to which project frame coordinates, default is today (optional)',default=None) - parser.add_argument('-n', '--num_threads', type=int, help='number of threads to run in parallel',default=None) - return parser.parse_args() - -def file_path(path): - if _os.path.isfile(path): - return path - else: - raise argparse.ArgumentTypeError(f"{path} is not a valid path") - -if __name__ == "__main__": - parsed_args = parse_arguments() - rnxglob = parsed_args.rnxglob - - if isinstance(rnxglob,list): - if (len(rnxglob)==1) & (rnxglob[0].find('*')!=-1): # it's rnx_glob expression (may be better to check if star is present) - rnxglob = rnxglob[0] - - write_meta_gather_master(logs_glob_path=parsed_args.logglob, - rnx_glob_path=rnxglob, - out_path=parsed_args.outfile, - frame_snx_path = parsed_args.frame_snx, - frame_soln_path = parsed_args.frame_dis, - frame_psd_path = parsed_args.frame_psd, - frame_datetime=parsed_args.datetime, - num_threads=parsed_args.num_threads) diff --git a/scripts/merge_sp3.py b/scripts/merge_sp3.py deleted file mode 100644 index 58c97732c..000000000 --- a/scripts/merge_sp3.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -'''sinex stations quick view''' -import argparse -import logging as _logging -import os as _os - -from gn_lib.gn_io.sp3 import merge_sp3, write_sp3 - - -def parse_arguments(): - parser = argparse.ArgumentParser(description='Merge sinex SITE/ID block and create html map.') - parser.add_argument('-s', '--sp3list',help='sp3 files paths',nargs="+",default=[]) - parser.add_argument('-c', '--clklist',help='clk paths',nargs="+",default=None) - parser.add_argument('-o', '--outpath',help='path to output dir',default=_os.curdir + '/merge.sp3') - return parser.parse_args() - -def file_path(path): - if _os.path.isfile(path): - return path - else: - raise argparse.ArgumentTypeError(f"{path} is not a valid path") - - - -if __name__ == "__main__": - parsed_args = parse_arguments() - _logging.info(msg=parsed_args.outpath) - if parsed_args.sp3list: - merged_df = merge_sp3(sp3_paths = parsed_args.sp3list, clk_paths = parsed_args.clklist) - write_sp3(sp3_df = merged_df, path = parsed_args.outpath) - else: - _logging.error(msg='sp3 list is empty') - - - diff --git a/scripts/plotting/plotAtt.m b/scripts/plotting/plotAtt.m new file mode 100644 index 000000000..8c65b3f02 --- /dev/null +++ b/scripts/plotting/plotAtt.m @@ -0,0 +1,127 @@ +clear; + +mission = 'SPIRE'; + +ephFile = 'SPIRE_2023.001.124.11.xyz'; % retrieved from ephemeris, e.g. SP3, SCA, etc. +attFile = 'SPIRE_2023.001.124.11_att.att'; % generated by debugAttitude() +gifFile = 'SPIRE_2023.001.124.11_body(att).gif'; % output gif file + +ephUnit = 1e3; % unit of ephemeris: km == 1e3, m == 1 + +scaleEarth = 0.2; % scale factor of plotted Earth +scaleAxis = 1e6; % scale factor of plotted axes + +delay = 0.05; % animation refresh interval + +eph = load(ephFile); +t = eph(:,1:2); % GPS time +r = eph(:,3:5)*ephUnit; % sat pos + +att = load(attFile); +eX = att(:, 3: 5); +eY = att(:, 6: 8); +eZ = att(:, 9:11); +eS = att(:,21:23); % eSun + +dX = eX*scaleAxis; +dY = eY*scaleAxis; +dZ = eZ*scaleAxis; +dS = eS*scaleAxis; + +X = r + dX; +Y = r + dY; +Z = r + dZ; +S = r + dS; + +figure('unit', 'normalized', 'position', [0, 0, 1, 1]); +hold on; +axis equal; +axis off; +box off; + +RE = 6371000*scaleEarth; + +load topo; +axesm('globe', 'grid', 'on', 'galtitude', RE); +meshm(topo, topolegend, [], RE); +demcmap(topo); +view(135, 30); + +title = title(mission); + +orbit = plot3(r(1,1), r(1,2), r(1,3), 'c'); +sat = scatter3(r(1,1), r(1,2), r(1,3), 'filled'); +radial= plot3([0; r(1,1)], [0; r(1,2)], [0; r(1,3)], 'm--'); + +quiver3(0, 0, 0, RE*2, 0, 0, 'r'); +quiver3(0, 0, 0, 0, RE*2, 0, 'g'); +quiver3(0, 0, 0, 0, 0, RE*2, 'b'); + +text(RE*2, 0, 0, 'X_E_C_E_F'); +text(0, RE*2, 0, 'Y_E_C_E_F'); +text(0, 0, RE*2, 'Z_E_C_E_F'); + +axisX = quiver3(r(1,1), r(1,2), r(1,3), dX(1,1), dX(1,2), dX(1,3), 'r'); +axisY = quiver3(r(1,1), r(1,2), r(1,3), dY(1,1), dY(1,2), dY(1,3), 'g'); +axisZ = quiver3(r(1,1), r(1,2), r(1,3), dZ(1,1), dZ(1,2), dZ(1,3), 'b'); +eSun = quiver3(r(1,1), r(1,2), r(1,3), dS(1,1), dS(1,2), dS(1,3), 'y'); + +textX = text(X(1,1), X(1,2), X(1,3), 'X_b'); +textY = text(Y(1,1), Y(1,2), Y(1,3), 'Y_b'); +textZ = text(Z(1,1), Z(1,2), Z(1,3), 'Z_b'); +textS = text(S(1,1), S(1,2), S(1,3), 'eSun'); + +eR(1,:) = r(1,:)/norm(r(1,:)); + +info = sprintf('GPS Week: %d\nSec of Week: %8.1f\nSat Pos: %12.3f %12.3f %12.3f\neSun: %9.6f %9.6f %9.6f\neX_b: %9.6f %9.6f %9.6f\neY_b: %9.6f %9.6f %9.6f\neZ_b: %9.6f %9.6f %9.6f\neZ_b*eSat = %9.6f\neY_b*eSun = %9.6f', ... + t (1,1), t (1,2), ... + r (1,1), r (1,2), r (1,3), ... + eS(1,1), eS(1,2), eS(1,3), ... + eX(1,1), eX(1,2), eX(1,3), ... + eY(1,1), eY(1,2), eY(1,3), ... + eZ(1,1), eZ(1,2), eZ(1,3), ... + dot(eZ(1,:), eR(1,:)), ... + dot(eY(1,:), eS(1,:))); + +dash = annotation('textbox', [0.7 0.8 0 0], 'string', info, 'fitboxtotext', 'on'); + +for i = 1:10:length(t) + + eR(i,:) = r(i,:)/norm(r(i,:)); + + info = sprintf('GPS Week: %d\nSec of Week: %8.1f\nSat Pos: %12.3f %12.3f %12.3f\neSun: %9.6f %9.6f %9.6f\neX_b: %9.6f %9.6f %9.6f\neY_b: %9.6f %9.6f %9.6f\neZ_b: %9.6f %9.6f %9.6f\neZ_b*eSat = %9.6f\neY_b*eSun = %9.6f', ... + t (i,1), t (i,2), ... + r (i,1), r (i,2), r (i,3), ... + eS(i,1), eS(i,2), eS(i,3), ... + eX(i,1), eX(i,2), eX(i,3), ... + eY(i,1), eY(i,2), eY(i,3), ... + eZ(i,1), eZ(i,2), eZ(i,3), ... + dot(eZ(i,:), eR(i,:)), ... + dot(eY(i,:), eS(i,:))); + set(dash, 'string', info); + + set(orbit, 'xdata', r(1:i,1), 'ydata', r(1:i,2), 'zdata', r(1:i,3)); + set(sat, 'xdata', r(i,1), 'ydata', r(i,2), 'zdata', r(i,3)); + set(radial,'xdata', [0; r(i,1)], 'ydata', [0; r(i,2)], 'zdata', [0; r(i,3)]); + + set(axisX, 'xdata', r(i,1), 'ydata', r(i,2), 'zdata', r(i,3), 'udata', dX(i,1), 'vdata', dX(i,2), 'wdata', dX(i,3)); + set(axisY, 'xdata', r(i,1), 'ydata', r(i,2), 'zdata', r(i,3), 'udata', dY(i,1), 'vdata', dY(i,2), 'wdata', dY(i,3)); + set(axisZ, 'xdata', r(i,1), 'ydata', r(i,2), 'zdata', r(i,3), 'udata', dZ(i,1), 'vdata', dZ(i,2), 'wdata', dZ(i,3)); + set(eSun, 'xdata', r(i,1), 'ydata', r(i,2), 'zdata', r(i,3), 'udata', dS(i,1), 'vdata', dS(i,2), 'wdata', dS(i,3)); + + set(textX, 'position', [X(i,1), X(i,2), X(i,3)]); + set(textY, 'position', [Y(i,1), Y(i,2), Y(i,3)]); + set(textZ, 'position', [Z(i,1), Z(i,2), Z(i,3)]); + set(textS, 'position', [S(i,1), S(i,2), S(i,3)]); + + pause(delay); + + frame = getframe(gcf); + im = frame2im(frame); + [imind, cm] = rgb2ind(im, 256); + if i == 1 + imwrite(imind, cm, gifFile, 'gif', 'loopcount', inf, 'delaytime', delay); + else + imwrite(imind, cm, gifFile, 'gif', 'writemode', 'append', 'delaytime', delay); + end +end diff --git a/scripts/plotting/plotAttGrace.m b/scripts/plotting/plotAttGrace.m new file mode 100644 index 000000000..6498a2003 --- /dev/null +++ b/scripts/plotting/plotAttGrace.m @@ -0,0 +1,176 @@ +clear; + +ephFileC = 'GFOC_RL02_22001.xyz'; % retrieved from ephemeris, e.g. SP3, SCA, etc. +ephFileD = 'GFOD_RL02_22001.xyz'; % retrieved from ephemeris, e.g. SP3, SCA, etc. +attFileC = 'GFOC_RL02_22001.att'; % generated by debugAttitude() +attFileD = 'GFOD_RL02_22001.att'; % generated by debugAttitude() +gifFile = 'GRACE_FO_RL02_19044_body.gif'; % output gif file + +ephUnit = 1e3; % unit of ephemeris: km == 1e3, m == 1 + +scaleEarth = 1; % scale factor of plotted Earth +scaleAxis = 8e4; % scale factor of plotted axes + +delay = 0.2; % animation refresh interval + +eph = load(ephFileC); +t_C = eph(281:end,1:2); % GPS time +r_C = eph(281:end,3:5); % sat pos + +eph = load(ephFileD); +t_D = eph(281:end,1:2); % GPS time +r_D = eph(281:end,3:5); % sat pos + +att = load(attFileC); +eX_C = att(281:end, 3: 5); +eY_C = att(281:end, 6: 8); +eZ_C = att(281:end, 9:11); + +att = load(attFileD); +eX_D = att(281:end, 3: 5); +eY_D = att(281:end, 6: 8); +eZ_D = att(281:end, 9:11); + +dX_C = eX_C*scaleAxis; +dY_C = eY_C*scaleAxis; +dZ_C = eZ_C*scaleAxis; + +dX_D = eX_D*scaleAxis; +dY_D = eY_D*scaleAxis; +dZ_D = eZ_D*scaleAxis; + +X_C = r_C + dX_C; +Y_C = r_C + dY_C; +Z_C = r_C + dZ_C; + +X_D = r_D + dX_D; +Y_D = r_D + dY_D; +Z_D = r_D + dZ_D; + +figure('unit', 'normalized', 'position', [0, 0, 1, 1]); +hold on; +axis equal; +axis off; +box off; + +RE = 6371000*scaleEarth; + +load topo; +axesm('globe', 'grid', 'on', 'galtitude', RE); +meshm(topo, topolegend, [], RE); +% demcmap(topo); + +xlim((r_C(1,1)+r_D(1,1))/2 + [-1.5e7, 1.5e7]); +ylim((r_C(1,2)+r_D(1,2))/2 + [-1.5e7, 1.5e7]); +zlim((r_C(1,3)+r_D(1,3))/2 + [-1.5e7, 1.5e7]); + +az = rad2deg(atan2(r_C(1,2), r_C(1,1))) + 90; +el = 0; +view(az, el); +zoom(50); + +orbit_C = plot3(r_C(1,1), r_C(1,2), r_C(1,3), 'c'); +sat_C = scatter3(r_C(1,1), r_C(1,2), r_C(1,3), 'filled'); +radial_C= plot3([0; r_C(1,1)], [0; r_C(1,2)], [0; r_C(1,3)], 'm--'); + +orbit_D = plot3(r_D(1,1), r_D(1,2), r_D(1,3), 'c'); +sat_D = scatter3(r_D(1,1), r_D(1,2), r_D(1,3), 'filled'); +radial_D= plot3([0; r_D(1,1)], [0; r_D(1,2)], [0; r_D(1,3)], 'm--'); + +axisX_C = quiver3(r_C(1,1), r_C(1,2), r_C(1,3), dX_C(1,1), dX_C(1,2), dX_C(1,3), 'r'); +axisY_C = quiver3(r_C(1,1), r_C(1,2), r_C(1,3), dY_C(1,1), dY_C(1,2), dY_C(1,3), 'g'); +axisZ_C = quiver3(r_C(1,1), r_C(1,2), r_C(1,3), dZ_C(1,1), dZ_C(1,2), dZ_C(1,3), 'b'); + +axisX_D = quiver3(r_D(1,1), r_D(1,2), r_D(1,3), dX_D(1,1), dX_D(1,2), dX_D(1,3), 'r'); +axisY_D = quiver3(r_D(1,1), r_D(1,2), r_D(1,3), dY_D(1,1), dY_D(1,2), dY_D(1,3), 'g'); +axisZ_D = quiver3(r_D(1,1), r_D(1,2), r_D(1,3), dZ_D(1,1), dZ_D(1,2), dZ_D(1,3), 'b'); + +textX_C = text(X_C(1,1), X_C(1,2), X_C(1,3), 'X_b'); +textY_C = text(Y_C(1,1), Y_C(1,2), Y_C(1,3), 'Y_b'); +textZ_C = text(Z_C(1,1), Z_C(1,2), Z_C(1,3), 'Z_b'); + +textX_D = text(X_D(1,1), X_D(1,2), X_D(1,3), 'X_b'); +textY_D = text(Y_D(1,1), Y_D(1,2), Y_D(1,3), 'Y_b'); +textZ_D = text(Z_D(1,1), Z_D(1,2), Z_D(1,3), 'Z_b'); + +eR_C(1,:) = r_C(1,:)/norm(r_C(1,:)); + +eR_D(1,:) = r_D(1,:)/norm(r_D(1,:)); + +info = sprintf('Mission: GRACE-FO\nGPS Week: %d\nSec of Week: %8.1f\n\nGRACE-C\nSat Pos: %12.3f %12.3f %12.3f\neX_b: %9.6f %9.6f %9.6f\neY_b: %9.6f %9.6f %9.6f\neZ_b: %9.6f %9.6f %9.6f\neZ_b*eSat = %9.6f\n\nGRACE-D\nSat Pos: %12.3f %12.3f %12.3f\neX_b: %9.6f %9.6f %9.6f\neY_b: %9.6f %9.6f %9.6f\neZ_b: %9.6f %9.6f %9.6f\neZ_b*eSat = %9.6f', ... + t_C (1,1), t_C (1,2), ... + r_C (1,1), r_C (1,2), r_C (1,3), ... + eX_C(1,1), eX_C(1,2), eX_C(1,3), ... + eY_C(1,1), eY_C(1,2), eY_C(1,3), ... + eZ_C(1,1), eZ_C(1,2), eZ_C(1,3), ... + dot(eZ_C(1,:), eR_C(1,:)), ... + r_D (1,1), r_D (1,2), r_D (1,3), ... + eX_D(1,1), eX_D(1,2), eX_D(1,3), ... + eY_D(1,1), eY_D(1,2), eY_D(1,3), ... + eZ_D(1,1), eZ_D(1,2), eZ_D(1,3), ... + dot(eZ_D(1,:), eR_D(1,:))); +dash = annotation('textbox', [0.7 0.8 0 0], 'string', info, 'fitboxtotext', 'on'); + +for i = 1:length(t_C) + + xlim((r_C(i,1)+r_D(i,1))/2 + [-1.5e7, 1.5e7]); + ylim((r_C(i,2)+r_D(i,2))/2 + [-1.5e7, 1.5e7]); + zlim((r_C(i,3)+r_D(i,3))/2 + [-1.5e7, 1.5e7]); + + az = rad2deg(atan2(r_C(i,2), r_C(i,1))) + 90; + el = 0; + view(az, el); + + eR_C(i,:) = r_C(i,:)/norm(r_C(i,:)); + + eR_D(i,:) = r_D(i,:)/norm(r_D(i,:)); + + info = sprintf('Mission: GRACE-FO\nGPS Week: %d\nSec of Week: %8.1f\n\nGRACE-C\nSat Pos: %12.3f %12.3f %12.3f\neX_b: %9.6f %9.6f %9.6f\neY_b: %9.6f %9.6f %9.6f\neZ_b: %9.6f %9.6f %9.6f\neZ_b*eSat = %9.6f\n\nGRACE-D\nSat Pos: %12.3f %12.3f %12.3f\neX_b: %9.6f %9.6f %9.6f\neY_b: %9.6f %9.6f %9.6f\neZ_b: %9.6f %9.6f %9.6f\neZ_b*eSat = %9.6f', ... + t_C (i,1), t_C (i,2), ... + r_C (i,1), r_C (i,2), r_C (i,3), ... + eX_C(i,1), eX_C(i,2), eX_C(i,3), ... + eY_C(i,1), eY_C(i,2), eY_C(i,3), ... + eZ_C(i,1), eZ_C(i,2), eZ_C(i,3), ... + dot(eZ_C(i,:), eR_C(i,:)), ... + r_D (i,1), r_D (i,2), r_D (i,3), ... + eX_D(i,1), eX_D(i,2), eX_D(i,3), ... + eY_D(i,1), eY_D(i,2), eY_D(i,3), ... + eZ_D(i,1), eZ_D(i,2), eZ_D(i,3), ... + dot(eZ_D(i,:), eR_D(i,:))); + set(dash, 'string', info); + + set(orbit_C, 'xdata', r_C(1:i,1), 'ydata', r_C(1:i,2), 'zdata', r_C(1:i,3)); + set(sat_C, 'xdata', r_C(i,1), 'ydata', r_C(i,2), 'zdata', r_C(i,3)); + set(radial_C,'xdata', [0; r_C(i,1)], 'ydata', [0; r_C(i,2)], 'zdata', [0; r_C(i,3)]); + + set(orbit_D, 'xdata', r_D(1:i,1), 'ydata', r_D(1:i,2), 'zdata', r_D(1:i,3)); + set(sat_D, 'xdata', r_D(i,1), 'ydata', r_D(i,2), 'zdata', r_D(i,3)); + set(radial_D,'xdata', [0; r_D(i,1)], 'ydata', [0; r_D(i,2)], 'zdata', [0; r_D(i,3)]); + + set(axisX_C, 'xdata', r_C(i,1), 'ydata', r_C(i,2), 'zdata', r_C(i,3), 'udata', dX_C(i,1), 'vdata', dX_C(i,2), 'wdata', dX_C(i,3)); + set(axisY_C, 'xdata', r_C(i,1), 'ydata', r_C(i,2), 'zdata', r_C(i,3), 'udata', dY_C(i,1), 'vdata', dY_C(i,2), 'wdata', dY_C(i,3)); + set(axisZ_C, 'xdata', r_C(i,1), 'ydata', r_C(i,2), 'zdata', r_C(i,3), 'udata', dZ_C(i,1), 'vdata', dZ_C(i,2), 'wdata', dZ_C(i,3)); + + set(axisX_D, 'xdata', r_D(i,1), 'ydata', r_D(i,2), 'zdata', r_D(i,3), 'udata', dX_D(i,1), 'vdata', dX_D(i,2), 'wdata', dX_D(i,3)); + set(axisY_D, 'xdata', r_D(i,1), 'ydata', r_D(i,2), 'zdata', r_D(i,3), 'udata', dY_D(i,1), 'vdata', dY_D(i,2), 'wdata', dY_D(i,3)); + set(axisZ_D, 'xdata', r_D(i,1), 'ydata', r_D(i,2), 'zdata', r_D(i,3), 'udata', dZ_D(i,1), 'vdata', dZ_D(i,2), 'wdata', dZ_D(i,3)); + + set(textX_C, 'position', [X_C(i,1), X_C(i,2), X_C(i,3)]); + set(textY_C, 'position', [Y_C(i,1), Y_C(i,2), Y_C(i,3)]); + set(textZ_C, 'position', [Z_C(i,1), Z_C(i,2), Z_C(i,3)]); + + set(textX_D, 'position', [X_D(i,1), X_D(i,2), X_D(i,3)]); + set(textY_D, 'position', [Y_D(i,1), Y_D(i,2), Y_D(i,3)]); + set(textZ_D, 'position', [Z_D(i,1), Z_D(i,2), Z_D(i,3)]); + + pause(delay); + + frame = getframe(gcf); + im = frame2im(frame); + [imind, cm] = rgb2ind(im, 256); + if i == 1 + imwrite(imind, cm, gifFile, 'gif', 'loopcount', inf, 'delaytime', delay); + elseif mod(i, 5) == 1 + imwrite(imind, cm, gifFile, 'gif', 'writemode', 'append', 'delaytime', delay); + end +end diff --git a/scripts/requirements.txt b/scripts/requirements.txt index f2d349ce0..88151b99b 100644 --- a/scripts/requirements.txt +++ b/scripts/requirements.txt @@ -7,6 +7,7 @@ git+https://github.com/bmatv/python-unlzw.git # memory leak patched plotext==4.2 requests_oauthlib==1.3.1 werkzeug==2.2.2 +gnssanalysis==0.0.18 requests==2.27.1 numpy==1.21.6 # don't care of specific numpy and pandas versions pandas==1.1.0 #MongoDash required version diff --git a/scripts/setup.py b/scripts/setup.py deleted file mode 100644 index c1259a9a6..000000000 --- a/scripts/setup.py +++ /dev/null @@ -1,13 +0,0 @@ -# setup script for gn_lib - -from setuptools import setup, find_packages - -setup( - name="gn_lib", - version="0.0.1", - description="Ginan python scripts", - author="ga.gov.au", - packages=find_packages(include=["gn_lib","gn_lib.*"]), - scripts=["diffutil.py","log2snx.py","merge_sp3.py","snx2map.py","sp3_compare.py"], - install_requires=["plotext==4.2", "scipy", "requests", "requests_oauthlib"], -) diff --git a/scripts/slr_plot.py b/scripts/slr_plot.py new file mode 100644 index 000000000..09450269b --- /dev/null +++ b/scripts/slr_plot.py @@ -0,0 +1,89 @@ +import numpy as np +import pandas as pd +import plotly.express as px + +import os +import sys + +""" +This script is used to generate plots of the slr pea output data. +NOTE: This script only supports Linux distributions and may have problems on Windows (include WSL) + +To use this script you must have the following python packages installed: + - kaleido==0.2.1 + - pandas==1.1.0 + - plotly==5.3.1 + +Usage: +This script accepts 6 arguments, described as follows +`python3 slr_plot.py ` + + - file_name: This is the location of the csv file that holds the output of the slr pea, must have appropriate headers + - sat_name: This is the name of the satellite that you want to generate plots for (use "all" to generate plots for all satellites in the data) + - rec_name: This is the 4 letter code of the reciever station that you want to generate plots for (use "all" to generate plots for all stations) + - x_data: This is the column header of the output data that you want to have on the x axis (use "sequential" for sequential x-axis plots) + - y_data: This is the column header of the output data that you want to have on the y axis + +""" + +WRITE_FILE_PATH = "plots" + +def generate_plot(df, x_name, y_name, sat_name, rec_name): + if x_name == "sequential": + fig = px.scatter(df, x=list(range(len(df[y_name]))), y=y_name, title=f"{y_name} against {x_name} for {sat_name} and {rec_name}") + else: + fig = px.scatter(df, x=x_name, y=y_name, title=f"{y_name} against {x_name} for {sat_name} and {rec_name}") + + os.makedirs(WRITE_FILE_PATH, exist_ok=True) + + fig.write_image(f"{WRITE_FILE_PATH}/{sat_name}_{rec_name}_{x_name}_{y_name}.png", engine="auto") + +def generate_all_in_one(df, x_name, y_name): + if x_name == "sequential": + fig = px.scatter(df, x=list(range(len(df[y_name]))), y=y_name, title=f"{y_name} against {x_name} for all satellites and recievers") + else: + fig = px.scatter(df, x=x_name, y=y_name, title=f"{y_name} against {x_name} for all satellites and recievers") + + os.makedirs(WRITE_FILE_PATH, exist_ok=True) + + fig.write_image(f"{WRITE_FILE_PATH}/all_{x_name}_{y_name}.png", engine="auto") + + +def main(): + + if (len(sys.argv) != 6): + print("ERROR: Incorrect number of arguments. \n \ + Correct usage is: python3 slr_plot.py \n \ + Example: python3 slr_plot.py data.csv lageos1 YARL unix value \ + ") + return + + # Reading in command line arguments + file_name = sys.argv[1] + sat_name = sys.argv[2] + rec_name = sys.argv[3] + x_name = sys.argv[4] + y_name = sys.argv[5] + + df = pd.read_csv(file_name, skipinitialspace=True) + + if sat_name == "all": + sat_list = df["sat"].unique() + else: + sat_list = [sat_name] + + if rec_name == "all": + rec_list = df["rec"].unique() + else: + rec_list = [rec_name] + + + for sat in sat_list: + sat_df = df[df["sat"] == sat] + for rec in rec_list: + sat_rec_df = sat_df[sat_df["rec"] == rec] + generate_plot(sat_rec_df, x_name, y_name, sat, rec) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/snx2map.py b/scripts/snx2map.py deleted file mode 100644 index 9f20d3ecf..000000000 --- a/scripts/snx2map.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 - -'''sinex stations quick view''' -import argparse -import logging as _logging -import os as _os - -import pandas as _pd -import plotly.express as px - -from gn_lib.gn_io.sinex import _get_snx_id - - -def parse_arguments(): - parser = argparse.ArgumentParser(description='Parse sinex SITE/ID block and create html map.') - parser.add_argument('-i', '--snxpath', type=file_path,help='path to sinex file (.snx/.ssc). Can be compressed with LZW (.Z)',nargs="+",required=True) - parser.add_argument('-o', '--outdir', type=dir_path,help='path to output dir',default=None) - return parser.parse_args() - -def dir_path(path): - if _os.path.isdir(path): - return path - else: - raise argparse.ArgumentTypeError(f"{path} is not a valid path") - -def file_path(path): - if _os.path.isfile(path): - return path - else: - raise argparse.ArgumentTypeError(f"{path} is not a valid path") - -def snxid2html(paths, outdir = '/data/acs/pea/output/'): - '''Creates sinex station map html''' - size = 0.5 - buf = [] - title='' - - _logging.getLogger().setLevel(_logging.INFO) - _logging.info(msg=paths) - - for path in paths: - basename = _os.path.basename(path) - tmp_df = _get_snx_id(path) - tmp_df['SIZE'] = size - tmp_df['SNXFILE'] = basename - title += f'{tmp_df.shape[0]} stations [{basename}]
' - buf.append(tmp_df) - size **=1.8 - id_df = _pd.concat(buf) - - fig = px.scatter_geo(id_df, lon='LON',lat='LAT',title=title, - size='SIZE',color='SNXFILE',size_max=18, - hover_name="CODE", # column added to hover information - hover_data = ['PT','DOMES'], - projection="natural earth") - - - filename = ('gather_map' if len(paths)>1 else _os.path.basename(paths[0]))+'.html' - save_path = _os.path.join(_os.path.curdir if outdir is None else outdir,filename) - fig.write_html(save_path) - _logging.info(msg=f'html saved to {save_path}') - -if __name__ == "__main__": - parsed_args = parse_arguments() - snxid2html(paths=parsed_args.snxpath,outdir=parsed_args.outdir) diff --git a/scripts/snx_util.py b/scripts/snx_util.py deleted file mode 100644 index a961f31ae..000000000 --- a/scripts/snx_util.py +++ /dev/null @@ -1,23 +0,0 @@ -'''sinex read and gather routines''' - -# from gn_lib.gn_aux import sync_snx_sites as _sync_snx_sites -from gn_lib.gn_io.sinex import gather_sinex as _gather_sinex - - -def snx2df(glob_expr, n_threads=4, unconstrain=False): - '''An example demo function that can be run on sinex files dataset''' - return _gather_sinex(glob_expr=glob_expr, - n_threads=n_threads, - unconstrain=unconstrain) - - -# HOW TO USE. DEMO -# Need to first download the sample files -# This can be done with rclone. CDDIS ftp instance needs explicit TLS -# ./rclone sync cddis:pub/gps/products /data/cddis/ --include "/{19[8-9][0-9],20[0-3][0-9]}/{cod,esa,jpl}*[0-9][0-9][0-9][0-9][0-9].snx.Z" -vv --transfers 10 --checkers 10 -# ./rclone sync cddis:pub/gps/products /data/cddis/ --include "/{19[8-9][0-9],20[0-3][0-9]}/igs*[0-9][0-9][0-9][0-9][0-9].ssc.Z" -vv --transfers 10 --checkers 10 -# cod_gather = snx2df('/data/cddis/*/cod*.snx.Z') -# esa_gather = snx2df('/data/cddis/*/esa*.snx.Z') -# igs_gather = snx2df('/data/cddis/*/igs*.ssc.Z') -# jpl_gather = snx2df('/data/cddis/*/jpl*.snx.Z') -# cod_gather_c,esa_gather_c,igs_gather_c,jpl_gather_c = sync_snx_sites(cod_gather,esa_gather,igs_gather,jpl_gather) diff --git a/scripts/sp3_compare.py b/scripts/sp3_compare.py deleted file mode 100644 index 1f898e413..000000000 --- a/scripts/sp3_compare.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 - -'''Utility for comparing sp3 files''' -import argparse -import os as _os - -import matplotlib.pyplot as plt - -from gn_lib.gn_io.sp3 import diff_sp3_rac, read_sp3 -from gn_lib.gn_plot import plot_vec - -def parse_arguments(): - parser = argparse.ArgumentParser(description='Compares two sp3 files and outputs RAC residuals plot. Sp3 files can be LZW (.Z) or Gzip (.gz) compressed. \ - If -hlm parameter provided, will do the helmert transormation of sp3_b file into the frame of sp3_a and append sp3_b residuals plot to the bottom. \ - The helmert inversion mode is used to selected at which step to do the parameter computation and transfomation: ECF (as in sp3) or ECI.') - parser.add_argument('sp3_a',type=file_path,help='path to the main sp3 file which will be used to interpolate velocities and compute RAC rotation matrix') - parser.add_argument('sp3_b',type=file_path,help='path to another sp3 file') - parser.add_argument('-hlm', '--hlm_mode', help='helmert inversion mode',default=None, choices=(None, 'ECF', 'ECI')) - parser.add_argument('-o', '--output', help='plot output path',default=None) - return parser.parse_args() - -def file_path(path): - if _os.path.exists(path): - return path - else: - raise argparse.ArgumentTypeError(f"{path} is not a valid path") - -if __name__ == "__main__": - parsed_args = parse_arguments() - - sp3_a = read_sp3(parsed_args.sp3_a) - sp3_b = read_sp3(parsed_args.sp3_b) - a = diff_sp3_rac(sp3_a, sp3_b,hlm_mode=parsed_args.hlm_mode) - - extended_plot = a.attrs['hlm_mode'] is not None - - fig = plt.figure(figsize=(10, 5+5*extended_plot),dpi=100) - gs = fig.add_gridspec(3+3*extended_plot, hspace=0.2) - ax = gs.subplots(sharex=True, sharey=False) - plot_vec(axes=ax,df=a.unstack()['EST_RAC'] * 100000,axes_idx=[1,2,0]) - - if extended_plot: # append hlm residuals plot if transformation has been selected - line = plt.Line2D([0,1],[0.49,0.49], transform=fig.transFigure, color="black",ls='--') - plt.text(0.015,0.485,va = 'top', - s=f"{a.attrs['sp3_b']} - {a.attrs['sp3_b']}" + f" (HLM in {a.attrs['hlm_mode']})\nResiduals shown are in ECI frame", - rotation=90, transform=fig.transFigure, fontfamily='monospace') - fig.add_artist(line) - - plot_vec(axes=ax,df=a.attrs['hlm'][1].RES.unstack() * 100000,axes_idx=[3,4,5],legend=False) - - hlm = a.attrs['hlm'][0][0].reshape(-1).tolist() - hlm_txt = ('HLM coeffiecients:\n\n' - + f'Tx {hlm[0]:13.5e}\nTy {hlm[1]:13.5e}\nTz {hlm[2]:13.5e}\n' - + f'Rx {hlm[0]:13.5e}\nRy {hlm[1]:13.5e}\nRz {hlm[2]:13.5e}\n' - + f'μ {hlm[0]:13.5e}') - text2 = plt.text(0.815,0.485,s=hlm_txt,va = 'top', transform=fig.transFigure, fontfamily='monospace') - - fig.suptitle(a.attrs['sp3_a'] + ' - ' + a.attrs['sp3_b'] + (f" (HLM in {a.attrs['hlm_mode']})" if extended_plot else ""),y=0.92) - fig.patch.set_facecolor('w') #white background (non-transparent) - fig.legend(bbox_to_anchor = (.955,.89),ncol=2,fontsize=8) - plt.subplots_adjust(right=0.8) - - fig.savefig(f"{a.attrs['sp3_a'].split('.')[0]}-{a.attrs['sp3_b'].split('.')[0]}.pdf" if parsed_args.output is None else parsed_args.output) diff --git a/scripts/tests/test_datetime.py b/scripts/tests/test_datetime.py index 76ca9daaa..57452ce13 100644 --- a/scripts/tests/test_datetime.py +++ b/scripts/tests/test_datetime.py @@ -1,4 +1,4 @@ -from gn_lib.gn_datetime import GPSDate +from gnssanalysis.gn_datetime import GPSDate import numpy as np def test_gpsdate(): diff --git a/scripts/webhooks/postHook.sh b/scripts/webhooks/postHook.sh new file mode 100755 index 000000000..5b5e2bee5 --- /dev/null +++ b/scripts/webhooks/postHook.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +curl --trace-ascii \ +-F "payload_json='{'username': 'Clark Kent', 'content': 'Test two'}'" \ +-F 'file1=@plots.pdf' \ +"https://discord.com/api/webhooks/1044032882672422942/s7MFwrbikBEIdjAGdKeX3cjBBtIgKhMqkdixnfHuiTo_5sJyy4Rx0-Ycv9hcccMfeYYR" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 60e7d9377..e301f54c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8...3.22) cmake_policy(SET CMP0063 NEW) -cmake_policy(SET CMP0054 OLD) project(ginan) + enable_language(Fortran) set (CMAKE_Fortran_SOURCE_FILE_EXTENSIONS "f95;F90;f90;for;f;F") @@ -40,7 +40,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-overflow") -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-narrowing") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-but-set-variable") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-truncation") @@ -48,8 +48,11 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-variable") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-switch") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-dangling-else") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-misleading-indentation") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-var-tracking-assignments") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-var-tracking-assignments") +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-truncation") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-extern-c-compat") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-zero-length") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -frecursive") @@ -66,10 +69,25 @@ set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wno-unused-label") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wno-maybe-uninitialized") -option(ENABLE_UNIT_TESTS "ENABLE_UNIT_TESTS" OFF) -option(BUILD_DOC "BUILD_DOCUMENTATION" OFF) -option(ENABLE_PARALLELISATION "ENABLE_PARALLELISATION" ON) -option(ENABLE_OPTIMISATION "ENABLE_OPTIMISATION" ON) + + +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + + option(ENABLE_UNIT_TESTS "ENABLE_UNIT_TESTS" OFF) + option(BUILD_DOC "BUILD_DOCUMENTATION" ON) + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + option(ENABLE_PARALLELISATION "ENABLE_PARALLELISATION" OFF) + option(ENABLE_OPTIMISATION "ENABLE_OPTIMISATION" OFF) +else () + option(ENABLE_PARALLELISATION "ENABLE_PARALLELISATION" ON) + option(ENABLE_OPTIMISATION "ENABLE_OPTIMISATION" ON) +endif () + + + if(ENABLE_UNIT_TESTS) message(STATUS "Setting unit tests on") @@ -120,17 +138,13 @@ if (BUILD_DOC) else (DOXYGEN_FOUND) - message("Doxygen need to be installed to generate the doxygen documentation") - + message("Doxygen need to be installed to generate the doxygen documentation, disabling") + set(BUILD_DOC off CACHE BOOL "" FORCE) endif (DOXYGEN_FOUND) endif() -#set debug if nothing else is set. -set(default_build_type "Debug") -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE ${default_build_type}) -endif() + set(CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package(Threads REQUIRED) @@ -192,35 +206,53 @@ else() message(STATUS "Mongocxx was not found") endif() - message(STATUS "Found C++ compiler: " ${CMAKE_CXX_COMPILER_VERSION}) + message(STATUS "Found C++ compiler: " ${CMAKE_CXX_COMPILER_ID} " " ${CMAKE_CXX_COMPILER_VERSION}) IF(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.git) FIND_PACKAGE(Git) IF(GIT_FOUND) - EXECUTE_PROCESS( - COMMAND ${GIT_EXECUTABLE} describe --tags --always - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." - OUTPUT_VARIABLE "GINAN_COMMIT_VERSION" - OUTPUT_STRIP_TRAILING_WHITESPACE) EXECUTE_PROCESS( - COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." - OUTPUT_VARIABLE "GINAN_BRANCH_NAME" - OUTPUT_STRIP_TRAILING_WHITESPACE) - + COMMAND ${GIT_EXECUTABLE} log --pretty=format:'%h' -n 1 + OUTPUT_VARIABLE GINAN_COMMIT_HASH + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + EXECUTE_PROCESS( + COMMAND bash -c "git diff --quiet --exit-code || echo -dirty " + OUTPUT_VARIABLE GINAN_COMMIT_DIFF + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + EXECUTE_PROCESS( + COMMAND ${GIT_EXECUTABLE} describe --exact-match --tags + OUTPUT_VARIABLE GINAN_COMMIT_TAG ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + EXECUTE_PROCESS( + COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + OUTPUT_VARIABLE GINAN_BRANCH_NAME + OUTPUT_STRIP_TRAILING_WHITESPACE + ) EXECUTE_PROCESS( COMMAND ${GIT_EXECUTABLE} log -1 --format=%cd --date=local - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." - OUTPUT_VARIABLE "GINAN_COMMIT_DATE" - OUTPUT_STRIP_TRAILING_WHITESPACE) + OUTPUT_VARIABLE "GINAN_COMMIT_DATE" + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if (GINAN_COMMIT_TAG STREQUAL "") + set(GINAN_COMMIT_TAG "untagged") + endif() + string(REGEX REPLACE "'" "" GINAN_COMMIT_HASH "${GINAN_COMMIT_HASH}") + SET(GINAN_COMMIT_VERSION "${GINAN_COMMIT_TAG}-${GINAN_COMMIT_HASH}${GINAN_COMMIT_DIFF}") MESSAGE(STATUS "Git branch tag: ${GINAN_COMMIT_VERSION}") MESSAGE(STATUS "Git branch: ${GINAN_BRANCH_NAME}") ELSE(GIT_FOUND) - SET(GINAN_COMMIT_VERSION 0) - SET(GINAN_BRANCH_NAME "unknown branch") + SET(GINAN_COMMIT_VERSION "N/A") + SET(GINAN_COMMIT_DIFF "N/A") + SET(GINAN_COMMIT_TAG "N/A") + SET(GINAN_BRANCH_NAME "N/A") MESSAGE( STATUS "Git not found: ${GINAN_COMMIT_VERSION}" ) ENDIF(GIT_FOUND) ELSE() diff --git a/src/cpp/3rdparty/EigenDenseBaseAddons.h b/src/cpp/3rdparty/EigenDenseBaseAddons.h new file mode 100644 index 000000000..95a00a0a2 --- /dev/null +++ b/src/cpp/3rdparty/EigenDenseBaseAddons.h @@ -0,0 +1,38 @@ + +#pragma once + +friend class boost::serialization::access; + +template +void save(Archive & ar, const unsigned int version) const +{ + derived().eval(); + const Index rows = derived().rows(); + const Index cols = derived().cols(); + ar & rows; + ar & cols; + + for (Index j = 0; j < cols; j++) + for (Index i = 0; i < rows; i++) + ar & derived().coeff(i, j); +} + +template +void load(Archive & ar, const unsigned int version) +{ + Index rows, cols; + ar & rows; + ar & cols; + if ( rows != derived().rows() + || cols != derived().cols()) + { + derived().resize(rows, cols); + } + ar & boost::serialization::make_array(derived().data(), derived().size()); +} + +template +void serialize(Archive & ar, const unsigned int file_version) +{ + boost::serialization::split_member(ar, *this, file_version); +} diff --git a/src/cpp/3rdparty/beast/root_certificates.hpp b/src/cpp/3rdparty/beast/root_certificates.hpp new file mode 100644 index 000000000..6a7396cc5 --- /dev/null +++ b/src/cpp/3rdparty/beast/root_certificates.hpp @@ -0,0 +1,3963 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_EXAMPLE_COMMON_ROOT_CERTIFICATES_HPP +#define BOOST_BEAST_EXAMPLE_COMMON_ROOT_CERTIFICATES_HPP + +#include +#include + +/* + PLEASE READ + + These root certificates here are included just to make the + SSL client examples work. They are NOT intended to be + illustrative of best-practices for performing TLS certificate + verification. + + A REAL program which needs to verify the authenticity of a + server IP address resolved from a given DNS name needs to + consult the operating system specific certificate store + to validate the chain of signatures, compare the domain name + properly against the domain name in the certificate, check + the certificate revocation list, and probably do some other + things. + + ALL of these operations are entirely outside the scope of + both Boost.Beast and Boost.Asio. + + See (work in progress): + https://github.com/djarek/certify + + tl;dr: root_certificates.hpp should not be used in production code +*/ + +namespace ssl = boost::asio::ssl; // from + +namespace detail { + +inline +void +load_root_certificates(ssl::context& ctx, boost::system::error_code& ec) +{ + std::string cert = + "# ACCVRAIZ1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE\n" + "AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw\n" + "CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ\n" + "BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND\n" + "VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb\n" + "qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY\n" + "HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo\n" + "G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA\n" + "lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr\n" + "IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/\n" + "0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH\n" + "k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47\n" + "4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO\n" + "m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa\n" + "cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl\n" + "uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI\n" + "KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls\n" + "ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG\n" + "AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2\n" + "VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT\n" + "VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG\n" + "CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA\n" + "cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA\n" + "QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA\n" + "7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA\n" + "cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA\n" + "QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA\n" + "czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu\n" + "aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt\n" + "aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud\n" + "DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF\n" + "BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp\n" + "D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU\n" + "JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m\n" + "AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD\n" + "vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms\n" + "tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH\n" + "7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h\n" + "I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA\n" + "h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF\n" + "d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H\n" + "pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# AC RAIZ FNMT-RCM\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx\n" + "CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ\n" + "WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ\n" + "BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG\n" + "Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/\n" + "yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf\n" + "BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz\n" + "WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF\n" + "tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z\n" + "374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC\n" + "IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL\n" + "mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7\n" + "wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS\n" + "MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2\n" + "ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet\n" + "UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw\n" + "AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H\n" + "YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3\n" + "LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD\n" + "nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1\n" + "RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM\n" + "LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf\n" + "77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N\n" + "JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm\n" + "fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp\n" + "6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp\n" + "1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B\n" + "9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok\n" + "RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv\n" + "uu8wd+RU4riEmViAqhOLUTpPSPaLtrM=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Actalis Authentication Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE\n" + "BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w\n" + "MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290\n" + "IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC\n" + "SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1\n" + "ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB\n" + "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv\n" + "UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX\n" + "4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9\n" + "KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/\n" + "gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb\n" + "rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ\n" + "51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F\n" + "be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe\n" + "KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F\n" + "v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn\n" + "fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7\n" + "jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz\n" + "ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt\n" + "ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL\n" + "e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70\n" + "jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz\n" + "WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V\n" + "SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j\n" + "pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX\n" + "X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok\n" + "fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R\n" + "K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU\n" + "ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU\n" + "LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT\n" + "LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# AffirmTrust Commercial\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE\n" + "BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz\n" + "dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL\n" + "MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp\n" + "cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" + "AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP\n" + "Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr\n" + "ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL\n" + "MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1\n" + "yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr\n" + "VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/\n" + "nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ\n" + "KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG\n" + "XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj\n" + "vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt\n" + "Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g\n" + "N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC\n" + "nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# AffirmTrust Networking\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE\n" + "BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz\n" + "dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL\n" + "MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp\n" + "cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" + "AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y\n" + "YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua\n" + "kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL\n" + "QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp\n" + "6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG\n" + "yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i\n" + "QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ\n" + "KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO\n" + "tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu\n" + "QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ\n" + "Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u\n" + "olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48\n" + "x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# AffirmTrust Premium\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE\n" + "BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz\n" + "dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG\n" + "A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U\n" + "cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf\n" + "qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ\n" + "JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ\n" + "+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS\n" + "s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5\n" + "HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7\n" + "70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG\n" + "V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S\n" + "qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S\n" + "5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia\n" + "C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX\n" + "OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE\n" + "FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\n" + "BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2\n" + "KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg\n" + "Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B\n" + "8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ\n" + "MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc\n" + "0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ\n" + "u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF\n" + "u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH\n" + "YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8\n" + "GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO\n" + "RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e\n" + "KeC2uAloGRwYQw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# AffirmTrust Premium ECC\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC\n" + "VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ\n" + "cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ\n" + "BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt\n" + "VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D\n" + "0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9\n" + "ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G\n" + "A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G\n" + "A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs\n" + "aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I\n" + "flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Amazon Root CA 1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF\n" + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" + "b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL\n" + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" + "b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj\n" + "ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM\n" + "9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw\n" + "IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6\n" + "VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L\n" + "93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm\n" + "jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" + "AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA\n" + "A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI\n" + "U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs\n" + "N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv\n" + "o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU\n" + "5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy\n" + "rqXRfboQnoZsG4q5WTP468SQvvG5\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Amazon Root CA 2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF\n" + "ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6\n" + "b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL\n" + "MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv\n" + "b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK\n" + "gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ\n" + "W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg\n" + "1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K\n" + "8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r\n" + "2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me\n" + "z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR\n" + "8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj\n" + "mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz\n" + "7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6\n" + "+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI\n" + "0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB\n" + "Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm\n" + "UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2\n" + "LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY\n" + "+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS\n" + "k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl\n" + "7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm\n" + "btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl\n" + "urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+\n" + "fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63\n" + "n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE\n" + "76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H\n" + "9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT\n" + "4PsJYGw=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Amazon Root CA 3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5\n" + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n" + "Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n" + "A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n" + "Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl\n" + "ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j\n" + "QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr\n" + "ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr\n" + "BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM\n" + "YyRIHN8wfdVoOw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Amazon Root CA 4\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5\n" + "MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g\n" + "Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG\n" + "A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg\n" + "Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi\n" + "9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk\n" + "M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB\n" + "/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB\n" + "MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw\n" + "CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW\n" + "1KyLa2tJElMzrdfkviT8tQp21KW8EA==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Atos TrustedRoot 2011\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE\n" + "AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG\n" + "EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM\n" + "FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC\n" + "REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp\n" + "Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM\n" + "VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+\n" + "SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ\n" + "4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L\n" + "cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi\n" + "eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV\n" + "HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG\n" + "A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3\n" + "DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j\n" + "vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP\n" + "DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc\n" + "maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D\n" + "lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv\n" + "KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Autoridad de Certificacion Firmaprofesional CIF A62634068\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE\n" + "BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h\n" + "cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy\n" + "MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg\n" + "Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi\n" + "MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9\n" + "thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM\n" + "cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG\n" + "L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i\n" + "NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h\n" + "X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b\n" + "m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy\n" + "Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja\n" + "EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T\n" + "KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF\n" + "6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh\n" + "OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD\n" + "VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD\n" + "VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp\n" + "cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv\n" + "ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl\n" + "AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF\n" + "661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9\n" + "am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1\n" + "ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481\n" + "PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS\n" + "3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k\n" + "SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF\n" + "3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM\n" + "ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g\n" + "StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz\n" + "Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB\n" + "jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Baltimore CyberTrust Root\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ\n" + "RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD\n" + "VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX\n" + "DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y\n" + "ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy\n" + "VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr\n" + "mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr\n" + "IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK\n" + "mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu\n" + "XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy\n" + "dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye\n" + "jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1\n" + "BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3\n" + "DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92\n" + "9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx\n" + "jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0\n" + "Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz\n" + "ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS\n" + "R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Buypass Class 2 Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd\n" + "MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg\n" + "Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow\n" + "TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw\n" + "HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB\n" + "BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr\n" + "6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV\n" + "L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91\n" + "1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx\n" + "MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ\n" + "QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB\n" + "arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr\n" + "Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi\n" + "FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS\n" + "P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN\n" + "9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP\n" + "AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz\n" + "uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h\n" + "9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s\n" + "A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t\n" + "OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo\n" + "+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7\n" + "KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2\n" + "DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us\n" + "H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ\n" + "I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7\n" + "5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h\n" + "3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz\n" + "Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Buypass Class 3 Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd\n" + "MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg\n" + "Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow\n" + "TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw\n" + "HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB\n" + "BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y\n" + "ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E\n" + "N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9\n" + "tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX\n" + "0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c\n" + "/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X\n" + "KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY\n" + "zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS\n" + "O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D\n" + "34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP\n" + "K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3\n" + "AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv\n" + "Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj\n" + "QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV\n" + "cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS\n" + "IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2\n" + "HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa\n" + "O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv\n" + "033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u\n" + "dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE\n" + "kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41\n" + "3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD\n" + "u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq\n" + "4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# CA Disig Root R2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV\n" + "BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu\n" + "MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy\n" + "MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx\n" + "EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw\n" + "ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe\n" + "NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH\n" + "PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I\n" + "x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe\n" + "QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR\n" + "yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO\n" + "QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912\n" + "H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ\n" + "QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD\n" + "i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs\n" + "nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1\n" + "rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud\n" + "DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI\n" + "hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM\n" + "tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf\n" + "GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb\n" + "lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka\n" + "+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal\n" + "TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i\n" + "nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3\n" + "gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr\n" + "G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os\n" + "zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x\n" + "L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# CFCA EV ROOT\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD\n" + "TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y\n" + "aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx\n" + "MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j\n" + "aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP\n" + "T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03\n" + "sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL\n" + "TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5\n" + "/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp\n" + "7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz\n" + "EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt\n" + "hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP\n" + "a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot\n" + "aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg\n" + "TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV\n" + "PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv\n" + "cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL\n" + "tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd\n" + "BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB\n" + "ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT\n" + "ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL\n" + "jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS\n" + "ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy\n" + "P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19\n" + "xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d\n" + "Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN\n" + "5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe\n" + "/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z\n" + "AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ\n" + "5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# COMODO Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB\n" + "gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n" + "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV\n" + "BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw\n" + "MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl\n" + "YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P\n" + "RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0\n" + "aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3\n" + "UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI\n" + "2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8\n" + "Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp\n" + "+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+\n" + "DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O\n" + "nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW\n" + "/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g\n" + "PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u\n" + "QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY\n" + "SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv\n" + "IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/\n" + "RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4\n" + "zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd\n" + "BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB\n" + "ZQ==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# COMODO ECC Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL\n" + "MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" + "BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT\n" + "IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw\n" + "MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy\n" + "ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N\n" + "T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv\n" + "biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR\n" + "FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J\n" + "cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW\n" + "BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\n" + "BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm\n" + "fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv\n" + "GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# COMODO RSA Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB\n" + "hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G\n" + "A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV\n" + "BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5\n" + "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT\n" + "EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR\n" + "Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh\n" + "dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR\n" + "6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X\n" + "pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC\n" + "9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV\n" + "/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf\n" + "Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z\n" + "+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w\n" + "qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah\n" + "SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC\n" + "u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf\n" + "Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq\n" + "crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E\n" + "FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB\n" + "/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl\n" + "wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM\n" + "4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV\n" + "2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna\n" + "FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ\n" + "CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK\n" + "boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke\n" + "jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL\n" + "S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb\n" + "QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl\n" + "0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB\n" + "NVOFBkpdn627G190\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Certigna\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV\n" + "BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X\n" + "DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ\n" + "BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3\n" + "DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4\n" + "QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny\n" + "gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw\n" + "zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q\n" + "130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2\n" + "JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw\n" + "DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw\n" + "ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT\n" + "AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj\n" + "AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG\n" + "9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h\n" + "bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc\n" + "fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu\n" + "HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w\n" + "t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw\n" + "WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Certigna Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw\n" + "WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw\n" + "MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x\n" + "MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD\n" + "VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX\n" + "BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" + "ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO\n" + "ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M\n" + "CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu\n" + "I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm\n" + "TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh\n" + "C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf\n" + "ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz\n" + "IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT\n" + "Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k\n" + "JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5\n" + "hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB\n" + "GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n" + "FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of\n" + "1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov\n" + "L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo\n" + "dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr\n" + "aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq\n" + "hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L\n" + "6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG\n" + "HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6\n" + "0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB\n" + "lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi\n" + "o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1\n" + "gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v\n" + "faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63\n" + "Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh\n" + "jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw\n" + "3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Certum Trusted Network CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM\n" + "MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D\n" + "ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU\n" + "cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3\n" + "WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg\n" + "Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw\n" + "IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B\n" + "AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH\n" + "UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM\n" + "TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU\n" + "BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM\n" + "kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x\n" + "AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV\n" + "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV\n" + "HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y\n" + "sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL\n" + "I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8\n" + "J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY\n" + "VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI\n" + "03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Certum Trusted Network CA 2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB\n" + "gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu\n" + "QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG\n" + "A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz\n" + "OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ\n" + "VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp\n" + "ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3\n" + "b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA\n" + "DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn\n" + "0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB\n" + "OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE\n" + "fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E\n" + "Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m\n" + "o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i\n" + "sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW\n" + "OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez\n" + "Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS\n" + "adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n\n" + "3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD\n" + "AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC\n" + "AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ\n" + "F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf\n" + "CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29\n" + "XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm\n" + "djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/\n" + "WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb\n" + "AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq\n" + "P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko\n" + "b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj\n" + "XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P\n" + "5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi\n" + "DrW5viSP\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Chambers of Commerce Root - 2008\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD\n" + "VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0\n" + "IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3\n" + "MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz\n" + "IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz\n" + "MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj\n" + "dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw\n" + "EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp\n" + "MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G\n" + "CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9\n" + "28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq\n" + "VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q\n" + "DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR\n" + "5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL\n" + "ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a\n" + "Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl\n" + "UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s\n" + "+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5\n" + "Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj\n" + "ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx\n" + "hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV\n" + "HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1\n" + "+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN\n" + "YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t\n" + "L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy\n" + "ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt\n" + "IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV\n" + "HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w\n" + "DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW\n" + "PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF\n" + "5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1\n" + "glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH\n" + "FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2\n" + "pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD\n" + "xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG\n" + "tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq\n" + "jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De\n" + "fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg\n" + "OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ\n" + "d0jQ\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Comodo AAA Services root\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb\n" + "MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow\n" + "GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj\n" + "YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL\n" + "MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE\n" + "BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM\n" + "GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" + "ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua\n" + "BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe\n" + "3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4\n" + "YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR\n" + "rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm\n" + "ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU\n" + "oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF\n" + "MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v\n" + "QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t\n" + "b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF\n" + "AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q\n" + "GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz\n" + "Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2\n" + "G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi\n" + "l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3\n" + "smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Cybertrust Global Root\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG\n" + "A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh\n" + "bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE\n" + "ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS\n" + "b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5\n" + "7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS\n" + "J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y\n" + "HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP\n" + "t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz\n" + "FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY\n" + "XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/\n" + "MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw\n" + "hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js\n" + "MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA\n" + "A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj\n" + "Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx\n" + "XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o\n" + "omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc\n" + "A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW\n" + "WL1WMRJOEcgh4LMRkWXbtKaIOM5V\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# D-TRUST Root Class 3 CA 2 2009\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF\n" + "MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD\n" + "bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha\n" + "ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM\n" + "HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB\n" + "BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03\n" + "UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42\n" + "tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R\n" + "ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM\n" + "lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp\n" + "/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G\n" + "A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G\n" + "A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj\n" + "dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy\n" + "MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl\n" + "cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js\n" + "L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL\n" + "BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni\n" + "acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0\n" + "o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K\n" + "zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8\n" + "PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y\n" + "Johw1+qRzT65ysCQblrGXnRl11z+o+I=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# D-TRUST Root Class 3 CA 2 EV 2009\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF\n" + "MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD\n" + "bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw\n" + "NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV\n" + "BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI\n" + "hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn\n" + "ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0\n" + "3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z\n" + "qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR\n" + "p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8\n" + "HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw\n" + "ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea\n" + "HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw\n" + "Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh\n" + "c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E\n" + "RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt\n" + "dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku\n" + "Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp\n" + "3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05\n" + "nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF\n" + "CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na\n" + "xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX\n" + "KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DST Root CA X3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/\n" + "MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" + "DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow\n" + "PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD\n" + "Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" + "AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O\n" + "rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq\n" + "OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b\n" + "xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw\n" + "7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD\n" + "aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV\n" + "HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG\n" + "SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69\n" + "ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr\n" + "AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz\n" + "R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5\n" + "JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo\n" + "Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert Assured ID Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv\n" + "b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG\n" + "EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl\n" + "cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi\n" + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c\n" + "JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP\n" + "mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+\n" + "wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4\n" + "VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/\n" + "AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB\n" + "AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW\n" + "BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun\n" + "pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC\n" + "dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf\n" + "fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm\n" + "NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx\n" + "H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe\n" + "+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert Assured ID Root G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv\n" + "b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG\n" + "EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl\n" + "cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi\n" + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA\n" + "n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc\n" + "biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp\n" + "EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA\n" + "bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu\n" + "YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB\n" + "AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW\n" + "BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI\n" + "QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I\n" + "0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni\n" + "lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9\n" + "B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv\n" + "ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo\n" + "IhNzbM8m9Yop5w==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert Assured ID Root G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw\n" + "CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\n" + "ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg\n" + "RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV\n" + "UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\n" + "Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq\n" + "hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf\n" + "Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q\n" + "RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/\n" + "BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD\n" + "AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY\n" + "JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv\n" + "6pZjamVFkpUBtA==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert Global Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n" + "QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT\n" + "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" + "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG\n" + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB\n" + "CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97\n" + "nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt\n" + "43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P\n" + "T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4\n" + "gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO\n" + "BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR\n" + "TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw\n" + "DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr\n" + "hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg\n" + "06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF\n" + "PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls\n" + "YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk\n" + "CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert Global Root G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n" + "MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n" + "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n" + "b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n" + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n" + "2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n" + "1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n" + "q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n" + "tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n" + "vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n" + "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n" + "5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n" + "1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n" + "NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n" + "Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n" + "8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n" + "pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n" + "MrY=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert Global Root G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw\n" + "CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu\n" + "ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe\n" + "Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw\n" + "EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x\n" + "IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF\n" + "K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG\n" + "fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO\n" + "Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd\n" + "BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx\n" + "AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/\n" + "oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8\n" + "sycX\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert High Assurance EV Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n" + "ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL\n" + "MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n" + "LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug\n" + "RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm\n" + "+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW\n" + "PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM\n" + "xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB\n" + "Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3\n" + "hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg\n" + "EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF\n" + "MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA\n" + "FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec\n" + "nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z\n" + "eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF\n" + "hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2\n" + "Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe\n" + "vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep\n" + "+OkuE6N36B9K\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# DigiCert Trusted Root G4\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi\n" + "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n" + "d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg\n" + "RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV\n" + "UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu\n" + "Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG\n" + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y\n" + "ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If\n" + "xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV\n" + "ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO\n" + "DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ\n" + "jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/\n" + "CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi\n" + "EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM\n" + "fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY\n" + "uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK\n" + "chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t\n" + "9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\n" + "hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD\n" + "ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2\n" + "SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd\n" + "+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc\n" + "fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa\n" + "sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N\n" + "cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N\n" + "0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie\n" + "4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI\n" + "r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1\n" + "/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm\n" + "gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# E-Tugra Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV\n" + "BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC\n" + "aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV\n" + "BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1\n" + "Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz\n" + "MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+\n" + "BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp\n" + "em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN\n" + "ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n" + "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY\n" + "B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH\n" + "D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF\n" + "Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo\n" + "q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D\n" + "k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH\n" + "fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut\n" + "dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM\n" + "ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8\n" + "zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn\n" + "rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX\n" + "U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6\n" + "Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5\n" + "XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF\n" + "Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR\n" + "HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY\n" + "GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c\n" + "77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3\n" + "+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK\n" + "vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6\n" + "FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl\n" + "yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P\n" + "AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD\n" + "y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d\n" + "NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# EC-ACC\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB\n" + "8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy\n" + "dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1\n" + "YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3\n" + "dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh\n" + "IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD\n" + "LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG\n" + "EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g\n" + "KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD\n" + "ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu\n" + "bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg\n" + "ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN\n" + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R\n" + "85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm\n" + "4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV\n" + "HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd\n" + "QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t\n" + "lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB\n" + "o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E\n" + "BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4\n" + "opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo\n" + "dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW\n" + "ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN\n" + "AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y\n" + "/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k\n" + "SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy\n" + "Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS\n" + "Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl\n" + "nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# EE Certification Centre Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1\n" + "MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1\n" + "czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG\n" + "CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy\n" + "MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl\n" + "ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS\n" + "b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB\n" + "AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy\n" + "euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO\n" + "bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw\n" + "WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d\n" + "MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE\n" + "1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD\n" + "VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/\n" + "zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB\n" + "BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF\n" + "BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV\n" + "v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG\n" + "E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u\n" + "uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW\n" + "iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v\n" + "GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Entrust.net Premium 2048 Secure Server CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML\n" + "RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp\n" + "bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5\n" + "IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp\n" + "ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3\n" + "MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3\n" + "LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp\n" + "YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG\n" + "A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp\n" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq\n" + "K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe\n" + "sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX\n" + "MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT\n" + "XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/\n" + "HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH\n" + "4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" + "HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub\n" + "j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo\n" + "U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf\n" + "zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b\n" + "u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+\n" + "bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er\n" + "fF6adulZkMV8gzURZVE=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Entrust Root Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC\n" + "VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0\n" + "Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW\n" + "KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl\n" + "cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw\n" + "NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw\n" + "NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy\n" + "ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV\n" + "BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ\n" + "KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo\n" + "Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4\n" + "4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9\n" + "KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI\n" + "rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi\n" + "94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB\n" + "sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi\n" + "gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo\n" + "kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE\n" + "vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA\n" + "A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t\n" + "O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua\n" + "AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP\n" + "9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/\n" + "eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m\n" + "0vdXcDazv/wor3ElhVsT/h5/WrQ8\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Entrust Root Certification Authority - EC1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG\n" + "A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3\n" + "d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu\n" + "dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq\n" + "RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy\n" + "MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD\n" + "VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0\n" + "L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g\n" + "Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD\n" + "ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi\n" + "A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt\n" + "ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH\n" + "Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O\n" + "BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC\n" + "R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX\n" + "hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Entrust Root Certification Authority - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC\n" + "VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50\n" + "cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs\n" + "IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz\n" + "dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy\n" + "NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu\n" + "dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt\n" + "dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0\n" + "aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj\n" + "YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" + "AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T\n" + "RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN\n" + "cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW\n" + "wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1\n" + "U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0\n" + "jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP\n" + "BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN\n" + "BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/\n" + "jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ\n" + "Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v\n" + "1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R\n" + "nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH\n" + "VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Entrust Root Certification Authority - G4\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw\n" + "gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL\n" + "Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg\n" + "MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw\n" + "BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0\n" + "MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT\n" + "MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1\n" + "c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ\n" + "bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg\n" + "Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B\n" + "AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ\n" + "2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E\n" + "T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j\n" + "5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM\n" + "C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T\n" + "DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX\n" + "wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A\n" + "2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm\n" + "nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8\n" + "dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl\n" + "N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj\n" + "c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD\n" + "VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS\n" + "5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS\n" + "Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr\n" + "hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/\n" + "B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI\n" + "AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw\n" + "H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+\n" + "b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk\n" + "2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol\n" + "IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk\n" + "5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY\n" + "n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GDCA TrustAUTH R5 ROOT\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE\n" + "BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ\n" + "IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0\n" + "MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV\n" + "BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w\n" + "HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF\n" + "AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj\n" + "Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj\n" + "TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u\n" + "KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj\n" + "qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm\n" + "MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12\n" + "ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP\n" + "zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk\n" + "L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC\n" + "jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA\n" + "HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC\n" + "AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB\n" + "/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg\n" + "p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm\n" + "DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5\n" + "COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry\n" + "L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf\n" + "JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg\n" + "IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io\n" + "2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV\n" + "09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ\n" + "XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq\n" + "T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe\n" + "MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GTS Root R1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH\n" + "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n" + "QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n" + "MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n" + "cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB\n" + "AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM\n" + "f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX\n" + "mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7\n" + "zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P\n" + "fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc\n" + "vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4\n" + "Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp\n" + "zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO\n" + "Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW\n" + "k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+\n" + "DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF\n" + "lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" + "HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW\n" + "Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1\n" + "d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z\n" + "XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR\n" + "gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3\n" + "d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv\n" + "J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg\n" + "DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM\n" + "+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy\n" + "F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9\n" + "SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws\n" + "E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GTS Root R2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH\n" + "MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n" + "QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n" + "MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n" + "cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB\n" + "AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv\n" + "CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg\n" + "GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu\n" + "XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd\n" + "re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu\n" + "PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1\n" + "mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K\n" + "8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj\n" + "x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR\n" + "nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0\n" + "kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok\n" + "twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n" + "HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp\n" + "8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT\n" + "vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT\n" + "z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA\n" + "pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb\n" + "pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB\n" + "R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R\n" + "RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk\n" + "0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC\n" + "5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF\n" + "izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn\n" + "yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GTS Root R3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw\n" + "CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n" + "MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n" + "MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n" + "Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA\n" + "IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout\n" + "736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A\n" + "DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n" + "DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk\n" + "fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA\n" + "njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GTS Root R4\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw\n" + "CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n" + "MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n" + "MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n" + "Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA\n" + "IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu\n" + "hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l\n" + "xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n" + "DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0\n" + "CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx\n" + "sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GeoTrust Global CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT\n" + "MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i\n" + "YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG\n" + "EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg\n" + "R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9\n" + "9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq\n" + "fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv\n" + "iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU\n" + "1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+\n" + "bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW\n" + "MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA\n" + "ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l\n" + "uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn\n" + "Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS\n" + "tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF\n" + "PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un\n" + "hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV\n" + "5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GeoTrust Primary Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY\n" + "MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo\n" + "R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx\n" + "MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK\n" + "Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp\n" + "ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" + "AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9\n" + "AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA\n" + "ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0\n" + "7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W\n" + "kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI\n" + "mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G\n" + "A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ\n" + "KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1\n" + "6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl\n" + "4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K\n" + "oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj\n" + "UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU\n" + "AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GeoTrust Primary Certification Authority - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL\n" + "MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj\n" + "KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2\n" + "MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0\n" + "eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV\n" + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw\n" + "NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV\n" + "BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH\n" + "MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL\n" + "So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal\n" + "tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n" + "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG\n" + "CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT\n" + "qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz\n" + "rD6ogRLQy7rQkgu2npaqBA+K\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GeoTrust Primary Certification Authority - G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB\n" + "mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT\n" + "MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s\n" + "eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv\n" + "cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ\n" + "BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg\n" + "MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0\n" + "BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\n" + "LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz\n" + "+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm\n" + "hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn\n" + "5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W\n" + "JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL\n" + "DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC\n" + "huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\n" + "HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB\n" + "AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB\n" + "zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN\n" + "kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD\n" + "AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH\n" + "SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G\n" + "spki4cErx5z481+oghLrGREt\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GeoTrust Universal CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW\n" + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy\n" + "c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE\n" + "BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0\n" + "IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV\n" + "VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8\n" + "cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT\n" + "QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh\n" + "F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v\n" + "c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w\n" + "mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd\n" + "VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX\n" + "teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ\n" + "f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe\n" + "Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+\n" + "nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB\n" + "/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY\n" + "MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG\n" + "9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc\n" + "aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX\n" + "IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn\n" + "ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z\n" + "uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN\n" + "Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja\n" + "QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW\n" + "koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9\n" + "ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt\n" + "DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm\n" + "bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GeoTrust Universal CA 2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW\n" + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy\n" + "c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD\n" + "VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1\n" + "c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n" + "AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81\n" + "WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG\n" + "FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq\n" + "XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL\n" + "se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb\n" + "KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd\n" + "IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73\n" + "y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt\n" + "hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc\n" + "QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4\n" + "Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV\n" + "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV\n" + "HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ\n" + "KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z\n" + "dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ\n" + "L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr\n" + "Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo\n" + "ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY\n" + "T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz\n" + "GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m\n" + "1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV\n" + "OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH\n" + "6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX\n" + "QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GlobalSign ECC Root CA - R4\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk\n" + "MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH\n" + "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\n" + "DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\n" + "QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\n" + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ\n" + "FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw\n" + "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F\n" + "uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX\n" + "kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs\n" + "ewv4n4Q=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GlobalSign ECC Root CA - R5\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk\n" + "MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH\n" + "bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX\n" + "DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD\n" + "QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu\n" + "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc\n" + "8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke\n" + "hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD\n" + "VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI\n" + "KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg\n" + "515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO\n" + "xwy8p2Fp8fc74SrL+SvzZpA3\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GlobalSign Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG\n" + "A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv\n" + "b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw\n" + "MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i\n" + "YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT\n" + "aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ\n" + "jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp\n" + "xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp\n" + "1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG\n" + "snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ\n" + "U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8\n" + "9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E\n" + "BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B\n" + "AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz\n" + "yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE\n" + "38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP\n" + "AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad\n" + "DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME\n" + "HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GlobalSign Root CA - R2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G\n" + "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp\n" + "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1\n" + "MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG\n" + "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" + "hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL\n" + "v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8\n" + "eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq\n" + "tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd\n" + "C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa\n" + "zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB\n" + "mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH\n" + "V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n\n" + "bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG\n" + "3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs\n" + "J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO\n" + "291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS\n" + "ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd\n" + "AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7\n" + "TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GlobalSign Root CA - R3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G\n" + "A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp\n" + "Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4\n" + "MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG\n" + "A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI\n" + "hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8\n" + "RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT\n" + "gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm\n" + "KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd\n" + "QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ\n" + "XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw\n" + "DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o\n" + "LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU\n" + "RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp\n" + "jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK\n" + "6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX\n" + "mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs\n" + "Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH\n" + "WD9f\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# GlobalSign Root CA - R6\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg\n" + "MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh\n" + "bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx\n" + "MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET\n" + "MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ\n" + "KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI\n" + "xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k\n" + "ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD\n" + "aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw\n" + "LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw\n" + "1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX\n" + "k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2\n" + "SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h\n" + "bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n\n" + "WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY\n" + "rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce\n" + "MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD\n" + "AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu\n" + "bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN\n" + "nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt\n" + "Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61\n" + "55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj\n" + "vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf\n" + "cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz\n" + "oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp\n" + "nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs\n" + "pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v\n" + "JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R\n" + "8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4\n" + "5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Global Chambersign Root - 2008\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD\n" + "VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0\n" + "IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3\n" + "MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD\n" + "aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx\n" + "MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy\n" + "cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG\n" + "A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl\n" + "BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI\n" + "hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed\n" + "KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7\n" + "G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2\n" + "zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4\n" + "ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG\n" + "HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2\n" + "Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V\n" + "yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e\n" + "beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r\n" + "6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh\n" + "wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog\n" + "zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW\n" + "BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr\n" + "ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp\n" + "ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk\n" + "cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt\n" + "YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC\n" + "CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow\n" + "KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI\n" + "hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ\n" + "UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz\n" + "X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x\n" + "fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz\n" + "a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd\n" + "Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd\n" + "SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O\n" + "AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso\n" + "M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge\n" + "v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z\n" + "09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Go Daddy Class 2 CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh\n" + "MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE\n" + "YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3\n" + "MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo\n" + "ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg\n" + "MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN\n" + "ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA\n" + "PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w\n" + "wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi\n" + "EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY\n" + "avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+\n" + "YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE\n" + "sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h\n" + "/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5\n" + "IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj\n" + "YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD\n" + "ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy\n" + "OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P\n" + "TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ\n" + "HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER\n" + "dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf\n" + "ReYNnyicsbkqWletNw+vHX/bvZ8=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Go Daddy Root Certificate Authority - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx\n" + "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT\n" + "EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp\n" + "ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz\n" + "NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH\n" + "EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE\n" + "AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw\n" + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD\n" + "E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH\n" + "/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy\n" + "DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh\n" + "GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR\n" + "tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA\n" + "AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE\n" + "FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX\n" + "WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu\n" + "9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr\n" + "gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo\n" + "2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO\n" + "LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI\n" + "4uJEvlz36hz1\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Hellenic Academic and Research Institutions ECC RootCA 2015\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN\n" + "BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl\n" + "c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl\n" + "bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv\n" + "b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ\n" + "BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj\n" + "YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5\n" + "MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0\n" + "dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg\n" + "QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa\n" + "jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC\n" + "MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi\n" + "C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep\n" + "lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof\n" + "TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Hellenic Academic and Research Institutions RootCA 2011\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix\n" + "RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1\n" + "dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p\n" + "YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw\n" + "NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK\n" + "EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl\n" + "cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl\n" + "c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB\n" + "BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz\n" + "dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ\n" + "fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns\n" + "bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD\n" + "75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP\n" + "FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV\n" + "HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp\n" + "5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu\n" + "b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA\n" + "A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p\n" + "6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8\n" + "TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7\n" + "dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys\n" + "Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI\n" + "l7WdmplNsDz4SgCbZN2fOUvRJ9e4\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Hellenic Academic and Research Institutions RootCA 2015\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix\n" + "DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k\n" + "IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT\n" + "N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v\n" + "dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG\n" + "A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh\n" + "ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx\n" + "QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1\n" + "dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC\n" + "AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA\n" + "4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0\n" + "AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10\n" + "4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C\n" + "ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV\n" + "9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD\n" + "gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6\n" + "Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq\n" + "NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko\n" + "LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc\n" + "Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV\n" + "HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd\n" + "ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I\n" + "XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI\n" + "M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot\n" + "9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V\n" + "Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea\n" + "j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh\n" + "X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ\n" + "l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf\n" + "bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4\n" + "pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK\n" + "e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0\n" + "vm9qp/UsQu0yrbYhnr68\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Hongkong Post Root CA 1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx\n" + "FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg\n" + "Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG\n" + "A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr\n" + "b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" + "AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ\n" + "jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn\n" + "PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh\n" + "ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9\n" + "nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h\n" + "q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED\n" + "MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC\n" + "mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3\n" + "7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB\n" + "oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs\n" + "EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO\n" + "fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi\n" + "AmvZWg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Hongkong Post Root CA 3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL\n" + "BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ\n" + "SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n\n" + "a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5\n" + "NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT\n" + "CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u\n" + "Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" + "AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO\n" + "dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI\n" + "VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV\n" + "9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY\n" + "2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY\n" + "vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt\n" + "bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb\n" + "x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+\n" + "l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK\n" + "TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj\n" + "Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP\n" + "BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e\n" + "i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw\n" + "DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG\n" + "7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk\n" + "MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr\n" + "gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk\n" + "GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS\n" + "3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm\n" + "Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+\n" + "l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c\n" + "JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP\n" + "L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa\n" + "LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG\n" + "mpv0\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# ISRG Root X1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" + "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" + "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" + "WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" + "ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" + "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" + "h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" + "0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" + "A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" + "T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" + "B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" + "B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" + "KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" + "OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" + "jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" + "qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" + "rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" + "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" + "hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" + "ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" + "3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" + "NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" + "ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" + "TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" + "jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" + "oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" + "4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" + "mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" + "emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# IdenTrust Commercial Root CA 1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK\n" + "MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu\n" + "VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw\n" + "MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw\n" + "JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG\n" + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT\n" + "3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU\n" + "+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp\n" + "S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1\n" + "bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi\n" + "T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL\n" + "vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK\n" + "Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK\n" + "dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT\n" + "c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv\n" + "l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N\n" + "iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\n" + "/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD\n" + "ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH\n" + "6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt\n" + "LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93\n" + "nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3\n" + "+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK\n" + "W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT\n" + "AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq\n" + "l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG\n" + "4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ\n" + "mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A\n" + "7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# IdenTrust Public Sector Root CA 1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN\n" + "MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu\n" + "VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN\n" + "MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0\n" + "MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi\n" + "MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7\n" + "ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy\n" + "RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS\n" + "bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF\n" + "/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R\n" + "3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw\n" + "EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy\n" + "9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V\n" + "GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ\n" + "2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV\n" + "WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD\n" + "W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/\n" + "BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN\n" + "AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj\n" + "t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV\n" + "DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9\n" + "TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G\n" + "lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW\n" + "mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df\n" + "WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5\n" + "+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ\n" + "tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA\n" + "GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv\n" + "8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Izenpe.com\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4\n" + "MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6\n" + "ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD\n" + "VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j\n" + "b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq\n" + "scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO\n" + "xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H\n" + "LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX\n" + "uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD\n" + "yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+\n" + "JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q\n" + "rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN\n" + "BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L\n" + "hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB\n" + "QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+\n" + "HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu\n" + "Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg\n" + "QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB\n" + "BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx\n" + "MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\n" + "AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA\n" + "A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb\n" + "laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56\n" + "awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo\n" + "JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw\n" + "LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT\n" + "VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk\n" + "LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb\n" + "UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/\n" + "QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+\n" + "naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls\n" + "QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# LuxTrust Global Root 2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQEL\n" + "BQAwRjELMAkGA1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNV\n" + "BAMMFkx1eFRydXN0IEdsb2JhbCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUw\n" + "MzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEWMBQGA1UECgwNTHV4VHJ1c3QgUy5B\n" + "LjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCCAiIwDQYJKoZIhvcN\n" + "AQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wmKb3F\n" + "ibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTem\n" + "hfY7RBi2xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1\n" + "EMShduxq3sVs35a0VkBCwGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsn\n" + "Xpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4\n" + "zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkmFRseTJIpgp7VkoGSQXAZ\n" + "96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niFwpN6cj5m\n" + "j5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4g\n" + "DEa/a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+\n" + "8kPREd8vZS9kzl8UubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2j\n" + "X5t/Lax5Gw5CMZdjpPuKadUiDTSQMC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmH\n" + "hFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGByuB\n" + "KwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5Lmx1eHRydXN0\n" + "Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT\n" + "+Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQEL\n" + "BQADggIBAGoZFO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9\n" + "BzZAcg4atmpZ1gDlaCDdLnINH2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTO\n" + "jFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW7MM3LGVYvlcAGvI1+ut7MV3CwRI9\n" + "loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIuZY+kt9J/Z93I055c\n" + "qqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWAVWe+\n" + "2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/\n" + "JEAdemrRTxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKre\n" + "zrnK+T+Tb/mjuuqlPpmt/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQf\n" + "LSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+\n" + "x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31IiyBMz2TWuJdGsE7RKlY6\n" + "oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Microsec e-Szigno Root CA 2009\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD\n" + "VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0\n" + "ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G\n" + "CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y\n" + "OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx\n" + "FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp\n" + "Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o\n" + "dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP\n" + "kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc\n" + "cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U\n" + "fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7\n" + "N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC\n" + "xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1\n" + "+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G\n" + "A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM\n" + "Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG\n" + "SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h\n" + "mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk\n" + "ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775\n" + "tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c\n" + "2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t\n" + "HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# NetLock Arany (Class Gold) Főtanúsítvány\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG\n" + "EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3\n" + "MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl\n" + "cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR\n" + "dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB\n" + "pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM\n" + "b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm\n" + "aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz\n" + "IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + "MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT\n" + "lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz\n" + "AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5\n" + "VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG\n" + "ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2\n" + "BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG\n" + "AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M\n" + "U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh\n" + "bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C\n" + "+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC\n" + "bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F\n" + "uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2\n" + "XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Network Solutions Certificate Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi\n" + "MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu\n" + "MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp\n" + "dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV\n" + "UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO\n" + "ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG\n" + "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz\n" + "c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP\n" + "OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl\n" + "mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF\n" + "BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4\n" + "qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw\n" + "gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB\n" + "BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu\n" + "bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp\n" + "dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8\n" + "6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/\n" + "h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH\n" + "/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv\n" + "wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN\n" + "pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# OISTE WISeKey Global Root GA CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB\n" + "ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly\n" + "aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl\n" + "ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w\n" + "NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G\n" + "A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD\n" + "VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX\n" + "SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + "MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR\n" + "VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2\n" + "w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF\n" + "mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg\n" + "4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9\n" + "4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw\n" + "DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw\n" + "EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx\n" + "SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2\n" + "ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8\n" + "vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa\n" + "hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi\n" + "Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ\n" + "/L7fCg0=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# OISTE WISeKey Global Root GB CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt\n" + "MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg\n" + "Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i\n" + "YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x\n" + "CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG\n" + "b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh\n" + "bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3\n" + "HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx\n" + "WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX\n" + "1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk\n" + "u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P\n" + "99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r\n" + "M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw\n" + "AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB\n" + "BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh\n" + "cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5\n" + "gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO\n" + "ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf\n" + "aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic\n" + "Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# OISTE WISeKey Global Root GC CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw\n" + "CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91\n" + "bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg\n" + "Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ\n" + "BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu\n" + "ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS\n" + "b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni\n" + "eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W\n" + "p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E\n" + "BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T\n" + "rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV\n" + "57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg\n" + "Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# QuoVadis Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC\n" + "TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0\n" + "aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0\n" + "aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz\n" + "MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw\n" + "IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR\n" + "dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG\n" + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp\n" + "li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D\n" + "rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ\n" + "WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug\n" + "F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU\n" + "xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC\n" + "Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv\n" + "dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw\n" + "ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl\n" + "IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh\n" + "c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy\n" + "ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh\n" + "Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI\n" + "KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T\n" + "KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq\n" + "y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p\n" + "dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD\n" + "VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL\n" + "MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk\n" + "fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8\n" + "7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R\n" + "cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y\n" + "mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW\n" + "xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK\n" + "SnQ2+Q==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# QuoVadis Root CA 1 G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL\n" + "BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc\n" + "BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00\n" + "MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\n" + "aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG\n" + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV\n" + "wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe\n" + "rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341\n" + "68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh\n" + "4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp\n" + "UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o\n" + "abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc\n" + "3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G\n" + "KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt\n" + "hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO\n" + "Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt\n" + "zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\n" + "BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD\n" + "ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC\n" + "MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2\n" + "cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN\n" + "qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5\n" + "YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv\n" + "b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2\n" + "8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k\n" + "NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj\n" + "ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp\n" + "q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt\n" + "nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# QuoVadis Root CA 2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x\n" + "GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv\n" + "b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV\n" + "BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W\n" + "YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa\n" + "GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg\n" + "Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J\n" + "WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB\n" + "rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp\n" + "+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1\n" + "ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i\n" + "Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz\n" + "PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og\n" + "/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH\n" + "oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI\n" + "yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud\n" + "EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2\n" + "A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL\n" + "MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT\n" + "ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f\n" + "BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn\n" + "g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl\n" + "fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K\n" + "WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha\n" + "B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc\n" + "hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR\n" + "TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD\n" + "mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z\n" + "ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y\n" + "4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza\n" + "8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# QuoVadis Root CA 2 G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL\n" + "BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc\n" + "BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00\n" + "MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\n" + "aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG\n" + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf\n" + "qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW\n" + "n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym\n" + "c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+\n" + "O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1\n" + "o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j\n" + "IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq\n" + "IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz\n" + "8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh\n" + "vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l\n" + "7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG\n" + "cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\n" + "BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD\n" + "ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66\n" + "AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC\n" + "roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga\n" + "W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n\n" + "lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE\n" + "+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV\n" + "csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd\n" + "dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg\n" + "KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM\n" + "HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4\n" + "WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# QuoVadis Root CA 3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x\n" + "GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv\n" + "b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV\n" + "BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W\n" + "YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM\n" + "V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB\n" + "4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr\n" + "H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd\n" + "8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv\n" + "vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT\n" + "mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe\n" + "btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc\n" + "T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt\n" + "WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ\n" + "c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A\n" + "4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD\n" + "VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG\n" + "CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0\n" + "aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0\n" + "aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu\n" + "dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw\n" + "czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G\n" + "A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC\n" + "TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg\n" + "Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0\n" + "7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem\n" + "d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd\n" + "+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B\n" + "4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN\n" + "t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x\n" + "DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57\n" + "k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s\n" + "zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j\n" + "Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT\n" + "mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK\n" + "4SVhM7JZG+Ju1zdXtg2pEto=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# QuoVadis Root CA 3 G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL\n" + "BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc\n" + "BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00\n" + "MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM\n" + "aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG\n" + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR\n" + "/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu\n" + "FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR\n" + "U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c\n" + "ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR\n" + "FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k\n" + "A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw\n" + "eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl\n" + "sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp\n" + "VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q\n" + "A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+\n" + "ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB\n" + "BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD\n" + "ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px\n" + "KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI\n" + "FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv\n" + "oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg\n" + "u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP\n" + "0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf\n" + "3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl\n" + "8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+\n" + "DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN\n" + "PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/\n" + "ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SSL.com EV Root Certification Authority ECC\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC\n" + "VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T\n" + "U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp\n" + "Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx\n" + "NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv\n" + "dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv\n" + "bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49\n" + "AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA\n" + "VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku\n" + "WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP\n" + "MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX\n" + "5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ\n" + "ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg\n" + "h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SSL.com EV Root Certification Authority RSA R2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV\n" + "BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE\n" + "CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy\n" + "dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy\n" + "MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G\n" + "A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD\n" + "DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy\n" + "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq\n" + "M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf\n" + "OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa\n" + "4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9\n" + "HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR\n" + "aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA\n" + "b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ\n" + "Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV\n" + "PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO\n" + "pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu\n" + "UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY\n" + "MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV\n" + "HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4\n" + "9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW\n" + "s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5\n" + "Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg\n" + "cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM\n" + "79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz\n" + "/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt\n" + "ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm\n" + "Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK\n" + "QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ\n" + "w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi\n" + "S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07\n" + "mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SSL.com Root Certification Authority ECC\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC\n" + "VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T\n" + "U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0\n" + "aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz\n" + "WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0\n" + "b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS\n" + "b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB\n" + "BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI\n" + "7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg\n" + "CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud\n" + "EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD\n" + "VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T\n" + "kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+\n" + "gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SSL.com Root Certification Authority RSA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE\n" + "BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK\n" + "DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp\n" + "Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz\n" + "OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv\n" + "dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv\n" + "bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN\n" + "AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R\n" + "xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX\n" + "qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC\n" + "C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3\n" + "6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh\n" + "/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF\n" + "YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E\n" + "JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc\n" + "US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8\n" + "ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm\n" + "+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi\n" + "M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV\n" + "HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G\n" + "A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV\n" + "cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc\n" + "Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs\n" + "PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/\n" + "q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0\n" + "cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr\n" + "a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I\n" + "H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y\n" + "K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu\n" + "nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf\n" + "oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY\n" + "Ic2wBlX7Jz9TkHCpBB5XJ7k=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SZAFIR ROOT CA2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL\n" + "BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6\n" + "ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw\n" + "NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L\n" + "cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg\n" + "Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN\n" + "QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT\n" + "3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw\n" + "3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6\n" + "3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5\n" + "BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN\n" + "XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD\n" + "AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF\n" + "AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw\n" + "8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG\n" + "nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP\n" + "oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy\n" + "d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg\n" + "LvWpCz/UXeHPhJ/iGcJfitYgHuNztw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SecureSign RootCA11\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr\n" + "MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG\n" + "A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0\n" + "MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp\n" + "Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD\n" + "QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz\n" + "i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8\n" + "h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV\n" + "MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9\n" + "UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni\n" + "8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC\n" + "h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD\n" + "VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB\n" + "AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm\n" + "KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ\n" + "X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr\n" + "QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5\n" + "pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN\n" + "QSdJQO7e5iNEOdyhIta6A/I=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SecureTrust CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI\n" + "MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x\n" + "FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz\n" + "MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv\n" + "cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN\n" + "AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz\n" + "Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO\n" + "0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao\n" + "wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj\n" + "7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS\n" + "8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT\n" + "BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB\n" + "/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg\n" + "JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC\n" + "NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3\n" + "6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/\n" + "3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm\n" + "D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS\n" + "CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR\n" + "3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Secure Global CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK\n" + "MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x\n" + "GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx\n" + "MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg\n" + "Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG\n" + "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ\n" + "iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa\n" + "/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ\n" + "jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI\n" + "HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7\n" + "sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w\n" + "gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF\n" + "MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw\n" + "KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG\n" + "AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L\n" + "URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO\n" + "H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm\n" + "I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY\n" + "iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc\n" + "f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Security Communication RootCA2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl\n" + "MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe\n" + "U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX\n" + "DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy\n" + "dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj\n" + "YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV\n" + "OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr\n" + "zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM\n" + "VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ\n" + "hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO\n" + "ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw\n" + "awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs\n" + "OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3\n" + "DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF\n" + "coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc\n" + "okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8\n" + "t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy\n" + "1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/\n" + "SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Security Communication Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY\n" + "MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t\n" + "dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5\n" + "WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD\n" + "VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3\n" + "DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8\n" + "9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ\n" + "DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9\n" + "Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N\n" + "QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ\n" + "xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G\n" + "A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T\n" + "AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG\n" + "kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr\n" + "Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5\n" + "Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU\n" + "JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot\n" + "RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Sonera Class 2 Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP\n" + "MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx\n" + "MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV\n" + "BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI\n" + "hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o\n" + "Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt\n" + "5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s\n" + "3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej\n" + "vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu\n" + "8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw\n" + "DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG\n" + "MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil\n" + "zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/\n" + "3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD\n" + "FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6\n" + "Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2\n" + "ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Staat der Nederlanden EV Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO\n" + "TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh\n" + "dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y\n" + "MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg\n" + "TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS\n" + "b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS\n" + "M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC\n" + "UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d\n" + "Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p\n" + "rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l\n" + "pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb\n" + "j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC\n" + "KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS\n" + "/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X\n" + "cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH\n" + "1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP\n" + "px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB\n" + "/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7\n" + "MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI\n" + "eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u\n" + "2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS\n" + "v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC\n" + "wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy\n" + "CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e\n" + "vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6\n" + "Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa\n" + "Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL\n" + "eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8\n" + "FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc\n" + "7uzXLg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Staat der Nederlanden Root CA - G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO\n" + "TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh\n" + "dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX\n" + "DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl\n" + "ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv\n" + "b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP\n" + "cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW\n" + "IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX\n" + "xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy\n" + "KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR\n" + "9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az\n" + "5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8\n" + "6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7\n" + "Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP\n" + "bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt\n" + "BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt\n" + "XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF\n" + "MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd\n" + "INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD\n" + "U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp\n" + "LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8\n" + "Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp\n" + "gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh\n" + "/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw\n" + "0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A\n" + "fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq\n" + "4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR\n" + "1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/\n" + "QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM\n" + "94B7IWcnMFk=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Starfield Class 2 CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n" + "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n" + "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n" + "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n" + "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n" + "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n" + "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n" + "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n" + "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n" + "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n" + "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n" + "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n" + "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n" + "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n" + "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n" + "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n" + "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n" + "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n" + "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n" + "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n" + "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n" + "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Starfield Root Certificate Authority - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n" + "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n" + "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n" + "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n" + "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n" + "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n" + "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n" + "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n" + "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n" + "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n" + "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n" + "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n" + "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n" + "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n" + "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n" + "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n" + "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n" + "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n" + "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n" + "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Starfield Services Root Certificate Authority - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx\n" + "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n" + "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs\n" + "ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5\n" + "MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD\n" + "VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy\n" + "ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy\n" + "dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI\n" + "hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p\n" + "OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2\n" + "8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K\n" + "Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe\n" + "hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk\n" + "6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw\n" + "DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q\n" + "AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI\n" + "bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB\n" + "ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z\n" + "qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd\n" + "iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn\n" + "0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN\n" + "sSi6\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SwissSign Gold CA - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\n" + "BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln\n" + "biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF\n" + "MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT\n" + "d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\n" + "CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8\n" + "76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+\n" + "bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c\n" + "6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE\n" + "emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd\n" + "MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt\n" + "MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y\n" + "MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y\n" + "FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi\n" + "aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM\n" + "gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB\n" + "qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7\n" + "lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn\n" + "8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov\n" + "L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6\n" + "45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO\n" + "UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5\n" + "O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC\n" + "bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv\n" + "GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a\n" + "77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC\n" + "hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3\n" + "92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp\n" + "Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w\n" + "ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt\n" + "Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# SwissSign Silver CA - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE\n" + "BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu\n" + "IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow\n" + "RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY\n" + "U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A\n" + "MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv\n" + "Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br\n" + "YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF\n" + "nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH\n" + "6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt\n" + "eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/\n" + "c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ\n" + "MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH\n" + "HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf\n" + "jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6\n" + "5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB\n" + "rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU\n" + "F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c\n" + "wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0\n" + "cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB\n" + "AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp\n" + "WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9\n" + "xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ\n" + "2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ\n" + "IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8\n" + "aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X\n" + "em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR\n" + "dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/\n" + "OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+\n" + "hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy\n" + "tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# T-TeleSec GlobalRoot Class 2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx\n" + "KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd\n" + "BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl\n" + "YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1\n" + "OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy\n" + "aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50\n" + "ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G\n" + "CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd\n" + "AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC\n" + "FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi\n" + "1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq\n" + "jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ\n" + "wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj\n" + "QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/\n" + "WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy\n" + "NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC\n" + "uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw\n" + "IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6\n" + "g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN\n" + "9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP\n" + "BSeOE6Fuwg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# T-TeleSec GlobalRoot Class 3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx\n" + "KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd\n" + "BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl\n" + "YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1\n" + "OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy\n" + "aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50\n" + "ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G\n" + "CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN\n" + "8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/\n" + "RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4\n" + "hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5\n" + "ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM\n" + "EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj\n" + "QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1\n" + "A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy\n" + "WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ\n" + "1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30\n" + "6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT\n" + "91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml\n" + "e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p\n" + "TpPDpFQUWw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx\n" + "GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp\n" + "bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w\n" + "KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0\n" + "BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy\n" + "dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG\n" + "EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll\n" + "IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU\n" + "QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT\n" + "TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg\n" + "LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7\n" + "a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr\n" + "LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr\n" + "N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X\n" + "YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/\n" + "iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f\n" + "AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH\n" + "V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n" + "BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh\n" + "AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf\n" + "IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4\n" + "lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c\n" + "8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf\n" + "lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# TWCA Global Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx\n" + "EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT\n" + "VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5\n" + "NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT\n" + "B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG\n" + "SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF\n" + "10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz\n" + "0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh\n" + "MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH\n" + "zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc\n" + "46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2\n" + "yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi\n" + "laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP\n" + "oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA\n" + "BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE\n" + "qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm\n" + "4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB\n" + "/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL\n" + "1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn\n" + "LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF\n" + "H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo\n" + "RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+\n" + "nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh\n" + "15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW\n" + "6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW\n" + "nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j\n" + "wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz\n" + "aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy\n" + "KwbQBM0=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# TWCA Root Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES\n" + "MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU\n" + "V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz\n" + "WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO\n" + "LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm\n" + "aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\n" + "AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE\n" + "AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH\n" + "K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX\n" + "RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z\n" + "rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx\n" + "3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" + "HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq\n" + "hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC\n" + "MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls\n" + "XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D\n" + "lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn\n" + "aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ\n" + "YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Taiwan GRCA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/\n" + "MQswCQYDVQQGEwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmlj\n" + "YXRpb24gQXV0aG9yaXR5MB4XDTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1ow\n" + "PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp\n" + "Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB\n" + "AJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qNw8XR\n" + "IePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1q\n" + "gQdW8or5BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKy\n" + "yhwOeYHWtXBiCAEuTk8O1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAts\n" + "F/tnyMKtsc2AtJfcdgEWFelq16TheEfOhtX7MfP6Mb40qij7cEwdScevLJ1tZqa2\n" + "jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wovJ5pGfaENda1UhhXcSTvx\n" + "ls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7Q3hub/FC\n" + "VGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHK\n" + "YS1tB6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoH\n" + "EgKXTiCQ8P8NHuJBO9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThN\n" + "Xo+EHWbNxWCWtFJaBYmOlXqYwZE8lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1Ud\n" + "DgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNVHRMEBTADAQH/MDkGBGcqBwAE\n" + "MTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg209yewDL7MTqK\n" + "UWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ\n" + "TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyf\n" + "qzvS/3WXy6TjZwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaK\n" + "ZEk9GhiHkASfQlK3T8v+R0F2Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFE\n" + "JPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlUD7gsL0u8qV1bYH+Mh6XgUmMqvtg7\n" + "hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6QzDxARvBMB1uUO07+1\n" + "EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+HbkZ6Mm\n" + "nD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WX\n" + "udpVBrkk7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44Vbnz\n" + "ssQwmSNOXfJIoRIM3BKQCZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDe\n" + "LMDDav7v3Aun+kbfYNucpllQdSNpc5Oy+fwC00fmcc4QAu4njIT/rEUNE1yDMuAl\n" + "pYYsfPQS\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# TeliaSonera Root CA v1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw\n" + "NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv\n" + "b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD\n" + "VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2\n" + "MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F\n" + "VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1\n" + "7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X\n" + "Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+\n" + "/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs\n" + "81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm\n" + "dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe\n" + "Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu\n" + "sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4\n" + "pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs\n" + "slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ\n" + "arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD\n" + "VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG\n" + "9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl\n" + "dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx\n" + "0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj\n" + "TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed\n" + "Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7\n" + "Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI\n" + "OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7\n" + "vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW\n" + "t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn\n" + "HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx\n" + "SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# TrustCor ECA-1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD\n" + "VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk\n" + "MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U\n" + "cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y\n" + "IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV\n" + "BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw\n" + "IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy\n" + "dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig\n" + "RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb\n" + "3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA\n" + "BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5\n" + "3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou\n" + "owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/\n" + "wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF\n" + "ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf\n" + "BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/\n" + "MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv\n" + "civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2\n" + "AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F\n" + "hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50\n" + "soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI\n" + "WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi\n" + "tJ/X5g==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# TrustCor RootCert CA-1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD\n" + "VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk\n" + "MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U\n" + "cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y\n" + "IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB\n" + "pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h\n" + "IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG\n" + "A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU\n" + "cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + "CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid\n" + "RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V\n" + "seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme\n" + "9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV\n" + "EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW\n" + "hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/\n" + "DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw\n" + "DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD\n" + "ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I\n" + "/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf\n" + "ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ\n" + "yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts\n" + "L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN\n" + "zl/HHk484IkzlQsPpTLWPFp5LBk=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# TrustCor RootCert CA-2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV\n" + "BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw\n" + "IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy\n" + "dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig\n" + "Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk\n" + "MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg\n" + "Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD\n" + "VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy\n" + "dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" + "AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+\n" + "QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq\n" + "1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp\n" + "2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK\n" + "DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape\n" + "az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF\n" + "3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88\n" + "oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM\n" + "g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3\n" + "mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh\n" + "8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd\n" + "BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U\n" + "nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw\n" + "DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX\n" + "dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+\n" + "MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL\n" + "/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX\n" + "CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa\n" + "ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW\n" + "2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7\n" + "N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3\n" + "Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB\n" + "As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp\n" + "5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu\n" + "1uwJ\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Trustis FPS Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF\n" + "MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL\n" + "ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx\n" + "MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc\n" + "MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD\n" + "ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+\n" + "AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH\n" + "iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj\n" + "vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA\n" + "0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB\n" + "OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/\n" + "BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E\n" + "FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01\n" + "GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW\n" + "zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4\n" + "1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE\n" + "f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F\n" + "jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN\n" + "ZetX2fNXlrtIzYE=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# UCA Extended Validation Root\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH\n" + "MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF\n" + "eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx\n" + "MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV\n" + "BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB\n" + "AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog\n" + "D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS\n" + "sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop\n" + "O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk\n" + "sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi\n" + "c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj\n" + "VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz\n" + "KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/\n" + "TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G\n" + "sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs\n" + "1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD\n" + "fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T\n" + "AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN\n" + "l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR\n" + "ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ\n" + "VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5\n" + "c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp\n" + "4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s\n" + "t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj\n" + "2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO\n" + "vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C\n" + "xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx\n" + "cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM\n" + "fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# UCA Global G2 Root\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9\n" + "MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH\n" + "bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x\n" + "CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds\n" + "b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr\n" + "b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9\n" + "kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm\n" + "VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R\n" + "VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc\n" + "C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj\n" + "tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY\n" + "D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv\n" + "j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl\n" + "NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6\n" + "iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP\n" + "O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/\n" + "BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV\n" + "ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj\n" + "L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5\n" + "1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl\n" + "1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU\n" + "b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV\n" + "PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj\n" + "y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb\n" + "EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg\n" + "DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI\n" + "+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy\n" + "YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX\n" + "UB+K+wb1whnw0A==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# USERTrust ECC Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\n" + "MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n" + "eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n" + "JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\n" + "MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n" + "Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\n" + "VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\n" + "aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\n" + "I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\n" + "o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\n" + "A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\n" + "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\n" + "zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\n" + "RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# USERTrust RSA Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB\n" + "iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl\n" + "cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV\n" + "BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw\n" + "MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV\n" + "BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU\n" + "aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy\n" + "dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK\n" + "AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B\n" + "3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY\n" + "tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/\n" + "Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2\n" + "VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT\n" + "79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6\n" + "c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT\n" + "Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l\n" + "c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee\n" + "UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE\n" + "Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd\n" + "BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G\n" + "A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF\n" + "Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO\n" + "VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3\n" + "ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs\n" + "8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR\n" + "iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze\n" + "Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ\n" + "XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/\n" + "qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB\n" + "VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB\n" + "L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG\n" + "jjxDah2nGN59PRbxYvnKkKj9\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# VeriSign Class 3 Public Primary Certification Authority - G4\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL\n" + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\n" + "ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln\n" + "biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\n" + "U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + "aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG\n" + "A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp\n" + "U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg\n" + "SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln\n" + "biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5\n" + "IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm\n" + "GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve\n" + "fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw\n" + "AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ\n" + "aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj\n" + "aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW\n" + "kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC\n" + "4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga\n" + "FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# VeriSign Class 3 Public Primary Certification Authority - G5\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB\n" + "yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n" + "ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp\n" + "U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW\n" + "ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\n" + "aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL\n" + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW\n" + "ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln\n" + "biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp\n" + "U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y\n" + "aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1\n" + "nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex\n" + "t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz\n" + "SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG\n" + "BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+\n" + "rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/\n" + "NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E\n" + "BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH\n" + "BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy\n" + "aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv\n" + "MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE\n" + "p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y\n" + "5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK\n" + "WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ\n" + "4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N\n" + "hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# VeriSign Universal Root Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB\n" + "vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL\n" + "ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp\n" + "U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W\n" + "ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n" + "Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX\n" + "MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0\n" + "IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y\n" + "IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh\n" + "bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF\n" + "AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF\n" + "9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH\n" + "H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H\n" + "LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN\n" + "/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT\n" + "rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud\n" + "EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw\n" + "WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs\n" + "exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud\n" + "DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4\n" + "sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+\n" + "seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz\n" + "4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+\n" + "BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR\n" + "lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3\n" + "7M2CYfE45k+XmCpajQ==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# Verisign Class 3 Public Primary Certification Authority - G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw\n" + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl\n" + "cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu\n" + "LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT\n" + "aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp\n" + "dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD\n" + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT\n" + "aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ\n" + "bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu\n" + "IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg\n" + "LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b\n" + "N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t\n" + "KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu\n" + "kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm\n" + "CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ\n" + "Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu\n" + "imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te\n" + "2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe\n" + "DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC\n" + "/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p\n" + "F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt\n" + "TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# XRamp Global CA Root\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB\n" + "gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk\n" + "MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY\n" + "UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx\n" + "NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3\n" + "dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy\n" + "dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB\n" + "dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6\n" + "38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP\n" + "KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q\n" + "DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4\n" + "qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa\n" + "JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi\n" + "PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P\n" + "BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs\n" + "jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0\n" + "eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD\n" + "ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR\n" + "vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt\n" + "qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa\n" + "IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy\n" + "i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ\n" + "O+7ETPTsJ3xCwnR8gooJybQDJbw=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# certSIGN ROOT CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT\n" + "AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD\n" + "QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP\n" + "MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC\n" + "ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do\n" + "0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ\n" + "UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d\n" + "RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ\n" + "OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv\n" + "JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C\n" + "AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O\n" + "BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ\n" + "LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY\n" + "MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ\n" + "44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I\n" + "Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw\n" + "i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN\n" + "9u6wWk5JRFRYX0KD\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# ePKI Root Certification Authority\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe\n" + "MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0\n" + "ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe\n" + "Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw\n" + "IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL\n" + "SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF\n" + "AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH\n" + "SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh\n" + "ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X\n" + "DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1\n" + "TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ\n" + "fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA\n" + "sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU\n" + "WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS\n" + "nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH\n" + "dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip\n" + "NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC\n" + "AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF\n" + "MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH\n" + "ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB\n" + "uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl\n" + "PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP\n" + "JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/\n" + "gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2\n" + "j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6\n" + "5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB\n" + "o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS\n" + "/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z\n" + "Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE\n" + "W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D\n" + "hNQ+IIX3Sj0rnP0qCglN6oH4EZw=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# emSign ECC Root CA - C3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG\n" + "EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx\n" + "IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw\n" + "MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln\n" + "biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND\n" + "IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci\n" + "MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti\n" + "sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O\n" + "BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB\n" + "Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c\n" + "3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J\n" + "0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# emSign ECC Root CA - G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG\n" + "EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo\n" + "bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g\n" + "RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ\n" + "TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s\n" + "b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw\n" + "djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0\n" + "WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS\n" + "fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB\n" + "zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq\n" + "hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB\n" + "CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD\n" + "+JbNR6iC8hZVdyR+EhCVBCyj\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# emSign Root CA - C1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG\n" + "A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg\n" + "SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw\n" + "MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln\n" + "biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v\n" + "dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ\n" + "BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ\n" + "HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH\n" + "3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH\n" + "GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c\n" + "xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1\n" + "aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq\n" + "TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n" + "BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87\n" + "/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4\n" + "kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG\n" + "YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT\n" + "+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo\n" + "WXzhriKi4gp6D/piq1JM4fHfyr6DDUI=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# emSign Root CA - G1\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD\n" + "VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU\n" + "ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH\n" + "MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO\n" + "MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv\n" + "Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN\n" + "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz\n" + "f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO\n" + "8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq\n" + "d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM\n" + "tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt\n" + "Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB\n" + "o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD\n" + "AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x\n" + "PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM\n" + "wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d\n" + "GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH\n" + "6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby\n" + "RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx\n" + "iN66zB+Afko=\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# thawte Primary Root CA\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB\n" + "qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf\n" + "Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw\n" + "MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV\n" + "BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw\n" + "NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j\n" + "LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG\n" + "A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl\n" + "IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG\n" + "SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs\n" + "W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta\n" + "3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk\n" + "6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6\n" + "Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J\n" + "NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA\n" + "MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP\n" + "r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU\n" + "DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz\n" + "YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX\n" + "xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2\n" + "/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/\n" + "LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7\n" + "jVaMaA==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# thawte Primary Root CA - G2\n" + "-----BEGIN CERTIFICATE-----\n" + "MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL\n" + "MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp\n" + "IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi\n" + "BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw\n" + "MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh\n" + "d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig\n" + "YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v\n" + "dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/\n" + "BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6\n" + "papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E\n" + "BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K\n" + "DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3\n" + "KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox\n" + "XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==\n" + "-----END CERTIFICATE-----\n" + "\n"; + cert += + "# thawte Primary Root CA - G3\n" + "-----BEGIN CERTIFICATE-----\n" + "MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB\n" + "rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf\n" + "Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw\n" + "MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV\n" + "BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa\n" + "Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl\n" + "LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u\n" + "MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl\n" + "ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz\n" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm\n" + "gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8\n" + "YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf\n" + "b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9\n" + "9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S\n" + "zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk\n" + "OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV\n" + "HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA\n" + "2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW\n" + "oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu\n" + "t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c\n" + "KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM\n" + "m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu\n" + "MdRAGmI0Nj81Aa6sY6A=\n" + "-----END CERTIFICATE-----"; + + ctx.add_certificate_authority( + boost::asio::buffer(cert.data(), cert.size()), ec); + if(ec) + return; +} + +} // detail + +// Load the root certificates into an ssl::context + +inline +void +load_root_certificates(ssl::context& ctx, boost::system::error_code& ec) +{ + detail::load_root_certificates(ctx, ec); +} + +inline +void +load_root_certificates(ssl::context& ctx) +{ + boost::system::error_code ec; + detail::load_root_certificates(ctx, ec); + if(ec) + throw boost::system::system_error{ec}; +} + +#endif diff --git a/src/cpp/3rdparty/beast/server_certificate.hpp b/src/cpp/3rdparty/beast/server_certificate.hpp new file mode 100644 index 000000000..bf4766158 --- /dev/null +++ b/src/cpp/3rdparty/beast/server_certificate.hpp @@ -0,0 +1,125 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_EXAMPLE_COMMON_SERVER_CERTIFICATE_HPP +#define BOOST_BEAST_EXAMPLE_COMMON_SERVER_CERTIFICATE_HPP + +#include +#include +#include +#include + +/* Load a signed certificate into the ssl context, and configure + the context for use with a server. + + For this to work with the browser or operating system, it is + necessary to import the "Beast Test CA" certificate into + the local certificate store, browser, or operating system + depending on your environment Please see the documentation + accompanying the Beast certificate for more details. +*/ +inline +void +load_server_certificate(boost::asio::ssl::context& ctx) +{ + /* + The certificate was generated from bash on Ubuntu (OpenSSL 1.1.1f) using: + + openssl dhparam -out dh.pem 2048 + openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 10000 -out cert.pem -subj "/C=US/ST=CA/L=Los Angeles/O=Beast/CN=www.example.com" + */ + + std::string const cert = + "-----BEGIN CERTIFICATE-----\n" + "MIIDlTCCAn2gAwIBAgIUOLxr3q7Wd/pto1+2MsW4fdRheCIwDQYJKoZIhvcNAQEL\n" + "BQAwWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRQwEgYDVQQHDAtMb3MgQW5n\n" + "ZWxlczEOMAwGA1UECgwFQmVhc3QxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAe\n" + "Fw0yMTA3MDYwMTQ5MjVaFw00ODExMjEwMTQ5MjVaMFoxCzAJBgNVBAYTAlVTMQsw\n" + "CQYDVQQIDAJDQTEUMBIGA1UEBwwLTG9zIEFuZ2VsZXMxDjAMBgNVBAoMBUJlYXN0\n" + "MRgwFgYDVQQDDA93d3cuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQCz0GwgnxSBhygxBdhTHGx5LDLIJSuIDJ6nMwZFvAjdhLnB/vOT\n" + "Lppr5MKxqQHEpYdyDYGD1noBoz4TiIRj5JapChMgx58NLq5QyXkHV/ONT7yi8x05\n" + "P41c2F9pBEnUwUxIUG1Cb6AN0cZWF/wSMOZ0w3DoBhnl1sdQfQiS25MTK6x4tATm\n" + "Wm9SJc2lsjWptbyIN6hFXLYPXTwnYzCLvv1EK6Ft7tMPc/FcJpd/wYHgl8shDmY7\n" + "rV+AiGTxUU35V0AzpJlmvct5aJV/5vSRRLwT9qLZSddE9zy/0rovC5GML6S7BUC4\n" + "lIzJ8yxzOzSStBPxvdrOobSSNlRZIlE7gnyNAgMBAAGjUzBRMB0GA1UdDgQWBBR+\n" + "dYtY9zmFSw9GYpEXC1iJKHC0/jAfBgNVHSMEGDAWgBR+dYtY9zmFSw9GYpEXC1iJ\n" + "KHC0/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBzKrsiYywl\n" + "RKeB2LbddgSf7ahiQMXCZpAjZeJikIoEmx+AmjQk1bam+M7WfpRAMnCKooU+Utp5\n" + "TwtijjnJydkZHFR6UH6oCWm8RsUVxruao/B0UFRlD8q+ZxGd4fGTdLg/ztmA+9oC\n" + "EmrcQNdz/KIxJj/fRB3j9GM4lkdaIju47V998Z619E/6pt7GWcAySm1faPB0X4fL\n" + "FJ6iYR2r/kJLoppPqL0EE49uwyYQ1dKhXS2hk+IIfA9mBn8eAFb/0435A2fXutds\n" + "qhvwIOmAObCzcoKkz3sChbk4ToUTqbC0TmFAXI5Upz1wnADzjpbJrpegCA3pmvhT\n" + "7356drqnCGY9\n" + "-----END CERTIFICATE-----\n"; + + std::string const key = + "-----BEGIN PRIVATE KEY-----\n" + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCz0GwgnxSBhygx\n" + "BdhTHGx5LDLIJSuIDJ6nMwZFvAjdhLnB/vOTLppr5MKxqQHEpYdyDYGD1noBoz4T\n" + "iIRj5JapChMgx58NLq5QyXkHV/ONT7yi8x05P41c2F9pBEnUwUxIUG1Cb6AN0cZW\n" + "F/wSMOZ0w3DoBhnl1sdQfQiS25MTK6x4tATmWm9SJc2lsjWptbyIN6hFXLYPXTwn\n" + "YzCLvv1EK6Ft7tMPc/FcJpd/wYHgl8shDmY7rV+AiGTxUU35V0AzpJlmvct5aJV/\n" + "5vSRRLwT9qLZSddE9zy/0rovC5GML6S7BUC4lIzJ8yxzOzSStBPxvdrOobSSNlRZ\n" + "IlE7gnyNAgMBAAECggEAY0RorQmldGx9D7M+XYOPjsWLs1px0cXFwGA20kCgVEp1\n" + "kleBeHt93JqJsTKwOzN2tswl9/ZrnIPWPUpcbBlB40ggjzQk5k4jBY50Nk2jsxuV\n" + "9A9qzrP7AoqhAYTQjZe42SMtbkPZhEeOyvCqxBAi6csLhcv4eB4+In0kQo7dfvLs\n" + "Xu/3WhSsuAWqdD9EGnhD3n+hVTtgiasRe9318/3R9DzP+IokoQGOtXm+1dsfP0mV\n" + "8XGzQHBpUtJNn0yi6SC4kGEQuKkX33zORlSnZgT5VBLofNgra0THd7x3atOx1lbr\n" + "V0QizvCdBa6j6FwhOQwW8UwgOCnUbWXl/Xn4OaofMQKBgQDdRXSMyys7qUMe4SYM\n" + "Mdawj+rjv0Hg98/xORuXKEISh2snJGKEwV7L0vCn468n+sM19z62Axz+lvOUH8Qr\n" + "hLkBNqJvtIP+b0ljRjem78K4a4qIqUlpejpRLw6a/+44L76pMJXrYg3zdBfwzfwu\n" + "b9NXdwHzWoNuj4v36teGP6xOUwKBgQDQCT52XX96NseNC6HeK5BgWYYjjxmhksHi\n" + "stjzPJKySWXZqJpHfXI8qpOd0Sd1FHB+q1s3hand9c+Rxs762OXlqA9Q4i+4qEYZ\n" + "qhyRkTsl+2BhgzxmoqGd5gsVT7KV8XqtuHWLmetNEi+7+mGSFf2iNFnonKlvT1JX\n" + "4OQZC7ntnwKBgH/ORFmmaFxXkfteFLnqd5UYK5ZMvGKTALrWP4d5q2BEc7HyJC2F\n" + "+5lDR9nRezRedS7QlppPBgpPanXeO1LfoHSA+CYJYEwwP3Vl83Mq/Y/EHgp9rXeN\n" + "L+4AfjEtLo2pljjnZVDGHETIg6OFdunjkXDtvmSvnUbZBwG11bMnSAEdAoGBAKFw\n" + "qwJb6FNFM3JnNoQctnuuvYPWxwM1yjRMqkOIHCczAlD4oFEeLoqZrNhpuP8Ij4wd\n" + "GjpqBbpzyVLNP043B6FC3C/edz4Lh+resjDczVPaUZ8aosLbLiREoxE0udfWf2dU\n" + "oBNnrMwwcs6jrRga7Kr1iVgUSwBQRAxiP2CYUv7tAoGBAKdPdekPNP/rCnHkKIkj\n" + "o13pr+LJ8t+15vVzZNHwPHUWiYXFhG8Ivx7rqLQSPGcuPhNss3bg1RJiZAUvF6fd\n" + "e6QS4EZM9dhhlO2FmPQCJMrRVDXaV+9TcJZXCbclQnzzBus9pwZZyw4Anxo0vmir\n" + "nOMOU6XI4lO9Xge/QDEN4Y2R\n" + "-----END PRIVATE KEY-----\n"; + + std::string const dh = + "-----BEGIN DH PARAMETERS-----\n" + "MIIBCAKCAQEArzQc5mpm0Fs8yahDeySj31JZlwEphUdZ9StM2D8+Fo7TMduGtSi+\n" + "/HRWVwHcTFAgrxVdm+dl474mOUqqaz4MpzIb6+6OVfWHbQJmXPepZKyu4LgUPvY/\n" + "4q3/iDMjIS0fLOu/bLuObwU5ccZmDgfhmz1GanRlTQOiYRty3FiOATWZBRh6uv4u\n" + "tff4A9Bm3V9tLx9S6djq31w31Gl7OQhryodW28kc16t9TvO1BzcV3HjRPwpe701X\n" + "oEEZdnZWANkkpR/m/pfgdmGPU66S2sXMHgsliViQWpDCYeehrvFRHEdR9NV+XJfC\n" + "QMUk26jPTIVTLfXmmwU0u8vUkpR7LQKkwwIBAg==\n" + "-----END DH PARAMETERS-----\n"; + + ctx.set_password_callback( + [](std::size_t, + boost::asio::ssl::context_base::password_purpose) + { + return "test"; + }); + + ctx.set_options( + boost::asio::ssl::context::default_workarounds | + boost::asio::ssl::context::no_sslv2 | + boost::asio::ssl::context::single_dh_use); + + ctx.use_certificate_chain( + boost::asio::buffer(cert.data(), cert.size())); + + ctx.use_private_key( + boost::asio::buffer(key.data(), key.size()), + boost::asio::ssl::context::file_format::pem); + + ctx.use_tmp_dh( + boost::asio::buffer(dh.data(), dh.size())); +} + +#endif diff --git a/src/cpp/3rdparty/enum_macros.h b/src/cpp/3rdparty/enum_macros.h new file mode 100644 index 000000000..5d14a1165 --- /dev/null +++ b/src/cpp/3rdparty/enum_macros.h @@ -0,0 +1,581 @@ +// This file was automatically generated by make_macros.py + +#pragma once + +#ifndef BETTER_ENUMS_MACRO_FILE_H +#define BETTER_ENUMS_MACRO_FILE_H + +#define BETTER_ENUMS_PP_MAP(macro, data, ...) \ + BETTER_ENUMS_ID( \ + BETTER_ENUMS_APPLY( \ + BETTER_ENUMS_PP_MAP_VAR_COUNT, \ + BETTER_ENUMS_PP_COUNT(__VA_ARGS__)) \ + (macro, data, __VA_ARGS__)) + +#define BETTER_ENUMS_PP_MAP_VAR_COUNT(count) BETTER_ENUMS_M ## count + +#define BETTER_ENUMS_APPLY(macro, ...) BETTER_ENUMS_ID(macro(__VA_ARGS__)) + +#define BETTER_ENUMS_ID(x) x + +#define BETTER_ENUMS_M1(m, d, x) m(d,0,x) +#define BETTER_ENUMS_M2(m,d,x,...) m(d,1,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M1(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M3(m,d,x,...) m(d,2,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M2(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M4(m,d,x,...) m(d,3,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M3(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M5(m,d,x,...) m(d,4,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M4(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M6(m,d,x,...) m(d,5,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M5(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M7(m,d,x,...) m(d,6,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M6(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M8(m,d,x,...) m(d,7,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M7(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M9(m,d,x,...) m(d,8,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M8(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M10(m,d,x,...) m(d,9,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M9(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M11(m,d,x,...) m(d,10,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M10(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M12(m,d,x,...) m(d,11,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M11(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M13(m,d,x,...) m(d,12,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M12(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M14(m,d,x,...) m(d,13,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M13(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M15(m,d,x,...) m(d,14,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M14(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M16(m,d,x,...) m(d,15,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M15(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M17(m,d,x,...) m(d,16,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M16(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M18(m,d,x,...) m(d,17,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M17(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M19(m,d,x,...) m(d,18,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M18(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M20(m,d,x,...) m(d,19,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M19(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M21(m,d,x,...) m(d,20,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M20(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M22(m,d,x,...) m(d,21,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M21(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M23(m,d,x,...) m(d,22,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M22(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M24(m,d,x,...) m(d,23,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M23(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M25(m,d,x,...) m(d,24,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M24(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M26(m,d,x,...) m(d,25,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M25(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M27(m,d,x,...) m(d,26,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M26(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M28(m,d,x,...) m(d,27,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M27(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M29(m,d,x,...) m(d,28,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M28(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M30(m,d,x,...) m(d,29,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M29(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M31(m,d,x,...) m(d,30,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M30(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M32(m,d,x,...) m(d,31,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M31(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M33(m,d,x,...) m(d,32,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M32(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M34(m,d,x,...) m(d,33,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M33(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M35(m,d,x,...) m(d,34,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M34(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M36(m,d,x,...) m(d,35,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M35(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M37(m,d,x,...) m(d,36,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M36(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M38(m,d,x,...) m(d,37,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M37(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M39(m,d,x,...) m(d,38,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M38(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M40(m,d,x,...) m(d,39,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M39(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M41(m,d,x,...) m(d,40,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M40(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M42(m,d,x,...) m(d,41,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M41(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M43(m,d,x,...) m(d,42,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M42(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M44(m,d,x,...) m(d,43,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M43(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M45(m,d,x,...) m(d,44,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M44(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M46(m,d,x,...) m(d,45,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M45(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M47(m,d,x,...) m(d,46,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M46(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M48(m,d,x,...) m(d,47,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M47(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M49(m,d,x,...) m(d,48,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M48(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M50(m,d,x,...) m(d,49,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M49(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M51(m,d,x,...) m(d,50,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M50(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M52(m,d,x,...) m(d,51,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M51(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M53(m,d,x,...) m(d,52,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M52(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M54(m,d,x,...) m(d,53,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M53(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M55(m,d,x,...) m(d,54,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M54(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M56(m,d,x,...) m(d,55,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M55(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M57(m,d,x,...) m(d,56,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M56(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M58(m,d,x,...) m(d,57,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M57(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M59(m,d,x,...) m(d,58,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M58(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M60(m,d,x,...) m(d,59,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M59(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M61(m,d,x,...) m(d,60,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M60(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M62(m,d,x,...) m(d,61,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M61(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M63(m,d,x,...) m(d,62,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M62(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M64(m,d,x,...) m(d,63,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M63(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M65(m,d,x,...) m(d,64,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M64(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M66(m,d,x,...) m(d,65,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M65(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M67(m,d,x,...) m(d,66,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M66(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M68(m,d,x,...) m(d,67,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M67(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M69(m,d,x,...) m(d,68,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M68(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M70(m,d,x,...) m(d,69,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M69(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M71(m,d,x,...) m(d,70,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M70(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M72(m,d,x,...) m(d,71,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M71(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M73(m,d,x,...) m(d,72,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M72(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M74(m,d,x,...) m(d,73,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M73(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M75(m,d,x,...) m(d,74,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M74(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M76(m,d,x,...) m(d,75,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M75(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M77(m,d,x,...) m(d,76,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M76(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M78(m,d,x,...) m(d,77,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M77(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M79(m,d,x,...) m(d,78,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M78(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M80(m,d,x,...) m(d,79,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M79(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M81(m,d,x,...) m(d,80,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M80(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M82(m,d,x,...) m(d,81,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M81(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M83(m,d,x,...) m(d,82,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M82(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M84(m,d,x,...) m(d,83,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M83(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M85(m,d,x,...) m(d,84,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M84(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M86(m,d,x,...) m(d,85,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M85(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M87(m,d,x,...) m(d,86,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M86(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M88(m,d,x,...) m(d,87,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M87(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M89(m,d,x,...) m(d,88,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M88(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M90(m,d,x,...) m(d,89,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M89(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M91(m,d,x,...) m(d,90,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M90(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M92(m,d,x,...) m(d,91,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M91(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M93(m,d,x,...) m(d,92,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M92(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M94(m,d,x,...) m(d,93,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M93(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M95(m,d,x,...) m(d,94,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M94(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M96(m,d,x,...) m(d,95,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M95(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M97(m,d,x,...) m(d,96,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M96(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M98(m,d,x,...) m(d,97,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M97(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M99(m,d,x,...) m(d,98,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M98(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M100(m,d,x,...) m(d,99,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M99(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M101(m,d,x,...) m(d,100,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M100(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M102(m,d,x,...) m(d,101,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M101(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M103(m,d,x,...) m(d,102,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M102(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M104(m,d,x,...) m(d,103,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M103(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M105(m,d,x,...) m(d,104,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M104(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M106(m,d,x,...) m(d,105,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M105(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M107(m,d,x,...) m(d,106,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M106(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M108(m,d,x,...) m(d,107,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M107(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M109(m,d,x,...) m(d,108,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M108(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M110(m,d,x,...) m(d,109,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M109(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M111(m,d,x,...) m(d,110,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M110(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M112(m,d,x,...) m(d,111,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M111(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M113(m,d,x,...) m(d,112,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M112(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M114(m,d,x,...) m(d,113,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M113(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M115(m,d,x,...) m(d,114,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M114(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M116(m,d,x,...) m(d,115,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M115(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M117(m,d,x,...) m(d,116,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M116(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M118(m,d,x,...) m(d,117,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M117(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M119(m,d,x,...) m(d,118,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M118(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M120(m,d,x,...) m(d,119,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M119(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M121(m,d,x,...) m(d,120,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M120(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M122(m,d,x,...) m(d,121,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M121(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M123(m,d,x,...) m(d,122,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M122(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M124(m,d,x,...) m(d,123,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M123(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M125(m,d,x,...) m(d,124,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M124(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M126(m,d,x,...) m(d,125,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M125(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M127(m,d,x,...) m(d,126,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M126(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M128(m,d,x,...) m(d,127,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M127(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M129(m,d,x,...) m(d,128,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M128(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M130(m,d,x,...) m(d,129,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M129(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M131(m,d,x,...) m(d,130,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M130(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M132(m,d,x,...) m(d,131,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M131(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M133(m,d,x,...) m(d,132,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M132(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M134(m,d,x,...) m(d,133,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M133(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M135(m,d,x,...) m(d,134,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M134(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M136(m,d,x,...) m(d,135,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M135(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M137(m,d,x,...) m(d,136,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M136(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M138(m,d,x,...) m(d,137,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M137(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M139(m,d,x,...) m(d,138,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M138(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M140(m,d,x,...) m(d,139,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M139(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M141(m,d,x,...) m(d,140,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M140(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M142(m,d,x,...) m(d,141,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M141(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M143(m,d,x,...) m(d,142,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M142(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M144(m,d,x,...) m(d,143,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M143(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M145(m,d,x,...) m(d,144,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M144(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M146(m,d,x,...) m(d,145,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M145(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M147(m,d,x,...) m(d,146,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M146(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M148(m,d,x,...) m(d,147,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M147(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M149(m,d,x,...) m(d,148,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M148(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M150(m,d,x,...) m(d,149,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M149(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M151(m,d,x,...) m(d,150,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M150(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M152(m,d,x,...) m(d,151,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M151(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M153(m,d,x,...) m(d,152,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M152(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M154(m,d,x,...) m(d,153,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M153(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M155(m,d,x,...) m(d,154,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M154(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M156(m,d,x,...) m(d,155,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M155(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M157(m,d,x,...) m(d,156,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M156(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M158(m,d,x,...) m(d,157,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M157(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M159(m,d,x,...) m(d,158,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M158(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M160(m,d,x,...) m(d,159,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M159(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M161(m,d,x,...) m(d,160,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M160(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M162(m,d,x,...) m(d,161,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M161(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M163(m,d,x,...) m(d,162,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M162(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M164(m,d,x,...) m(d,163,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M163(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M165(m,d,x,...) m(d,164,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M164(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M166(m,d,x,...) m(d,165,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M165(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M167(m,d,x,...) m(d,166,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M166(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M168(m,d,x,...) m(d,167,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M167(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M169(m,d,x,...) m(d,168,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M168(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M170(m,d,x,...) m(d,169,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M169(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M171(m,d,x,...) m(d,170,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M170(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M172(m,d,x,...) m(d,171,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M171(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M173(m,d,x,...) m(d,172,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M172(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M174(m,d,x,...) m(d,173,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M173(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M175(m,d,x,...) m(d,174,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M174(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M176(m,d,x,...) m(d,175,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M175(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M177(m,d,x,...) m(d,176,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M176(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M178(m,d,x,...) m(d,177,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M177(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M179(m,d,x,...) m(d,178,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M178(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M180(m,d,x,...) m(d,179,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M179(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M181(m,d,x,...) m(d,180,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M180(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M182(m,d,x,...) m(d,181,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M181(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M183(m,d,x,...) m(d,182,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M182(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M184(m,d,x,...) m(d,183,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M183(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M185(m,d,x,...) m(d,184,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M184(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M186(m,d,x,...) m(d,185,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M185(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M187(m,d,x,...) m(d,186,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M186(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M188(m,d,x,...) m(d,187,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M187(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M189(m,d,x,...) m(d,188,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M188(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M190(m,d,x,...) m(d,189,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M189(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M191(m,d,x,...) m(d,190,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M190(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M192(m,d,x,...) m(d,191,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M191(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M193(m,d,x,...) m(d,192,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M192(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M194(m,d,x,...) m(d,193,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M193(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M195(m,d,x,...) m(d,194,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M194(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M196(m,d,x,...) m(d,195,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M195(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M197(m,d,x,...) m(d,196,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M196(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M198(m,d,x,...) m(d,197,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M197(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M199(m,d,x,...) m(d,198,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M198(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M200(m,d,x,...) m(d,199,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M199(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M201(m,d,x,...) m(d,200,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M200(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M202(m,d,x,...) m(d,201,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M201(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M203(m,d,x,...) m(d,202,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M202(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M204(m,d,x,...) m(d,203,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M203(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M205(m,d,x,...) m(d,204,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M204(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M206(m,d,x,...) m(d,205,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M205(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M207(m,d,x,...) m(d,206,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M206(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M208(m,d,x,...) m(d,207,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M207(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M209(m,d,x,...) m(d,208,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M208(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M210(m,d,x,...) m(d,209,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M209(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M211(m,d,x,...) m(d,210,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M210(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M212(m,d,x,...) m(d,211,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M211(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M213(m,d,x,...) m(d,212,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M212(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M214(m,d,x,...) m(d,213,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M213(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M215(m,d,x,...) m(d,214,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M214(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M216(m,d,x,...) m(d,215,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M215(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M217(m,d,x,...) m(d,216,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M216(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M218(m,d,x,...) m(d,217,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M217(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M219(m,d,x,...) m(d,218,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M218(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M220(m,d,x,...) m(d,219,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M219(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M221(m,d,x,...) m(d,220,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M220(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M222(m,d,x,...) m(d,221,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M221(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M223(m,d,x,...) m(d,222,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M222(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M224(m,d,x,...) m(d,223,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M223(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M225(m,d,x,...) m(d,224,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M224(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M226(m,d,x,...) m(d,225,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M225(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M227(m,d,x,...) m(d,226,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M226(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M228(m,d,x,...) m(d,227,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M227(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M229(m,d,x,...) m(d,228,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M228(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M230(m,d,x,...) m(d,229,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M229(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M231(m,d,x,...) m(d,230,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M230(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M232(m,d,x,...) m(d,231,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M231(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M233(m,d,x,...) m(d,232,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M232(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M234(m,d,x,...) m(d,233,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M233(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M235(m,d,x,...) m(d,234,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M234(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M236(m,d,x,...) m(d,235,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M235(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M237(m,d,x,...) m(d,236,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M236(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M238(m,d,x,...) m(d,237,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M237(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M239(m,d,x,...) m(d,238,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M238(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M240(m,d,x,...) m(d,239,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M239(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M241(m,d,x,...) m(d,240,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M240(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M242(m,d,x,...) m(d,241,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M241(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M243(m,d,x,...) m(d,242,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M242(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M244(m,d,x,...) m(d,243,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M243(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M245(m,d,x,...) m(d,244,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M244(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M246(m,d,x,...) m(d,245,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M245(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M247(m,d,x,...) m(d,246,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M246(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M248(m,d,x,...) m(d,247,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M247(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M249(m,d,x,...) m(d,248,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M248(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M250(m,d,x,...) m(d,249,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M249(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M251(m,d,x,...) m(d,250,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M250(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M252(m,d,x,...) m(d,251,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M251(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M253(m,d,x,...) m(d,252,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M252(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M254(m,d,x,...) m(d,253,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M253(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M255(m,d,x,...) m(d,254,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M254(m,d,__VA_ARGS__)) +#define BETTER_ENUMS_M256(m,d,x,...) m(d,255,x) \ + BETTER_ENUMS_ID(BETTER_ENUMS_M255(m,d,__VA_ARGS__)) + +#define BETTER_ENUMS_PP_COUNT_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ + _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, \ + _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, \ + _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, \ + _71, _72, _73, _74, _75, _76, _77, _78, _79, _80, _81, _82, _83, _84, _85, \ + _86, _87, _88, _89, _90, _91, _92, _93, _94, _95, _96, _97, _98, _99, _100,\ + _101, _102, _103, _104, _105, _106, _107, _108, _109, _110, _111, _112, \ + _113, _114, _115, _116, _117, _118, _119, _120, _121, _122, _123, _124, \ + _125, _126, _127, _128, _129, _130, _131, _132, _133, _134, _135, _136, \ + _137, _138, _139, _140, _141, _142, _143, _144, _145, _146, _147, _148, \ + _149, _150, _151, _152, _153, _154, _155, _156, _157, _158, _159, _160, \ + _161, _162, _163, _164, _165, _166, _167, _168, _169, _170, _171, _172, \ + _173, _174, _175, _176, _177, _178, _179, _180, _181, _182, _183, _184, \ + _185, _186, _187, _188, _189, _190, _191, _192, _193, _194, _195, _196, \ + _197, _198, _199, _200, _201, _202, _203, _204, _205, _206, _207, _208, \ + _209, _210, _211, _212, _213, _214, _215, _216, _217, _218, _219, _220, \ + _221, _222, _223, _224, _225, _226, _227, _228, _229, _230, _231, _232, \ + _233, _234, _235, _236, _237, _238, _239, _240, _241, _242, _243, _244, \ + _245, _246, _247, _248, _249, _250, _251, _252, _253, _254, _255, _256, \ + count, ...) count + +#define BETTER_ENUMS_PP_COUNT(...) \ + BETTER_ENUMS_ID(BETTER_ENUMS_PP_COUNT_IMPL(__VA_ARGS__, 256, 255, 254, 253,\ + 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, \ + 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, \ + 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, \ + 210, 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, \ + 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, \ + 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, \ + 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, \ + 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, \ + 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 130, 129, 128, 127, \ + 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, \ + 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 99, \ + 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81,\ + 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63,\ + 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45,\ + 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27,\ + 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, \ + 8, 7, 6, 5, 4, 3, 2, 1)) + +#define BETTER_ENUMS_ITERATE(X, f, l) X(f, l, 0) X(f, l, 1) X(f, l, 2) \ + X(f, l, 3) X(f, l, 4) X(f, l, 5) X(f, l, 6) X(f, l, 7) X(f, l, 8) \ + X(f, l, 9) X(f, l, 10) X(f, l, 11) X(f, l, 12) X(f, l, 13) X(f, l, 14) \ + X(f, l, 15) X(f, l, 16) X(f, l, 17) X(f, l, 18) X(f, l, 19) X(f, l, 20) \ + X(f, l, 21) X(f, l, 22) X(f, l, 23) + +#endif // #ifndef BETTER_ENUMS_MACRO_FILE_H diff --git a/src/cpp/3rdparty/mqtt_cpp/CMakeLists.txt b/src/cpp/3rdparty/mqtt_cpp/CMakeLists.txt new file mode 100644 index 000000000..2024defef --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/CMakeLists.txt @@ -0,0 +1,73 @@ +FILE(GLOB HDR_ROOT "*.hpp") +FILE(GLOB HDR_MQTT "mqtt/*.hpp") + +SET(ROOT_INCLUDE_TARGET include) +SET(ROOT_MQTT_TARGET include/mqtt) + +ADD_LIBRARY(${PROJECT_NAME} INTERFACE) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} INTERFACE Threads::Threads Boost::system Boost::date_time) + +IF(MQTT_USE_STATIC_OPENSSL) + # Unfortunately, cmake doesn't automatically detect that statically linked openssl + # requires at least two more libs to be linked. "dl" is for dynamic library linking + # and zlib is for basic compression functionality. + # There is currently no way to specify statically linked zlib. + TARGET_LINK_LIBRARIES(${PROJECT_NAME} INTERFACE $<$:${CMAKE_DL_LIBS} ZLIB::ZLIB>) +ENDIF() + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} INTERFACE $<$:OpenSSL::SSL>) + +TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} + INTERFACE + $ + $ + $ +) + +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_USE_TLS>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_USE_WS>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_USE_STR_CHECK>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_USE_LOG>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE MQTT_ALWAYS_SEND_REASON_CODE=$) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_STD_VARIANT>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_STD_OPTIONAL>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_STD_ANY>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_STD_STRING_VIEW>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_STD_SHARED_PTR_ARRAY>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_DISABLE_LIBSTDCXX_TUPLE_ANY_WORKAROUND>) +TARGET_COMPILE_DEFINITIONS(${PROJECT_NAME} INTERFACE $<$:MQTT_NO_TS_EXECUTORS>) + +# You might wonder why we don't simply add the list of header files to the check_deps +# executable directly, and let cmake figure everything out on it's own. +# The reason we can't do that is because cmake has built in rules that can't be disabled +# or overridden that prevent it from ever treating a file that ends in .h as a source file. +# So the work around for this problem is that we copy the header files to a different folder, +# one that's owned by CMake (the binary dir), and compile the header files there to perform +# the dependency checking. +SET (HDR_DEPS_CHK_FOLDER "${CMAKE_BINARY_DIR}/check_deps_headers") +FILE (MAKE_DIRECTORY "${HDR_DEPS_CHK_FOLDER}") +LIST (APPEND CHK_MQTT) +FILE (GLOB_RECURSE ALL_HPP "mqtt/*.hpp") +FOREACH (HDR ${ALL_HPP}) + GET_FILENAME_COMPONENT (HDR_NAME ${HDR} NAME) + # Of course, the FILE macro always treats the destination name as if it were a folder name + # So we have to first copy the header file, and THEN rename the header file to have an + # extension that cmake will treat as a source file. + FILE (COPY ${HDR} DESTINATION "${HDR_DEPS_CHK_FOLDER}") + FILE (RENAME "${HDR_DEPS_CHK_FOLDER}/${HDR_NAME}" "${HDR_DEPS_CHK_FOLDER}/${HDR_NAME}.cpp") + LIST (APPEND CHK_MQTT "${HDR_DEPS_CHK_FOLDER}/${HDR_NAME}.cpp") +ENDFOREACH () + +# The EXCLUDE_FROM_ALL property prevents check_deps from being included in the default target +ADD_LIBRARY(check_deps OBJECT EXCLUDE_FROM_ALL ${CHK_MQTT}) + +# We don't need to actually run the whole compiler. We're just checking that all the includes are valid +# So here we ask for only the syntax checking mode to be used. +# We also don't mind that there might be unused constant variables when doing deps checking. +TARGET_COMPILE_OPTIONS(check_deps PUBLIC -Wno-unused-const-variable $,/Zs,-fsyntax-only>) + +TARGET_LINK_LIBRARIES (check_deps PUBLIC ${PROJECT_NAME}) + +INSTALL(FILES ${HDR_ROOT} DESTINATION ${ROOT_INCLUDE_TARGET}) +INSTALL(FILES ${HDR_MQTT} DESTINATION ${ROOT_MQTT_TARGET}) diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/any.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/any.hpp new file mode 100644 index 000000000..91b2e2551 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/any.hpp @@ -0,0 +1,36 @@ +// Copyright Takatoshi Kondo 2016 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_ANY_HPP) +#define MQTT_ANY_HPP + +#include + +#ifdef MQTT_STD_ANY + +#include + +namespace MQTT_NS { + +using std::any; +using std::any_cast; + +} // namespace MQTT_NS + +#else // MQTT_STD_ANY + +#include + +namespace MQTT_NS { + +using boost::any; +using boost::any_cast; + +} // namespace MQTT_NS + +#endif // !defined(MQTT_STD_ANY) + +#endif // MQTT_ANY_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/async_client.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/async_client.hpp new file mode 100644 index 000000000..c750c49db --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/async_client.hpp @@ -0,0 +1,1238 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_ASYNC_CLIENT_HPP) +#define MQTT_ASYNC_CLIENT_HPP + +#include +#include +#include +#include + +namespace MQTT_NS { + +template +class async_client : public client { + using this_type = async_client; + using base = client; + using constructor_access = typename base::constructor_access; +public: + + /** + * Constructor used by factory functions at the end of this file. + */ + template + explicit async_client(constructor_access, Args && ... args) + : async_client(std::forward(args)...) + { } + + /** + * @brief Create no tls async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > + make_async_client(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create no tls async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > + make_async_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object. + * strand is controlled by ws_endpoint, not endpoint, so async_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > + make_async_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > + make_async_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + /** + * @brief Create tls async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > + make_tls_async_client(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create tls async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > + make_tls_async_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object. + * strand is controlled by ws_endpoint, not endpoint, so async_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + strand + > + > + > + > + make_tls_async_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > + make_tls_async_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) +#endif // defined(MQTT_USE_TLS) + + /** + * @brief Create no tls async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > + make_async_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create no tls async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > + make_async_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object. + * strand is controlled by ws_endpoint, not endpoint, so async_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > + make_async_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > + make_async_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + /** + * @brief Create tls async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > + make_tls_async_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create tls async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > + make_tls_async_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket async_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object. + * strand is controlled by ws_endpoint, not endpoint, so async_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > + make_tls_async_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket async_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return async_client object + */ + friend std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > + make_tls_async_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) +#endif // defined(MQTT_USE_TLS) + + + /** + * @brief Set auto publish response mode. + * @param b set value + * @param async auto publish response send asynchronous + * + * When set auto publish response mode to true, puback, pubrec, pubrel,and pub comp automatically send.
+ */ + void set_auto_pub_response(bool b = true) { + base::set_auto_pub_response(b); + } + + void connect() = delete; + void disconnect() = delete; + void force_disconnect() = delete; + + void publish() = delete; + void subscribe() = delete; + void unsubscribe() = delete; + void pingresp() = delete; + void connack() = delete; + void puback() = delete; + void pubrec() = delete; + void pubrel() = delete; + void pubcomp() = delete; + void suback() = delete; + void unsuback() = delete; + +protected: + // Ensure that only code that knows the *exact* type of an object + // inheriting from this abstract base class can destruct it. + // This avoids issues of the destructor not triggering destruction + // of derived classes, and any member variables contained in them. + // Note: Not virtual to avoid need for a vtable when possible. + ~async_client() = default; + + async_client( + as::io_context& ioc, + std::string host, + std::string port, +#if defined(MQTT_USE_WS) + std::string path = "/", +#endif // defined(MQTT_USE_WS) + protocol_version version = protocol_version::v3_1_1 + ):base(ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + force_move(path), +#endif // defined(MQTT_USE_WS) + version, + true + ) { + set_auto_pub_response(); + } +}; + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_async_client(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_async_client(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_async_client( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_async_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_async_client_no_strand(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_async_client_no_strand( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_async_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_async_client_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_async_client_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_async_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_async_client_no_strand_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_async_client_no_strand_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_async_client(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + tls::stream, + strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_async_client(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_async_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + tls::stream, + null_strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_async_client_no_strand(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client_no_strand( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_async_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + tls::stream, + strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_async_client_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_async_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + tls::stream, + null_strand + > + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_async_client_no_strand_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client_no_strand_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + +// 32bit Packet Id (experimental) + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_async_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_async_client_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_async_client_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_async_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_async_client_no_strand_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_async_client_no_strand_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_async_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_async_client_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_async_client_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_async_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_async_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_async_client_no_strand_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_async_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_async_client_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_async_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_async_client_no_strand_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client_no_strand_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_async_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_async_client_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_async_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using async_client_t = async_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + >; + return std::make_shared>( + async_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + async_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_async_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_async_client_no_strand_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + +} // namespace MQTT_NS + +#endif // MQTT_ASYNC_CLIENT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/attributes.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/attributes.hpp new file mode 100644 index 000000000..95ac13e3a --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/attributes.hpp @@ -0,0 +1,22 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_ATTRIBUTES_HPP) +#define MQTT_ATTRIBUTES_HPP + +#include + +#ifdef _MSC_VER + +#define MQTT_ALWAYS_INLINE + +#else // GCC or Clang + +#define MQTT_ALWAYS_INLINE [[gnu::always_inline]] + +#endif // _MSC_VER + +#endif // MQTT_ATTRIBUTES_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/broker.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/broker.hpp new file mode 100644 index 000000000..1299105f5 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/broker.hpp @@ -0,0 +1,2194 @@ +// Copyright Takatoshi Kondo 2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_BROKER_HPP) +#define MQTT_BROKER_BROKER_HPP + +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +MQTT_BROKER_NS_BEGIN + +namespace mi = boost::multi_index; +namespace as = boost::asio; + +class broker_t { +public: + broker_t(as::io_context& timer_ioc) + :timer_ioc_(timer_ioc), + tim_disconnect_(timer_ioc_) { + security.default_config(); + } + + // [begin] for test setting + /** + * @brief set_disconnect_delay adds a delay to disconnect operations. + * + * This makes the broker wait the specified amount between when a disconnect + * is received from a client, and when the connection is actually closed in + * the broker. + * + * @param delay - the amount to delay by + */ + void set_disconnect_delay(std::chrono::steady_clock::duration delay) { + delay_disconnect_ = force_move(delay); + } + + /** + * @brief set pingresp send operaton + * + * @param b - if true, send pingresp when pingreq is received. + * if false, doesn't send pingresp for test. + */ + void set_pingresp(bool b) { + pingresp_ = b; + } + + /** + * @brief set pingresp send operaton + * + * @param b - if true, send connack when connect is received. + * if false, doesn't send connack for test. + */ + void set_connack(bool b) { + connack_ = b; + } + + /** + * @brief configure the security settings + */ + void set_security(broker::security&& security) { + this->security = force_move(security); + } + + // [end] for test setting + + /** + * @brief handle_accept + * + * Call this function when an server (of whatever kind) has accepted a raw + * connection from an MQTT client. By 'raw connection', this might be raw TCP sockets + * or websockets, or completed a TLS handshake, or any other underlying transport + * type, but what is not meant is that the mqtt client on the other end of the endpoint + * has initiated the MQTT application protocol connection sequence with CONNECT or CONACK + * messages being sent or received. + * + * This function will assign several event handlers into server (of whatever kind) + * that is provided as a parameter. This includes connection handlers, disconnection handlers + * and various handlers for a variety of of MQTT message types. + * + * @param ep - The server (of whichever kind) to accept a connection on. + */ + void handle_accept(con_sp_t spep) { + con_wp_t wp(spep); + endpoint_t& ep = *spep; + + ep.socket().lowest_layer().set_option(as::ip::tcp::no_delay(true)); + ep.set_auto_pub_response(false); + ep.set_async_operation(true); + ep.set_topic_alias_maximum(MQTT_NS::topic_alias_max); + + // set connection (lower than MQTT) level handlers + ep.set_close_handler( + [this, wp] + (){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + close_proc(force_move(sp), true); + }); + ep.set_error_handler( + [this, wp] + (error_code ec){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto ver = sp->get_protocol_version(); + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, this) + << " error_handler is called. ec:" << ec.message() << " protocol_version:" << ver; + + auto send_response = + [&](auto ec) { + if (sp->connected()) { + auto rc = + [&] () -> MQTT_NS::optional { + if (ec == boost::system::errc::protocol_error) { + return MQTT_NS::v5::disconnect_reason_code::protocol_error; + } + else if (ec == boost::system::errc::bad_message) { + return MQTT_NS::v5::disconnect_reason_code::malformed_packet; + } + return MQTT_NS::nullopt; + }(); + if (rc) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "send DISCONNECT reason_code:" << rc.value(); + sp->async_disconnect( + rc.value(), + v5::properties{}, + [sp] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, sp.get()) + << ec.message(); + } + } + ); + } + } + else if (sp->underlying_connected()){ + // underlying layer connected, mqtt connecting + // and protocol_version has already been determind as v5 + auto rc = + [&] () -> MQTT_NS::optional { + if (ec ==boost::system::errc::protocol_error) { + return MQTT_NS::v5::connect_reason_code::protocol_error; + } + else if (ec == boost::system::errc::bad_message) { + return MQTT_NS::v5::connect_reason_code::malformed_packet; + } + return MQTT_NS::nullopt; + }(); + if (rc) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "send CONNACK reason_code:" << rc.value(); + if (connack_) sp->async_connack( + false, + rc.value(), + [sp] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, sp.get()) + << ec.message(); + } + } + ); + } + } + }; + + switch (ver) { + case MQTT_NS::protocol_version::v5: + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#S4_13_Errors + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205 + // + // The DISCONNECT packet is the final MQTT Control Packet sent from the Client or + // the Server. + send_response(ec); + break; + case MQTT_NS::protocol_version::v3_1_1: + // DISCONNECT can't be sent by broker on v3.1.1 + // + // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718090 + // + // The DISCONNECT Packet is the final Control Packet sent from the Client to the Server. + // It indicates that the Client is disconnecting cleanly. + // + // At the MQTT connecting, there is no appropriate Connect Return Code on v3.1.1 + // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718035 + break; + default: + // The protocol_version is in the CONNECT packet. + // Protocol error could happen before the protocol_version is parsed. + break; + } + close_proc(force_move(sp), true); + } + ); + + // set MQTT level handlers + ep.set_connect_handler( + [this, wp] + (buffer client_id, + optional username, + optional password, + optional will, + bool clean_session, + std::uint16_t keep_alive) { + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return connect_handler( + force_move(sp), + force_move(client_id), + force_move(username), + force_move(password), + force_move(will), + clean_session, + keep_alive, + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_connect_handler( + [this, wp] + (buffer client_id, + optional username, + optional password, + optional will, + bool clean_start, + std::uint16_t keep_alive, + v5::properties props) { + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return connect_handler( + force_move(sp), + force_move(client_id), + force_move(username), + force_move(password), + force_move(will), + clean_start, + keep_alive, + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_disconnect_handler( + [this, wp] + (){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + disconnect_handler(force_move(sp)); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + } + } + ); + ep.set_v5_disconnect_handler( + [this, wp] + (v5::disconnect_reason_code /*reason_code*/, v5::properties props) { + if (h_disconnect_props_) h_disconnect_props_(force_move(props)); + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + disconnect_handler(force_move(sp)); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + } + } + ); + ep.set_puback_handler( + [this, wp] + (packet_id_t packet_id){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return puback_handler( + force_move(sp), + packet_id, + v5::puback_reason_code::success, + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_puback_handler( + [this, wp] + (packet_id_t packet_id, + v5::puback_reason_code reason_code, + v5::properties props){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return puback_handler( + force_move(sp), + packet_id, + reason_code, + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_pubrec_handler( + [this, wp] + (packet_id_t packet_id){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return pubrec_handler( + force_move(sp), + packet_id, + v5::pubrec_reason_code::success, + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_pubrec_handler( + [this, wp] + (packet_id_t packet_id, + v5::pubrec_reason_code reason_code, + v5::properties props){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return pubrec_handler( + force_move(sp), + packet_id, + reason_code, + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_pubrel_handler( + [this, wp] + (packet_id_t packet_id){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return pubrel_handler( + force_move(sp), + packet_id, + v5::pubrel_reason_code::success, + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_pubrel_handler( + [this, wp] + (packet_id_t packet_id, + v5::pubrel_reason_code reason_code, + v5::properties props){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return pubrel_handler( + force_move(sp), + packet_id, + reason_code, + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_pubcomp_handler( + [this, wp] + (packet_id_t packet_id){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return pubcomp_handler( + force_move(sp), + packet_id, + v5::pubcomp_reason_code::success, + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_pubcomp_handler( + [this, wp] + (packet_id_t packet_id, + v5::pubcomp_reason_code reason_code, + v5::properties props){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return pubcomp_handler( + force_move(sp), + packet_id, + reason_code, + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_publish_handler( + [this, wp] + (optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents){ + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return publish_handler( + force_move(sp), + packet_id, + pubopts, + force_move(topic_name), + force_move(contents), + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_publish_handler( + [this, wp] + (optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents, + v5::properties props + ) { + if (h_publish_props_) h_publish_props_(props); + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return publish_handler( + force_move(sp), + packet_id, + pubopts, + force_move(topic_name), + force_move(contents), + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_subscribe_handler( + [this, wp] + (packet_id_t packet_id, + std::vector entries) { + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return subscribe_handler( + force_move(sp), + packet_id, + force_move(entries), + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_subscribe_handler( + [this, wp] + (packet_id_t packet_id, + std::vector entries, + v5::properties props + ) { + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return subscribe_handler( + force_move(sp), + packet_id, + force_move(entries), + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_unsubscribe_handler( + [this, wp] + (packet_id_t packet_id, + std::vector entries) { + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return unsubscribe_handler( + force_move(sp), + packet_id, + force_move(entries), + v5::properties{} + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_v5_unsubscribe_handler( + [this, wp] + (packet_id_t packet_id, + std::vector entries, + v5::properties props + ) { + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + auto p = sp.get(); + try { + return unsubscribe_handler( + force_move(sp), + packet_id, + force_move(entries), + force_move(props) + ); + } + catch (std::exception const& ex) { + MQTT_LOG("mqtt_broker", error) + << MQTT_ADD_VALUE(address, p) + << ex.what(); + return true; + } + } + ); + ep.set_pingreq_handler( + [this, wp] { + con_sp_t sp = wp.lock(); + BOOST_ASSERT(sp); + if (pingresp_) { + auto p = sp.get(); + p->async_pingresp( + [sp = force_move(sp)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, sp.get()) + << ec.message(); + } + } + ); + } + return true; + } + ); + ep.set_v5_auth_handler( + [this] + (v5::auth_reason_code /*reason_code*/, + v5::properties props + ) { + if (h_auth_props_) h_auth_props_(force_move(props)); + return true; + } + ); + + // Pass spep to keep lifetime. + // It makes sure wp.lock() never return nullptr in the handlers below + // including close_handler and error_handler. + ep.start_session(spep); + } + + void set_connack_props(v5::properties props) { + connack_props_ = force_move(props); + } + + void set_suback_props(v5::properties props) { + suback_props_ = force_move(props); + } + + void set_unsuback_props(v5::properties props) { + unsuback_props_ = force_move(props); + } + + void set_puback_props(v5::properties props) { + puback_props_ = force_move(props); + } + + void set_pubrec_props(v5::properties props) { + pubrec_props_ = force_move(props); + } + + void set_pubrel_props(v5::properties props) { + pubrel_props_ = force_move(props); + } + + void set_pubcomp_props(v5::properties props) { + pubcomp_props_ = force_move(props); + } + + void set_connect_props_handler(std::function h) { + h_connect_props_ = force_move(h); + } + + void set_disconnect_props_handler(std::function h) { + h_disconnect_props_ = force_move(h); + } + + void set_publish_props_handler(std::function h) { + h_publish_props_ = force_move(h); + } + + void set_puback_props_handler(std::function h) { + h_puback_props_ = force_move(h); + } + + void set_pubrec_props_handler(std::function h) { + h_pubrec_props_ = force_move(h); + } + + void set_pubrel_props_handler(std::function h) { + h_pubrel_props_ = force_move(h); + } + + void set_pubcomp_props_handler(std::function h) { + h_pubcomp_props_ = force_move(h); + } + + void set_subscribe_props_handler(std::function h) { + h_subscribe_props_ = force_move(h); + } + + void set_unsubscribe_props_handler(std::function h) { + h_unsubscribe_props_ = force_move(h); + } + + void set_auth_props_handler(std::function h) { + h_auth_props_ = force_move(h); + } + + void clear_all_sessions() { + std::lock_guard g(mtx_sessions_); + sessions_.clear(); + } + + void clear_all_retained_topics() { + std::lock_guard g(mtx_retains_); + retains_.clear(); + } + +private: + static void force_disconnect(con_sp_t spep) { + auto p = spep.get(); + p->async_force_disconnect( + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + }; + + static void disconnect_and_force_disconnect(con_sp_t spep, v5::disconnect_reason_code rc) { + auto p = spep.get(); + p->async_disconnect( + rc, + v5::properties{}, + [spep = force_move(spep)] + (error_code) mutable { + force_disconnect(force_move(spep)); + } + ); + }; + + /** + * @brief connect_proc Process an incoming CONNECT packet + * + * This is called by the connect_handler function, which is registered + * on mqtt connections where the raw transport (tcp / tls / websocket / etc) + * is established, but the CONNECT message has not been sent / received by + * the mqtt client on the other end of the connection. + * + * When the CONNECT message is received, this function is called after some + * basic pre-connection logic, to setup the record keeping that this broker + * class needs to handle the connection and process subscriptions and publishing. + * + * @param clean_start - if the clean-start flag is set on the CONNECT message. + * @param spep - varient of shared pointers to underlying connection type. + * @param req_client_id - the id that the client wants to use (username will be prepended) + * @param will - the last-will-and-testiment of the connection, if any. + */ + bool connect_handler( + con_sp_t spep, + buffer client_id, + optional noauth_username, + optional password, + optional will, + bool clean_start, + std::uint16_t /*keep_alive*/, + v5::properties props + ) { + auto& ep = *spep; + + optional username; + if (ep.get_preauthed_user_name()) { + if (security.login_cert(ep.get_preauthed_user_name().value())) { + username = ep.get_preauthed_user_name(); + } + } + else if (!noauth_username && !password) { + username = security.login_anonymous(); + } + else if (noauth_username && password) { + username = security.login(*noauth_username, *password); + } + + // If login fails, try the unauthenticated user + if (!username) username = security.login_unauthenticated(); + + v5::properties connack_props; + connect_param cp = handle_connect_props(ep, props, will); + + if (!username) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "User failed to login: " + << (noauth_username ? std::string(*noauth_username) : std::string("anonymous user")); + + send_connack( + ep, + false, // session present + false, // authenticated + force_move(connack_props), + [spep](error_code) { + disconnect_and_force_disconnect(spep, v5::disconnect_reason_code::not_authorized); + } + ); + + return true; + } + + if (client_id.empty()) { + if (!handle_empty_client_id(spep, client_id, clean_start, connack_props)) { + return false; + } + // A new client id was generated + client_id = buffer(string_view(spep->get_client_id())); + } + + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "User logged in as: '" << *username << "', client_id: " << client_id; + + /** + * http://docs.oasis-open.org/mqtt/mqtt/v5.0/cs02/mqtt-v5.0-cs02.html#_Toc514345311 + * 3.1.2.4 Clean Start + * If a CONNECT packet is received with Clean Start is set to 1, the Client and Server MUST + * discard any existing Session and start a new Session [MQTT-3.1.2-4]. Consequently, + * the Session Present flag in CONNACK is always set to 0 if Clean Start is set to 1. + */ + + // Find any sessions that have the same client_id + std::lock_guard g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.lower_bound(std::make_tuple(*username, client_id)); + if (it == idx.end() || + it->client_id() != client_id || + it->get_username() != *username + ) { + // new connection + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "cid:" << client_id + << " new connection inserted."; + it = idx.emplace_hint( + it, + timer_ioc_, + mtx_subs_map_, + subs_map_, + shared_targets_, + spep, + client_id, + *username, + force_move(will), + // will_sender + [this](auto&&... params) { + do_publish(std::forward(params)...); + }, + force_move(cp.will_expiry_interval), + force_move(cp.session_expiry_interval) + ); + if (cp.response_topic_requested) { + // set_response_topic never modify key part + set_response_topic(const_cast(*it), connack_props, *username); + } + send_connack( + ep, + false, // session present + true, // authenticated + force_move(connack_props) + ); + } + else if (it->online()) { + // online overwrite + if (close_proc_no_lock(it->con(), true, v5::disconnect_reason_code::session_taken_over)) { + // remain offline + if (clean_start) { + // discard offline session + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "cid:" << client_id + << "online connection exists, discard old one due to new one's clean_start and renew"; + if (cp.response_topic_requested) { + // set_response_topic never modify key part + set_response_topic(const_cast(*it), connack_props, *username); + } + send_connack( + ep, + false, // session present + true, // authenticated + force_move(connack_props) + ); + idx.modify( + it, + [&](auto& e) { + e.clean(); + e.update_will(timer_ioc_, force_move(will), cp.will_expiry_interval); + e.set_username(*username); + // renew_session_expiry updates index + e.renew_session_expiry(force_move(cp.session_expiry_interval)); + }, + [](auto&) { BOOST_ASSERT(false); } + ); + } + else { + // inherit online session if previous session's session exists + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "cid:" << client_id + << "online connection exists, inherit old one and renew"; + if (cp.response_topic_requested) { + // set_response_topic never modify key part + set_response_topic(const_cast(*it), connack_props, *username); + } + send_connack( + ep, + true, // session present + true, // authenticated + force_move(connack_props), + [ + this, + &idx, + it, + will = force_move(will), + clean_start, + spep, + will_expiry_interval = cp.will_expiry_interval, + session_expiry_interval = cp.session_expiry_interval, + username + ] + (error_code ec) mutable { + if (ec) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << ec.message(); + return; + } + idx.modify( + it, + [&](auto& e) { + e.renew(spep, clean_start); + e.set_username(*username); + e.update_will(timer_ioc_, force_move(will), will_expiry_interval); + // renew_session_expiry updates index + e.renew_session_expiry(force_move(session_expiry_interval)); + e.send_inflight_messages(); + e.send_all_offline_messages(); + }, + [](auto&) { BOOST_ASSERT(false); } + ); + } + ); + } + } + else { + // new connection + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "cid:" << client_id + << "online connection exists, discard old one due to session_expiry and renew"; + bool inserted; + std::tie(it, inserted) = idx.emplace( + timer_ioc_, + mtx_subs_map_, + subs_map_, + shared_targets_, + spep, + client_id, + *username, + force_move(will), + // will_sender + [this](auto&&... params) { + do_publish(std::forward(params)...); + }, + force_move(cp.will_expiry_interval), + force_move(cp.session_expiry_interval) + ); + BOOST_ASSERT(inserted); + if (cp.response_topic_requested) { + // set_response_topic never modify key part + set_response_topic(const_cast(*it), connack_props, *username); + } + send_connack( + ep, + false, // session present + true, // authenticated + force_move(connack_props) + ); + } + } + else { + // offline -> online + if (clean_start) { + // discard offline session + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "cid:" << client_id + << "offline connection exists, discard old one due to new one's clean_start and renew"; + if (cp.response_topic_requested) { + // set_response_topic never modify key part + set_response_topic(const_cast(*it), connack_props, *username); + } + send_connack( + ep, + false, // session present + true, // authenticated + force_move(connack_props) + ); + idx.modify( + it, + [&](auto& e) { + e.clean(); + e.renew(spep, clean_start); + e.update_will(timer_ioc_, force_move(will), cp.will_expiry_interval); + e.set_username(*username); + // renew_session_expiry updates index + e.renew_session_expiry(force_move(cp.session_expiry_interval)); + }, + [](auto&) { BOOST_ASSERT(false); } + ); + } + else { + // inherit offline session + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "cid:" << client_id + << "offline connection exists, inherit old one and renew"; + if (cp.response_topic_requested) { + // set_response_topic never modify key part + set_response_topic(const_cast(*it), connack_props, *username); + } + send_connack( + ep, + true, // session present + true, // authenticated + force_move(connack_props), + [ + this, + &idx, + it, + will = force_move(will), + clean_start, + spep, + will_expiry_interval = cp.will_expiry_interval, + session_expiry_interval = cp.session_expiry_interval, + username + ] + (error_code ec) mutable { + if (ec) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << ec.message(); + return; + } + idx.modify( + it, + [&](auto& e) { + e.renew(spep, clean_start); + e.set_username(*username); + e.update_will(timer_ioc_, force_move(will), will_expiry_interval); + // renew_session_expiry updates index + e.renew_session_expiry(force_move(session_expiry_interval)); + e.send_inflight_messages(); + e.send_all_offline_messages(); + }, + [](auto&) { BOOST_ASSERT(false); } + ); + } + ); + } + } + + return true; + } + + struct connect_param { + optional session_expiry_interval; + optional will_expiry_interval; + bool response_topic_requested = false; + }; + + connect_param handle_connect_props( + endpoint_t& ep, + v5::properties const& props, + optional const& will + ) { + connect_param cp; + if (ep.get_protocol_version() == protocol_version::v5) { + { + auto v = get_property(props); + if (v && v.value().val() != 0) { + cp.session_expiry_interval.emplace(std::chrono::seconds(v.value().val())); + } + } + { + auto v = get_property(props); + if (v && v.value().val() == 1) { + cp.response_topic_requested = true; + } + } + + if (will) { + auto v = get_property(will.value().props()); + if (v) { + cp.will_expiry_interval.emplace(std::chrono::seconds(v.value().val())); + } + } + + if (h_connect_props_) { + h_connect_props_(props); + } + } + return cp; + } + + void send_connack( + endpoint_t& ep, + bool session_present, + bool authenticated, + v5::properties props, + std::function finish = [](error_code){} + ) { + // Reply to the connect message. + switch (ep.get_protocol_version()) { + case protocol_version::v3_1_1: + if (connack_) ep.async_connack( + session_present, + authenticated ? connect_return_code::accepted + : connect_return_code::not_authorized, + [finish = force_move(finish)] + (error_code ec) { + finish(ec); + } + ); + break; + case protocol_version::v5: + // connack_props_ member varible is for testing + if (connack_props_.empty()) { + // props local variable is is for real case + props.emplace_back(v5::property::topic_alias_maximum{topic_alias_max}); + props.emplace_back(v5::property::receive_maximum{receive_maximum_max}); + if (connack_) ep.async_connack( + session_present, + authenticated ? v5::connect_reason_code::success + : v5::connect_reason_code::not_authorized, + force_move(props), + [finish = force_move(finish)] + (error_code ec) { + finish(ec); + } + ); + } + else { + // use connack_props_ for testing + if (connack_) ep.async_connack( + session_present, + authenticated ? v5::connect_reason_code::success + : v5::connect_reason_code::not_authorized, + connack_props_, + [finish = force_move(finish)] + (error_code ec) { + finish(ec); + } + ); + } + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void remove_rule(std::size_t rule_nr) { + security.remove_auth(rule_nr); + } + + void set_response_topic(session_state& s, v5::properties& connack_props, std::string const &username) { + auto response_topic = + [&] { + if (auto rt_opt = s.get_response_topic()) { + return rt_opt.value(); + } + auto rt = create_uuid_string(); + s.set_response_topic(rt); + return rt; + } (); + + auto rule_nr = security.add_auth( + response_topic, + { "@any" }, MQTT_NS::broker::security::authorization::type::allow, + { username }, MQTT_NS::broker::security::authorization::type::allow + ); + + s.set_clean_handler( + [this, response_topic, rule_nr]() { + std::lock_guard g(mtx_retains_); + retains_.erase(response_topic); + remove_rule(rule_nr); + } + ); + + connack_props.emplace_back( + v5::property::response_topic( + allocate_buffer(response_topic) + ) + ); + } + + bool handle_empty_client_id( + con_sp_t spep, + buffer const& client_id, + bool clean_start, + v5::properties& connack_props + ) { + auto& ep = *spep; + switch (ep.get_protocol_version()) { + case protocol_version::v3_1_1: + if (client_id.empty()) { + if (clean_start) { + ep.set_client_id(create_uuid_string()); + } + else { + // https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349242 + // If the Client supplies a zero-byte ClientId, + // the Client MUST also set CleanSession to 1 [MQTT-3.1.3-7]. + // If it's a not a clean session, but no client id is provided, + // we would have no way to map this connection's session to a new connection later. + // So the connection must be rejected. + if (connack_) { + ep.async_connack( + false, + connect_return_code::identifier_rejected, + [&ep, spep = force_move(spep)] + (error_code ec) mutable { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + ep.async_force_disconnect( + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + } + ); + } + return false; + } + } + break; + case protocol_version::v5: + if (client_id.empty()) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059 + // A Server MAY allow a Client to supply a ClientID that has a length of zero bytes, + // however if it does so the Server MUST treat this as a special case and assign a + // unique ClientID to that Client [MQTT-3.1.3-6]. It MUST then process the + // CONNECT packet as if the Client had provided that unique ClientID, + // and MUST return the Assigned Client Identifier in the CONNACK packet [MQTT-3.1.3-7]. + // If the Server rejects the ClientID it MAY respond to the CONNECT packet with a CONNACK + // using Reason Code 0x85 (Client Identifier not valid) as described in section 4.13 + // Handling errors, and then it MUST close the Network Connection [MQTT-3.1.3-8]. + // + // mqtt_cpp author's note: On v5.0, no Clean Start restriction is described. + ep.set_client_id(create_uuid_string()); + connack_props.emplace_back( + v5::property::assigned_client_identifier(buffer(string_view(ep.get_client_id()))) + ); + } + break; + default: + BOOST_ASSERT(false); + return false; + } + return true; + } + + void disconnect_handler( + con_sp_t spep + ) { + if (delay_disconnect_) { + tim_disconnect_.expires_after(delay_disconnect_.value()); + tim_disconnect_.wait(); + } + close_proc(force_move(spep), false); + } + + /** + * @brief close_proc_no_lock - clean up a connection that has been closed. + * + * @param ep - The underlying server (of whichever type) that is disconnecting. + * @param send_will - Whether to publish this connections last will + * @return true if offline session is remained, otherwise false + */ + // TODO: Maybe change the name of this function. + bool close_proc_no_lock( + con_sp_t spep, + bool send_will, + optional rc) { + endpoint_t& ep = *spep; + + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // act_sess_it == act_sess_idx.end() could happen if broker accepts + // the session from client but the client closes the session before sending + // MQTT `CONNECT` message. + // In this case, do nothing is correct behavior. + if (it == idx.end()) return false; + + bool session_clear = + [&] { + if (ep.get_protocol_version() == protocol_version::v3_1_1) { + return ep.clean_session(); + } + else { + BOOST_ASSERT(ep.get_protocol_version() == protocol_version::v5); + auto const& sei_opt = it->session_expiry_interval(); + return !sei_opt || sei_opt.value() == std::chrono::steady_clock::duration::zero(); + } + } (); + + auto do_send_will = + [&](session_state& ss) { + if (send_will) { + ss.send_will(); + } + else { + ss.clear_will(); + } + }; + + if (session_clear) { + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& ss = const_cast(*it); + do_send_will(ss); + if (rc) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, spep.get()) + << "disconnect_and_force_disconnect(async) cid:" << ss.client_id(); + disconnect_and_force_disconnect(spep, rc.value()); + } + else { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, spep.get()) + << "force_disconnect(async) cid:" << ss.client_id(); + force_disconnect(spep); + } + idx.erase(it); + BOOST_ASSERT(sessions_.get().find(spep) == sessions_.get().end()); + return false; + } + else { + idx.modify( + it, + [&](session_state& ss) { + do_send_will(ss); + if (rc) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, spep.get()) + << "disconnect_and_force_disconnect(async) cid:" << ss.client_id(); + disconnect_and_force_disconnect(spep, rc.value()); + } + else { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, spep.get()) + << "force_disconnect(async) cid:" << ss.client_id(); + force_disconnect(spep); + } + // become_offline updates index + ss.become_offline( + [this] + (std::shared_ptr const& sp_tim) { + sessions_.get().erase(sp_tim); + } + ); + }, + [](auto&) { BOOST_ASSERT(false); } + ); + return true; + } + + } + + /** + * @brief close_proc - clean up a connection that has been closed. + * + * @param ep - The underlying server (of whichever type) that is disconnecting. + * @param send_will - Whether to publish this connections last will + * @param rc - Reason Code for send pack DISCONNECT + * @return true if offline session is remained, otherwise false + */ + // TODO: Maybe change the name of this function. + bool close_proc( + con_sp_t spep, + bool send_will, + optional rc = nullopt + ) { + std::lock_guard g(mtx_sessions_); + return close_proc_no_lock(force_move(spep), send_will, rc); + } + + bool publish_handler( + con_sp_t spep, + optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents, + v5::properties props) { + + auto& ep = *spep; + + std::shared_lock g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // broker uses async_* APIs + // If broker erase a connection, then async_force_disconnect() + // and/or async_force_disconnect () is called. + // During async operation, spep is valid but it has already been + // erased from sessions_ + if (it == idx.end()) return true; + + auto send_pubres = + [&] (bool authorized = true) { + switch (pubopts.get_qos()) { + case qos::at_least_once: + ep.async_puback( + packet_id.value(), + authorized ? v5::puback_reason_code::success + : v5::puback_reason_code::not_authorized, + puback_props_, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + break; + case qos::exactly_once: { + ep.async_pubrec( + packet_id.value(), + authorized ? v5::pubrec_reason_code::success + : v5::pubrec_reason_code::not_authorized, + pubrec_props_, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + } break; + default: + break; + } + }; + + // See if this session is authorized to publish this topic + if (security.auth_pub(topic_name, it->get_username()) != security::authorization::type::allow) { + + // Publish not authorized + send_pubres(false); + return true; + } + + v5::properties forward_props; + + for (auto&& p : props) { + MQTT_NS::visit( + make_lambda_visitor( + [](v5::property::topic_alias&&) { + // TopicAlias is not forwarded + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113 + // A receiver MUST NOT carry forward any Topic Alias mappings from + // one Network Connection to another [MQTT-3.3.2-7]. + }, + [&ep](v5::property::subscription_identifier&& p) { + MQTT_LOG("mqtt_broker", warning) + << MQTT_ADD_VALUE(address, &ep) + << "Subscription Identifier from client not forwarded sid:" << p.val(); + }, + [&forward_props](auto&& p) { + forward_props.push_back(force_move(p)); + } + ), + force_move(p) + ); + } + + do_publish( + *it, + force_move(topic_name), + force_move(contents), + pubopts.get_qos() | pubopts.get_retain(), // remove dup flag + force_move(forward_props) + ); + + send_pubres(); + return true; + } + + bool puback_handler( + con_sp_t spep, + packet_id_t packet_id, + v5::puback_reason_code /*reason_code*/, + v5::properties /*props*/) { + std::shared_lock g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // broker uses async_* APIs + // If broker erase a connection, then async_force_disconnect() + // and/or async_force_disconnect () is called. + // During async operation, spep is valid but it has already been + // erased from sessions_ + if (it == idx.end()) return true; + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& ss = const_cast(*it); + ss.erase_inflight_message_by_packet_id(packet_id); + ss.send_offline_messages_by_packet_id_release(); + + return true; + } + + bool pubrec_handler( + con_sp_t spep, + packet_id_t packet_id, + v5::pubrec_reason_code reason_code, + v5::properties /*props*/) { + std::shared_lock g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // broker uses async_* APIs + // If broker erase a connection, then async_force_disconnect() + // and/or async_force_disconnect () is called. + // During async operation, spep is valid but it has already been + // erased from sessions_ + if (it == idx.end()) return true; + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& ss = const_cast(*it); + ss.erase_inflight_message_by_packet_id(packet_id); + + if (is_error(reason_code)) return true; + + auto& ep = *spep; + + switch (ep.get_protocol_version()) { + case protocol_version::v3_1_1: + ep.async_pubrel( + packet_id, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + break; + case protocol_version::v5: + ep.async_pubrel( + packet_id, + v5::pubrel_reason_code::success, + pubrel_props_, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + break; + default: + BOOST_ASSERT(false); + break; + } + return true; + } + + bool pubrel_handler( + con_sp_t spep, + packet_id_t packet_id, + v5::pubrel_reason_code reason_code, + v5::properties /*props*/) { + std::shared_lock g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // broker uses async_* APIs + // If broker erase a connection, then async_force_disconnect() + // and/or async_force_disconnect () is called. + // During async operation, spep is valid but it has already been + // erased from sessions_ + if (it == idx.end()) return true; + + auto& ep = *spep; + + switch (ep.get_protocol_version()) { + case protocol_version::v3_1_1: + ep.async_pubcomp( + packet_id, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + break; + case protocol_version::v5: + ep.async_pubcomp( + packet_id, + // pubcomp reason code is the same as pubrel one + static_cast(reason_code), + pubcomp_props_, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + break; + default: + BOOST_ASSERT(false); + break; + } + return true; + } + + bool pubcomp_handler( + con_sp_t spep, + packet_id_t packet_id, + v5::pubcomp_reason_code /*reason_code*/, + v5::properties /*props*/){ + std::shared_lock g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // broker uses async_* APIs + // If broker erase a connection, then async_force_disconnect() + // and/or async_force_disconnect () is called. + // During async operation, spep is valid but it has already been + // erased from sessions_ + if (it == idx.end()) return true; + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& ss = const_cast(*it); + ss.erase_inflight_message_by_packet_id(packet_id); + ss.send_offline_messages_by_packet_id_release(); + + return true; + } + + bool subscribe_handler( + con_sp_t spep, + packet_id_t packet_id, + std::vector entries, + v5::properties props) { + + auto& ep = *spep; + + std::shared_lock g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // broker uses async_* APIs + // If broker erase a connection, then async_force_disconnect() + // and/or async_force_disconnect () is called. + // During async operation, spep is valid but it has already been + // erased from sessions_ + if (it == idx.end()) return true; + + // The element of sessions_ must have longer lifetime + // than corresponding subscription. + // Because the subscription store the reference of the element. + optional ssr_opt; + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& ss = const_cast(*it); + ssr_opt.emplace(ss); + + BOOST_ASSERT(ssr_opt); + session_state_ref ssr {ssr_opt.value()}; + + auto publish_proc = + [this, &ssr](retain_t const& r, qos qos_value, optional sid) { + auto props = r.props; + if (sid) { + props.push_back(v5::property::subscription_identifier(*sid)); + } + if (r.tim_message_expiry) { + auto d = + std::chrono::duration_cast( + r.tim_message_expiry->expiry() - std::chrono::steady_clock::now() + ).count(); + set_property( + props, + v5::property::message_expiry_interval( + static_cast(d) + ) + ); + } + ssr.get().publish( + timer_ioc_, + r.topic, + r.contents, + std::min(r.qos_value, qos_value) | MQTT_NS::retain::yes, + props + ); + }; + + std::vector> retain_deliver; + retain_deliver.reserve(entries.size()); + + // subscription identifier + optional sid; + + // An in-order list of qos settings, used to send the reply. + // The MQTT protocol 3.1.1 - 3.8.4 Response - paragraph 6 + // allows the server to grant a lower QOS than requested + // So we reply with the QOS setting that was granted + // not the one requested. + switch (ep.get_protocol_version()) { + case protocol_version::v3_1_1: { + std::vector res; + res.reserve(entries.size()); + for (auto& e : entries) { + if (security.is_subscribe_authorized(ss.get_username(), e.topic_filter)) { + res.emplace_back(qos_to_suback_return_code(e.subopts.get_qos())); // converts to granted_qos_x + ssr.get().subscribe( + force_move(e.share_name), + e.topic_filter, + e.subopts, + [&] { + std::shared_lock g(mtx_retains_); + retains_.find( + e.topic_filter, + [&](retain_t const& r) { + retain_deliver.emplace_back( + [&publish_proc, &r, qos_value = e.subopts.get_qos(), sid] { + publish_proc(r, qos_value, sid); + } + ); + } + ); + } + ); + } + else { + // User not authorized to subscribe to topic filter + res.emplace_back(suback_return_code::failure); + } + } + // Acknowledge the subscriptions, and the registered QOS settings + ep.async_suback( + packet_id, + force_move(res), + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + } break; + case protocol_version::v5: { + // Get subscription identifier + auto v = get_property(props); + if (v && v.value().val() != 0) { + sid.emplace(v.value().val()); + } + + std::vector res; + res.reserve(entries.size()); + for (auto& e : entries) { + if (security.is_subscribe_authorized(ss.get_username(), e.topic_filter)) { + res.emplace_back(v5::qos_to_suback_reason_code(e.subopts.get_qos())); // converts to granted_qos_x + ssr.get().subscribe( + force_move(e.share_name), + e.topic_filter, + e.subopts, + [&] { + std::shared_lock g(mtx_retains_); + retains_.find( + e.topic_filter, + [&](retain_t const& r) { + retain_deliver.emplace_back( + [&publish_proc, &r, qos_value = e.subopts.get_qos(), sid] { + publish_proc(r, qos_value, sid); + } + ); + } + ); + }, + sid + ); + } + else { + // User not authorized to subscribe to topic filter + res.emplace_back(v5::suback_reason_code::not_authorized); + } + } + if (h_subscribe_props_) h_subscribe_props_(props); + // Acknowledge the subscriptions, and the registered QOS settings + ep.async_suback( + packet_id, + force_move(res), + suback_props_, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + + for (auto const& f : retain_deliver) { + f(); + } + return true; + } + + bool unsubscribe_handler( + con_sp_t spep, + packet_id_t packet_id, + std::vector entries, + v5::properties props) { + + auto& ep = *spep; + + std::shared_lock g(mtx_sessions_); + auto& idx = sessions_.get(); + auto it = idx.find(spep); + + // broker uses async_* APIs + // If broker erase a connection, then async_force_disconnect() + // and/or async_force_disconnect () is called. + // During async operation, spep is valid but it has already been + // erased from sessions_ + if (it == idx.end()) return true; + + // The element of sessions_ must have longer lifetime + // than corresponding subscription. + // Because the subscription store the reference of the element. + optional ssr_opt; + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& ss = const_cast(*it); + ssr_opt.emplace(ss); + + BOOST_ASSERT(ssr_opt); + session_state_ref ssr {ssr_opt.value()}; + + // For each subscription that this connection has + // Compare against the list of topic filters, and remove + // the subscription if the topic filter is in the list. + for (auto const& e : entries) { + ssr.get().unsubscribe(e.share_name, e.topic_filter); + } + + switch (ep.get_protocol_version()) { + case protocol_version::v3_1_1: + ep.async_unsuback( + packet_id, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + break; + case protocol_version::v5: + if (h_unsubscribe_props_) h_unsubscribe_props_(props); + ep.async_unsuback( + packet_id, + std::vector( + entries.size(), + v5::unsuback_reason_code::success + ), + unsuback_props_, + [spep = force_move(spep)] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, spep.get()) + << ec.message(); + } + } + ); + break; + default: + BOOST_ASSERT(false); + break; + } + + return true; + } + + /** + * @brief do_publish Publish a message to any subscribed clients. + * + * @param source_ss - soource session_state. + * @param topic - The topic to publish the message on. + * @param contents - The contents of the message. + * @param pubopts - publish options + * @param props - properties + */ + void do_publish( + session_state const& source_ss, + buffer topic, + buffer contents, + publish_options pubopts, + v5::properties props + ) { + // Get auth rights for this topic + // auth_users prepared once here, and then referred multiple times in subs_map_.modify() for efficiency + auto auth_users = security.auth_sub(topic); + + // publish the message to subscribers. + // retain is delivered as the original only if rap_value is rap::retain. + // On MQTT v3.1.1, rap_value is always rap::dont. + auto deliver = + [&] (session_state& ss, subscription& sub, auto const& auth_users) { + + // See if this session is authorized to subscribe this topic + auto access = security.auth_sub_user(auth_users, ss.get_username()); + if (access != security::authorization::type::allow) return; + + publish_options new_pubopts = std::min(pubopts.get_qos(), sub.subopts.get_qos()); + if (sub.subopts.get_rap() == rap::retain && pubopts.get_retain() == MQTT_NS::retain::yes) { + new_pubopts |= MQTT_NS::retain::yes; + } + + if (sub.sid) { + props.push_back(v5::property::subscription_identifier(sub.sid.value())); + ss.deliver( + timer_ioc_, + topic, + contents, + new_pubopts, + props + ); + props.pop_back(); + } + else { + ss.deliver( + timer_ioc_, + topic, + contents, + new_pubopts, + props + ); + } + }; + + // share_name topic_filter + std::set> sent; + + { + std::shared_lock g{mtx_subs_map_}; + subs_map_.modify( + topic, + [&](buffer const& /*key*/, subscription& sub) { + if (sub.share_name.empty()) { + // Non shared subscriptions + + // If NL (no local) subscription option is set and + // publisher is the same as subscriber, then skip it. + if (sub.subopts.get_nl() == nl::yes && + sub.ss.get().client_id() == source_ss.client_id()) return; + deliver(sub.ss.get(), sub, auth_users); + } + else { + // Shared subscriptions + bool inserted; + std::tie(std::ignore, inserted) = sent.emplace(sub.share_name, sub.topic_filter); + if (inserted) { + if (auto ssr_opt = shared_targets_.get_target(sub.share_name, sub.topic_filter)) { + deliver(ssr_opt.value().get(), sub, auth_users); + } + } + } + } + ); + } + + optional message_expiry_interval; + if (source_ss.get_protocol_version() == protocol_version::v5) { + auto v = get_property(props); + if (v) { + message_expiry_interval.emplace(std::chrono::seconds(v.value().val())); + } + + } + + /* + * If the message is marked as being retained, then we + * keep it in case a new subscription is added that matches + * this topic. + * + * @note: The MQTT standard 3.3.1.3 RETAIN makes it clear that + * retained messages are global based on the topic, and + * are not scoped by the client id. So any client may + * publish a retained message on any topic, and the most + * recently published retained message on a particular + * topic is the message that is stored on the server. + * + * @note: The standard doesn't make it clear that publishing + * a message with zero length, but the retain flag not + * set, does not result in any existing retained message + * being removed. However, internet searching indicates + * that most brokers have opted to keep retained messages + * when receiving contents of zero bytes, unless the so + * received message has the retain flag set, in which case + * the retained message is removed. + */ + if (pubopts.get_retain() == MQTT_NS::retain::yes) { + if (contents.empty()) { + std::lock_guard g(mtx_retains_); + retains_.erase(topic); + } + else { + std::shared_ptr tim_message_expiry; + if (message_expiry_interval) { + tim_message_expiry = std::make_shared(timer_ioc_, message_expiry_interval.value()); + tim_message_expiry->async_wait( + [this, topic = topic, wp = std::weak_ptr(tim_message_expiry)] + (boost::system::error_code const& ec) { + if (auto sp = wp.lock()) { + if (!ec) { + retains_.erase(topic); + } + } + } + ); + } + + std::lock_guard g(mtx_retains_); + retains_.insert_or_assign( + topic, + retain_t { + force_move(topic), + force_move(contents), + force_move(props), + pubopts.get_qos(), + tim_message_expiry + } + ); + } + } + } + +private: + as::io_context& timer_ioc_; ///< The boost asio context to run this broker on. + as::steady_timer tim_disconnect_; ///< Used to delay disconnect handling for testing + optional delay_disconnect_; ///< Used to delay disconnect handling for testing + + // Authorization and authentication settings + broker::security security; + + mutable mutex mtx_subs_map_; + sub_con_map subs_map_; /// subscription information + shared_target shared_targets_; /// shared subscription targets + + ///< Map of active client id and connections + /// session_state has references of subs_map_ and shared_targets_. + /// because session_state (member of sessions_) has references of subs_map_ and shared_targets_. + mutable mutex mtx_sessions_; + session_states sessions_; + + mutable mutex mtx_retains_; + retained_messages retains_; ///< A list of messages retained so they can be sent to newly subscribed clients. + + // MQTTv5 members + v5::properties connack_props_; + v5::properties suback_props_; + v5::properties unsuback_props_; + v5::properties puback_props_; + v5::properties pubrec_props_; + v5::properties pubrel_props_; + v5::properties pubcomp_props_; + std::function h_connect_props_; + std::function h_disconnect_props_; + std::function h_publish_props_; + std::function h_puback_props_; + std::function h_pubrec_props_; + std::function h_pubrel_props_; + std::function h_pubcomp_props_; + std::function h_subscribe_props_; + std::function h_unsubscribe_props_; + std::function h_auth_props_; + bool pingresp_ = true; + bool connack_ = true; +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_BROKER_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/broker_namespace.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/broker_namespace.hpp new file mode 100644 index 000000000..30db3dd82 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/broker_namespace.hpp @@ -0,0 +1,26 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_BROKER_NAMESPACE_HPP) +#define MQTT_BROKER_BROKER_NAMESPACE_HPP + +#include + +#include + +#if __cplusplus >= 201703L + +#define MQTT_BROKER_NS_BEGIN namespace MQTT_NS::broker { +#define MQTT_BROKER_NS_END } + +#else // __cplusplus >= 201703L + +#define MQTT_BROKER_NS_BEGIN namespace MQTT_NS { namespace broker { +#define MQTT_BROKER_NS_END } } + +#endif // __cplusplus >= 201703L + +#endif // MQTT_BROKER_BROKER_NAMESPACE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/common_type.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/common_type.hpp new file mode 100644 index 000000000..7336a9c8e --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/common_type.hpp @@ -0,0 +1,24 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_COMMON_TYPE_HPP) +#define MQTT_BROKER_COMMON_TYPE_HPP + +#include + +#include +#include + +MQTT_BROKER_NS_BEGIN + +using endpoint_t = server<>::endpoint_t; +using con_sp_t = std::shared_ptr; +using con_wp_t = std::weak_ptr; +using packet_id_t = endpoint_t::packet_id_t; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_COMMON_TYPE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/constant.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/constant.hpp new file mode 100644 index 000000000..ed9c46d00 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/constant.hpp @@ -0,0 +1,24 @@ +// Copyright Wouter van Kleunen 2022 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_CONSTANT_HPP) +#define MQTT_BROKER_CONSTANT_HPP + + +#include +#include + +namespace MQTT_NS { + +namespace broker { + +static constexpr std::size_t max_cn_size = 0xffff; + +} // namespace broker + +} // namespace MQTT_NS + +#endif // MQTT_BROKER_CONSTANT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/inflight_message.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/inflight_message.hpp new file mode 100644 index 000000000..f9e11f62a --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/inflight_message.hpp @@ -0,0 +1,158 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_INFLIGHT_MESSAGE_HPP) +#define MQTT_BROKER_INFLIGHT_MESSAGE_HPP + +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +class inflight_messages; + +class inflight_message { +public: + inflight_message( + store_message_variant msg, + any life_keeper, + std::shared_ptr tim_message_expiry) + :msg_ { force_move(msg) }, + life_keeper_ { force_move(life_keeper) }, + tim_message_expiry_ { force_move(tim_message_expiry) } + {} + + packet_id_t packet_id() const { + return + MQTT_NS::visit( + make_lambda_visitor( + [](auto const& m) { + return m.packet_id(); + } + ), + msg_ + ); + } + + void send(endpoint_t& ep) const { + optional msg_opt; + if (tim_message_expiry_) { + MQTT_NS::visit( + make_lambda_visitor( + [&](v5::basic_publish_message const& m) { + auto updated_msg = m; + auto d = + std::chrono::duration_cast( + tim_message_expiry_->expiry() - std::chrono::steady_clock::now() + ).count(); + if (d < 0) d = 0; + updated_msg.update_prop( + v5::property::message_expiry_interval( + static_cast(d) + ) + ); + msg_opt.emplace(force_move(updated_msg)); + }, + [](auto const&) { + } + ), + msg_ + ); + } + // packet_id_exhausted never happen because inflight message has already + // allocated packet_id at the previous connection. + // In async_send_store_message(), packet_id is registered. + ep.async_send_store_message( + msg_opt ? msg_opt.value() : msg_, + life_keeper_, + [sp = ep.shared_from_this()](error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, sp.get()) + << ec; + } + } + ); + } + +private: + friend class inflight_messages; + + store_message_variant msg_; + any life_keeper_; + std::shared_ptr tim_message_expiry_; +}; + +class inflight_messages { +public: + void insert( + store_message_variant msg, + any life_keeper, + std::shared_ptr tim_message_expiry + ) { + messages_.emplace_back( + force_move(msg), + force_move(life_keeper), + force_move(tim_message_expiry) + ); + } + + void send_all_messages(endpoint_t& ep) { + for (auto const& ifm : messages_) { + ifm.send(ep); + } + } + + void clear() { + messages_.clear(); + } + + template + decltype(auto) get() { + return messages_.get(); + } + + template + decltype(auto) get() const { + return messages_.get(); + } + +private: + using mi_inflight_message = mi::multi_index_container< + inflight_message, + mi::indexed_by< + mi::sequenced< + mi::tag + >, + mi::ordered_unique< + mi::tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(inflight_message, packet_id_t, packet_id) + >, + mi::ordered_non_unique< + mi::tag, + BOOST_MULTI_INDEX_MEMBER(inflight_message, std::shared_ptr, tim_message_expiry_) + > + > + >; + + mi_inflight_message messages_; +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_INFLIGHT_MESSAGE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/mutex.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/mutex.hpp new file mode 100644 index 000000000..9458fdbcf --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/mutex.hpp @@ -0,0 +1,20 @@ +// Copyright Takatoshi Kondo 2021 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_MUTEX_HPP) +#define MQTT_BROKER_MUTEX_HPP + +#include + +#include + +MQTT_BROKER_NS_BEGIN + +using mutex = std::shared_timed_mutex; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_MUTEX_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/offline_message.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/offline_message.hpp new file mode 100644 index 000000000..4befea662 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/offline_message.hpp @@ -0,0 +1,195 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_OFFLINE_MESSAGE_HPP) +#define MQTT_BROKER_OFFLINE_MESSAGE_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +namespace mi = boost::multi_index; + +class offline_messages; + +// The offline_message structure holds messages that have been published on a +// topic that a not-currently-connected client is subscribed to. +// When a new connection is made with the client id for this saved data, +// these messages will be published to that client, and only that client. +class offline_message { +public: + offline_message( + buffer topic, + buffer contents, + publish_options pubopts, + v5::properties props, + std::shared_ptr tim_message_expiry) + : topic_(force_move(topic)), + contents_(force_move(contents)), + pubopts_(pubopts), + props_(force_move(props)), + tim_message_expiry_(force_move(tim_message_expiry)) + { } + + bool send(endpoint_t& ep) { + auto props = props_; + if (tim_message_expiry_) { + auto d = + std::chrono::duration_cast( + tim_message_expiry_->expiry() - std::chrono::steady_clock::now() + ).count(); + if (d < 0) d = 0; + set_property( + props, + v5::property::message_expiry_interval( + static_cast(d) + ) + ); + } + auto qos_value = pubopts_.get_qos(); + if (qos_value == qos::at_least_once || + qos_value == qos::exactly_once) { + if (auto pid = ep.acquire_unique_packet_id_no_except()) { + ep.async_publish( + pid.value(), + force_move(topic_), + force_move(contents_), + pubopts_, + force_move(props), + any{}, + [sp = ep.shared_from_this()] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", warning) + << MQTT_ADD_VALUE(address, sp.get()) + << ec.message(); + } + } + ); + return true; + } + } + else { + ep.publish( + topic_, + contents_, + pubopts_, + force_move(props) + ); + return true; + } + return false; + } + +private: + friend class offline_messages; + + buffer topic_; + buffer contents_; + publish_options pubopts_; + v5::properties props_; + std::shared_ptr tim_message_expiry_; +}; + +class offline_messages { +public: + void send_until_fail(endpoint_t& ep) { + auto& idx = messages_.get(); + while (!idx.empty()) { + auto it = idx.begin(); + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& m = const_cast(*it); + if (m.send(ep)) { + idx.pop_front(); + } + else { + break; + } + } + } + + void clear() { + messages_.clear(); + } + + bool empty() const { + return messages_.empty(); + } + + void push_back( + as::io_context& timer_ioc, + buffer pub_topic, + buffer contents, + publish_options pubopts, + v5::properties props) { + optional message_expiry_interval; + + auto v = get_property(props); + if (v) { + message_expiry_interval.emplace(std::chrono::seconds(v.value().val())); + } + + std::shared_ptr tim_message_expiry; + if (message_expiry_interval) { + tim_message_expiry = std::make_shared(timer_ioc, message_expiry_interval.value()); + tim_message_expiry->async_wait( + [this, wp = std::weak_ptr(tim_message_expiry)](error_code ec) mutable { + if (auto sp = wp.lock()) { + if (!ec) { + messages_.get().erase(sp); + } + } + } + ); + } + + auto& seq_idx = messages_.get(); + seq_idx.emplace_back( + force_move(pub_topic), + force_move(contents), + pubopts, + force_move(props), + force_move(tim_message_expiry) + ); + } + +private: + using mi_offline_message = mi::multi_index_container< + offline_message, + mi::indexed_by< + mi::sequenced< + mi::tag + >, + mi::ordered_non_unique< + mi::tag, + BOOST_MULTI_INDEX_MEMBER(offline_message, std::shared_ptr, tim_message_expiry_) + > + > + >; + + mi_offline_message messages_; +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_OFFLINE_MESSAGE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/property_util.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/property_util.hpp new file mode 100644 index 000000000..5051e15a0 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/property_util.hpp @@ -0,0 +1,49 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_PROPERTY_UTIL_HPP) +#define MQTT_BROKER_PROPERTY_UTIL_HPP + +#include + +#include +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +template +inline optional get_property(v5::properties const& props) { + optional result; + + auto visitor = make_lambda_visitor( + [&result](T const& t) { result = t; }, + [](auto const&) { } + ); + + for (auto const& p : props) { + MQTT_NS::visit(visitor, p); + } + + return result; +} + +template +inline void set_property(v5::properties& props, T&& v) { + auto visitor = make_lambda_visitor( + [&v](T& t) mutable { t = std::forward(v); }, + [](auto&) { } + ); + + for (auto& p : props) { + MQTT_NS::visit(visitor, p); + } +} + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_PROPERTY_UTIL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retain_t.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retain_t.hpp new file mode 100644 index 000000000..022091b66 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retain_t.hpp @@ -0,0 +1,48 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_RETAIN_T_HPP) +#define MQTT_BROKER_RETAIN_T_HPP + +#include + +#include + +#include +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +struct session_state; + +// A collection of messages that have been retained in +// case clients add a new subscription to the associated topics. +struct retain_t { + retain_t( + buffer topic, + buffer contents, + v5::properties props, + qos qos_value, + std::shared_ptr tim_message_expiry = std::shared_ptr()) + :topic(force_move(topic)), + contents(force_move(contents)), + props(force_move(props)), + qos_value(qos_value), + tim_message_expiry(force_move(tim_message_expiry)) + { } + + buffer topic; + buffer contents; + v5::properties props; + qos qos_value; + std::shared_ptr tim_message_expiry; +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_RETAIN_T_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retained_messages.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retained_messages.hpp new file mode 100644 index 000000000..c1532272f --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retained_messages.hpp @@ -0,0 +1,25 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_RETAINED_MESSAGES_HPP) +#define MQTT_BROKER_RETAINED_MESSAGES_HPP + +#include + +#include // reference_wrapper + +#include + +#include +#include + +MQTT_BROKER_NS_BEGIN + +using retained_messages = retained_topic_map; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_RETAINED_MESSAGES_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retained_topic_map.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retained_topic_map.hpp new file mode 100644 index 000000000..9f05cf27e --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/retained_topic_map.hpp @@ -0,0 +1,371 @@ +// Copyright Wouter van Kleunen 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_RETAINED_TOPIC_MAP_HPP) +#define MQTT_BROKER_RETAINED_TOPIC_MAP_HPP + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +MQTT_BROKER_NS_BEGIN + +namespace mi = boost::multi_index; + +template +class retained_topic_map { + + // Exceptions used + static void throw_max_stored_topics() { throw std::overflow_error("Retained map maximum number of topics reached"); } + static void throw_no_wildcards_allowed() { throw std::runtime_error("Retained map no wildcards allowed in retained topic name"); } + + using node_id_t = std::size_t; + + static constexpr node_id_t root_parent_id = 0; + static constexpr node_id_t root_node_id = 1; + static constexpr node_id_t max_node_id = std::numeric_limits::max(); + + struct path_entry { + node_id_t parent_id; + buffer name_buffer; + string_view name; + + node_id_t id; + + std::size_t count = 1; + static constexpr std::size_t max_count = std::numeric_limits::max(); + + // Increase the count for this node + void increase_count() { + if (count == max_count) { + throw_max_stored_topics(); + } + + ++count; + } + + // Decrease the count for this node + void decrease_count() { + BOOST_ASSERT(count >= count); + --count; + } + + optional value; + + path_entry(node_id_t parent_id, string_view name, node_id_t id) + : parent_id(parent_id), name_buffer(allocate_buffer(name)), name(name_buffer), id(id) + { } + }; + + struct wildcard_index_tag { }; + struct direct_index_tag { }; + + // allow for two indices on retained topics + using path_entry_set = mi::multi_index_container< + path_entry, + mi::indexed_by< + // index required for direct child access + mi::hashed_unique < + mi::tag, + mi::composite_key + >, + + // index required for wildcard processing + mi::ordered_non_unique< mi::tag, BOOST_MULTI_INDEX_MEMBER(path_entry, node_id_t, parent_id) > + > + >; + + using direct_const_iterator = typename path_entry_set::template index::type::const_iterator; + using wildcard_const_iterator = typename path_entry_set::template index::type::const_iterator; + + path_entry_set map; + size_t map_size; + node_id_t next_node_id; + + direct_const_iterator root; + + direct_const_iterator create_topic(string_view topic) { + direct_const_iterator parent = root; + + topic_filter_tokenizer( + topic, + [this, &parent](string_view t) { + if (t == "+" || t == "#") { + throw_no_wildcards_allowed(); + } + + node_id_t parent_id = parent->id; + + auto& direct_index = map.template get(); + direct_const_iterator entry = direct_index.find(std::make_tuple(parent_id, t)); + + if (entry == direct_index.end()) { + entry = map.insert(path_entry(parent->id, t, next_node_id++)).first; + if (next_node_id == max_node_id) { + throw_max_stored_topics(); + } + } + else { + direct_index.modify(entry, [](path_entry& entry){ entry.increase_count(); }); + } + + parent = entry; + return true; + } + ); + + return parent; + } + + std::vector find_topic(string_view topic) { + std::vector path; + direct_const_iterator parent = root; + + topic_filter_tokenizer( + topic, + [this, &parent, &path](string_view t) { + auto const& direct_index = map.template get(); + auto entry = direct_index.find(std::make_tuple(parent->id, t)); + + if (entry == direct_index.end()) { + path = std::vector(); + return false; + } + + path.push_back(entry); + parent = entry; + return true; + } + ); + + return path; + } + + // Match all underlying topics when a hash entry is matched + // perform a breadth-first iteration over all items in the tree below + template + void match_hash_entries(node_id_t parent, Output&& callback, bool ignore_system) const { + std::deque entries; + entries.push_back(parent); + std::deque new_entries; + + auto const& wildcard_index = map.template get(); + + while (!entries.empty()) { + new_entries.resize(0); + + for (auto root : entries) { + // Find all entries below this node + for (auto i = wildcard_index.lower_bound(root); i != wildcard_index.end() && i->parent_id == root; ++i) { + + // Should we ignore system matches + if (!ignore_system || i->name.empty() || i->name[0] != '$') { + if (i->value) { + callback(*i->value); + } + + new_entries.push_back(i->id); + } + } + } + + // Ignore system only on first level + ignore_system = false; + std::swap(entries, new_entries); + } + + } + + // Find all topics that match the specified topic filter + template + void find_match(string_view topic_filter, Output&& callback) const { + std::deque entries; + entries.push_back(root); + + std::deque new_entries; + topic_filter_tokenizer( + topic_filter, + [this, &entries, &new_entries, &callback](string_view t) { + auto const& direct_index = map.template get(); + auto const& wildcard_index = map.template get(); + new_entries.resize(0); + + for (auto const& entry : entries) { + node_id_t parent = entry->id; + + if (t == string_view("+")) { + for (auto i = wildcard_index.lower_bound(parent); i != wildcard_index.end() && i->parent_id == parent; ++i) { + if (parent != root_node_id || i->name.empty() || i->name[0] != '$') { + new_entries.push_back(map.template project(i)); + } + else { + break; + } + } + } + else if (t == string_view("#")) { + match_hash_entries(parent, callback, parent == root_node_id); + return false; + } + else { + direct_const_iterator i = direct_index.find(std::make_tuple(parent, t)); + if (i != direct_index.end()) { + new_entries.push_back(i); + } + } + } + + std::swap(new_entries, entries); + return !entries.empty(); + } + ); + + for (auto& entry : entries) { + if (entry->value) { + callback(*entry->value); + } + } + } + + // Remove a value at the specified topic + size_t erase_topic(string_view topic) { + auto path = find_topic(topic); + + // Reset the value if there is actually something stored + if (!path.empty() && path.back()->value) { + auto& direct_index = map.template get(); + direct_index.modify(path.back(), [](path_entry &entry){ entry.value = nullopt; }); + + // Do iterators stay valid when erasing ? I think they do ? + for (auto entry : path) { + direct_index.modify(entry, [](path_entry& entry){ entry.decrease_count(); }); + + if (entry->count == 0) { + map.erase(entry); + } + } + + return 1; + } + + return 0; + } + + // Increase the number of topics for this path + void increase_topics(std::vector const &path) { + auto& direct_index = map.template get(); + + for(auto& i : path) { + direct_index.modify(i, [](path_entry& entry){ entry.increase_count(); }); + } + } + + // Increase the map size (total number of topics stored) + void increase_map_size() { + if(map_size == std::numeric_limits::max()) { + throw_max_stored_topics(); + } + + ++map_size; + } + + // Decrease the map size (total number of topics stored) + void decrease_map_size(size_t count) { + BOOST_ASSERT(map_size >= count); + map_size -= count; + } + + void init_map() { + map_size = 0; + // Create the root node + root = map.insert(path_entry(root_parent_id, "", root_node_id)).first; + next_node_id = root_node_id + 1; + } + +public: + retained_topic_map() + { + init_map(); + } + + // Insert a value at the specified topic + template + std::size_t insert_or_assign(string_view topic, V&& value) { + auto& direct_index = map.template get(); + auto path = this->find_topic(topic); + + if (path.empty()) { + auto new_topic = this->create_topic(topic); + direct_index.modify(new_topic, [&value](path_entry &entry) mutable { entry.value.emplace(std::forward(value)); }); + increase_map_size(); + return 1; + } + + if (!path.back()->value) { + this->increase_topics(path); + direct_index.modify(path.back(), [&value](path_entry &entry) mutable { entry.value.emplace(std::forward(value)); }); + increase_map_size(); + return 1; + } + + direct_index.modify(path.back(), [&value](path_entry &entry) mutable { entry.value.emplace(std::forward(value)); }); + + return 0; + } + + // Find all stored topics that math the specified topic_filter + template + void find(string_view topic_filter, Output&& callback) const { + find_match(topic_filter, std::forward(callback)); + } + + // Remove a stored value at the specified topic + std::size_t erase(string_view topic) { + auto result = erase_topic(topic); + decrease_map_size(result); + return result; + } + + // Get the number of entries stored in the map + std::size_t size() const { return map_size; } + + // Get the number of entries in the map (for debugging purpose only) + std::size_t internal_size() const { return map.size(); } + + // Clear all topics + void clear() { + map.clear(); + init_map(); + } + + // Dump debug information + template + void dump(Output &out) { + auto const& direct_index = map.template get(); + for (auto const& i : direct_index) { + out << i.parent_id << " " << i.name << " " << (i.value ? "init" : "-") << " " << i.count << '\n'; + } + } + +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_RETAINED_TOPIC_MAP_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/security.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/security.hpp new file mode 100644 index 000000000..9dcd6f1ed --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/security.hpp @@ -0,0 +1,815 @@ +// Copyright Wouter van Kleunen 2021 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SECURITY_HPP) +#define MQTT_BROKER_SECURITY_HPP + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#if MQTT_USE_TLS +#include +#endif + +MQTT_BROKER_NS_BEGIN + +/** Remove comments from a JSON file (comments start with # and are not inside ' ' or " ") */ +inline std::string json_remove_comments(std::istream& input) { + bool inside_comment = false; + bool inside_single_quote = false; + bool inside_double_quote = false; + + std::ostringstream result; + + while (true) { + char c; + if (input.get(c).eof()) break; + + if (!inside_double_quote && !inside_single_quote && c == '#') inside_comment = true; + if (!inside_double_quote && c == '\'') inside_single_quote = !inside_single_quote; + if (!inside_single_quote && c == '"') inside_double_quote = !inside_double_quote; + if (!inside_double_quote && c == '\n') inside_comment = false; + + if (!inside_comment) result << c; + } + + return result.str(); +} + + +struct security { + + static constexpr char const* any_group_name = "@any"; + + struct authentication { + enum class method { + sha256, + plain_password, + client_cert, + anonymous, + unauthenticated + }; + + authentication( + method auth_method = method::sha256, + optional const& digest = nullopt, + std::string const& salt = std::string() + ) + : auth_method(auth_method), + digest(digest), + salt(salt) + { + } + + method auth_method; + optional digest; + std::string salt; + + std::vector groups; + }; + + + struct authorization { + enum class type { + deny, allow, none + }; + + authorization(string_view topic, std::size_t rule_nr) + : topic(topic), + rule_nr(rule_nr), + sub_type(type::none), + pub_type(type::none) + { + } + + std::vector topic_tokens; + + std::string topic; + std::size_t rule_nr; + + type sub_type; + std::set sub; + + type pub_type; + std::set pub; + }; + + struct group { + std::string name; + std::vector members; + }; + + /** Return username of anonymous user */ + optional const& login_anonymous() const { + return anonymous; + } + + /** Return username of unauthorized user */ + optional const& login_unauthenticated() const { + return unauthenticated; + } + + template + static std::string to_hex(T start, T end) { + std::string result; + boost::algorithm::hex(start, end, std::back_inserter(result)); + return result; + } + +#if defined(MQTT_USE_TLS) + static std::string sha256hash(string_view message) { + std::shared_ptr mdctx(EVP_MD_CTX_new(), EVP_MD_CTX_free); + EVP_DigestInit_ex(mdctx.get(), EVP_sha256(), NULL); + EVP_DigestUpdate(mdctx.get(), message.data(), message.size()); + + std::vector digest(static_cast(EVP_MD_size(EVP_sha256()))); + unsigned int digest_size = static_cast(digest.size()); + + EVP_DigestFinal_ex(mdctx.get(), digest.data(), &digest_size); + return to_hex(digest.data(), digest.data() + digest_size); + } +#else + static std::string sha256hash(string_view message) { + return std::string(message); + } +#endif + + bool login_cert(string_view username) const { + auto i = authentication_.find(std::string(username)); + return + i != authentication_.end() && + i->second.auth_method == security::authentication::method::client_cert; + } + + optional login(string_view username, string_view password) const { + auto i = authentication_.find(std::string(username)); + if (i != authentication_.end() && + i->second.auth_method == security::authentication::method::sha256) { + return [&] () -> optional { + if (boost::iequals( + i->second.digest.value(), + sha256hash(i->second.salt + std::string(password)) + ) + ) { + return std::string(username); + } + else { + return nullopt; + } + } (); + + } + else if ( + i != authentication_.end() && + i->second.auth_method == security::authentication::method::plain_password) { + return [&] () -> optional { + if (i->second.digest.value() == password) { + return std::string(username); + } + else { + return nullopt; + } + } (); + } + return nullopt; + } + + static authorization::type get_auth_type(string_view type) { + if (type == "allow") return authorization::type::allow; + if (type == "deny") return authorization::type::deny; + throw std::runtime_error( + "An invalid authorization type was specified: " + + std::string(type) + ); + } + + static bool is_valid_group_name(string_view name) { + return !name.empty() && name[0] == '@'; // TODO: validate utf-8 + } + + static bool is_valid_user_name(string_view name) { + return !name.empty() && name[0] != '@'; // TODO: validate utf-8 + } + + std::size_t get_next_rule_nr() const { + std::size_t rule_nr = 0; + for (auto const& i: authorization_) { + rule_nr = std::max(rule_nr, i.rule_nr); + } + return rule_nr + 1; + } + + void default_config() { + char const* username = "anonymous"; + authentication login(authentication::method::anonymous); + authentication_.insert({ username, login}); + anonymous = username; + + char const* topic = "#"; + authorization auth(topic, get_next_rule_nr()); + auth.topic_tokens = get_topic_filter_tokens("#"); + auth.sub_type = authorization::type::allow; + auth.sub.insert(username); + auth.pub_type = authorization::type::allow; + auth.pub.insert(username); + authorization_.push_back(auth); + + groups_.insert({ std::string(any_group_name), group() }); + + validate(); + } + + std::size_t add_auth( + std::string const& topic_filter, + std::set const& pub, + authorization::type auth_pub_type, + std::set const& sub, + authorization::type auth_sub_type + ) { + for(auto const& j : pub) { + if (!is_valid_user_name(j) && !is_valid_group_name(j)) { + throw std::runtime_error( + "An invalid username or groupname was specified for the authorization: " + j + ); + } + validate_entry("topic " + topic_filter, j); + } + + for(auto const& j : sub) { + if (!is_valid_user_name(j) && !is_valid_group_name(j)) { + throw std::runtime_error( + "An invalid username or groupname was specified for the authorization: " + j + ); + } + validate_entry("topic " + topic_filter, j); + } + + std::size_t rule_nr = get_next_rule_nr(); + authorization auth(topic_filter, rule_nr); + auth.topic_tokens = get_topic_filter_tokens(topic_filter); + auth.pub = pub; + auth.pub_type = auth_pub_type; + auth.sub = sub; + auth.sub_type = auth_sub_type; + + for (auto const& j: sub) { + auth_sub_map.insert_or_assign( + topic_filter, + j, + std::make_pair(auth_sub_type, rule_nr) + ); + } + for (auto const& j: pub) { + auth_pub_map.insert_or_assign( + topic_filter, + j, + std::make_pair(auth_pub_type, rule_nr) + ); + } + + authorization_.push_back(auth); + return rule_nr; + } + + void remove_auth(std::size_t rule_nr) + { + for (auto i = authorization_.begin(); i != authorization_.end(); ++i) { + if (i->rule_nr == rule_nr) { + for (auto const& j: i->sub) { + auth_sub_map.erase(i->topic, j); + } + for (auto const& j: i->pub) { + auth_pub_map.erase(i->topic, j); + } + + authorization_.erase(i); + return; + } + } + } + + void load_json(std::istream& input) { + // Create a root + boost::property_tree::ptree root; + + std::istringstream input_without_comments(json_remove_comments(input)); + boost::property_tree::read_json(input_without_comments, root); + + groups_.insert({ std::string(any_group_name), group() }); + + for (auto const& i: root.get_child("authentication")) { + std::string name = i.second.get("name"); + if (!is_valid_user_name(name)) { + throw std::runtime_error("An invalid username was specified: " + name); + } + + std::string method = i.second.get("method"); + + if (method == "sha256") { + std::string digest = i.second.get("digest"); + std::string salt = i.second.get("salt", ""); + + authentication auth(authentication::method::sha256, digest, salt); + authentication_.insert( { name, auth }); + } + else if (method == "plain_password") { + std::string digest = i.second.get("password"); + + authentication auth(authentication::method::plain_password, digest); + authentication_.insert( { name, auth }); + } + else if (method == "client_cert") { + authentication auth(authentication::method::client_cert); + authentication_.insert({ name, auth }); + } + else if (method == "anonymous") { + if(anonymous) { + throw std::runtime_error( + "Only a single anonymous user can be configured, anonymous user: " + + *anonymous + ); + } + anonymous = name; + + authentication auth(authentication::method::anonymous); + authentication_.insert( { name, auth }); + } + else if (method == "unauthenticated") { + if (unauthenticated) { + throw std::runtime_error( + "Only a single unauthenticated user can be configured, unauthenticated user: " + + *unauthenticated + ); + } + unauthenticated = name; + + authentication auth(authentication::method::unauthenticated); + authentication_.insert( { name, auth }); + } + else { + throw std::runtime_error("An invalid method was specified: " + method); + } + } + if (root.get_child_optional("groups")) { + for (auto const& i: root.get_child("groups")) { + std::string name = i.second.get("name"); + if (!is_valid_group_name(name)) { + throw std::runtime_error("An invalid group name was specified: " + name); + } + + group group; + if (i.second.get_child_optional("members")) { + for (auto const& j: i.second.get_child("members")) { + auto username = j.second.get_value(); + if (!is_valid_user_name(username)) { + throw std::runtime_error("An invalid user name was specified: " + username); + } + group.members.push_back(username); + } + } + + groups_.insert({ name, group }); + } + } + + for (auto const& i: root.get_child("authorization")) { + std::string name = i.second.get("topic"); + if (!validate_topic_filter(name)) { + throw std::runtime_error("An invalid topic filter was specified: " + name); + } + + authorization auth(name, get_next_rule_nr()); + auth.topic_tokens = get_topic_filter_tokens(name); + + if (i.second.get_child_optional("allow")) { + auto &allow = i.second.get_child("allow"); + if (allow.get_child_optional("sub")) { + for (auto const& j: allow.get_child("sub")) { + auth.sub.insert(j.second.get_value()); + } + auth.sub_type = authorization::type::allow; + } + + if (allow.get_child_optional("pub")) { + for (auto const& j: allow.get_child("pub")) { + auth.pub.insert(j.second.get_value()); + } + auth.pub_type = authorization::type::allow; + } + } + + if (i.second.get_child_optional("deny")) { + auto &deny = i.second.get_child("deny"); + if (deny.get_child_optional("sub")) { + for (auto const& j: deny.get_child("sub")) { + auth.sub.insert(j.second.get_value()); + } + auth.sub_type = authorization::type::deny; + } + + if (deny.get_child_optional("pub")) { + for (auto const& j: deny.get_child("pub")) { + auth.pub.insert(j.second.get_value()); + } + auth.pub_type = authorization::type::deny; + } + + } + authorization_.push_back(auth); + } + + validate(); + } + + template + void get_auth_sub_by_user(string_view username, T&& callback) const { + std::set username_and_groups; + username_and_groups.insert(std::string(username)); + + for (auto const& i: groups_) { + if (i.first == any_group_name || + std::find( + i.second.members.begin(), + i.second.members.end(), + username + ) != i.second.members.end() + ) { + username_and_groups.insert(i.first); + } + } + + for (auto const& i: authorization_) { + if (i.sub_type != authorization::type::none) { + bool sets_intersect = false; + auto store_intersect = + [&sets_intersect] + (std::string const &) mutable { + sets_intersect = true; + }; + + std::set_intersection( + i.sub.begin(), + i.sub.end(), + username_and_groups.begin(), + username_and_groups.end(), + boost::make_function_output_iterator(std::ref(store_intersect)) + ); + + if (sets_intersect) { + std::forward(callback)(i); + } + } + } + } + + authorization::type auth_pub(string_view topic, string_view username) const { + authorization::type result_type = authorization::type::deny; + + std::set username_and_groups; + username_and_groups.insert(std::string(username)); + + for (auto const& i : groups_) { + if (i.first == any_group_name || + std::find( + i.second.members.begin(), + i.second.members.end(), + username + ) != i.second.members.end() + ) { + username_and_groups.insert(i.first); + } + } + + std::size_t priority = 0; + auth_pub_map.find( + topic, + [&]( + std::string const& allowed_username, + std::pair entry + ) { + if (username_and_groups.find(allowed_username) != username_and_groups.end()) { + if (entry.second >= priority) { + result_type = entry.first; + priority = entry.second; + } + } + } + ); + + return result_type; + } + + std::map auth_sub(string_view topic) const { + std::map result; + + std::size_t priority = 0; + auth_sub_map.find( + topic, + [&]( + std::string const &allowed_username, + std::pair entry + ) { + if (entry.second >= priority) { + result[allowed_username] = entry.first; + priority = entry.second; + } + } + ); + + return result; + } + + authorization::type auth_sub_user( + std::map const& result, + std::string const& username) const { + auto i = result.find(username); + if (i != result.end()) return i->second; + + for (auto const& i: groups_) { + if (i.first == any_group_name || + std::find( + i.second.members.begin(), + i.second.members.end(), + username + ) != i.second.members.end() + ) { + auto j = result.find(i.first); + if (j != result.end()) return j->second; + } + } + + return authorization::type::deny; + } + + static bool is_hash(string_view level) { return level == "#"; } + static bool is_plus(string_view level) { return level == "+"; } + static bool is_literal(string_view level) { return !is_hash(level) && !is_plus(level); } + + static optional + is_subscribe_allowed( + std::vector const& authorized_filter, + string_view subscription_filter + ) { + optional result; + auto append_result = + [&result](string_view token) { + if (result) { + result.value() += topic_filter_separator; + result.value().append(token.data(), token.size()); + } + else { + result = std::string(token); + } + }; + + auto filter_begin = authorized_filter.begin(); + + auto subscription_begin = subscription_filter.begin(); + auto subscription_next = topic_filter_tokenizer_next(subscription_begin, subscription_filter.end()); + + while (true) { + if (filter_begin == authorized_filter.end()) { + return nullopt; + } + + auto auth = *filter_begin; + ++filter_begin; + + if (is_hash(auth)) { + append_result( + make_string_view( + subscription_begin, + subscription_filter.end() + ) + ); + return result; + } + + auto sub = make_string_view( + subscription_begin, + subscription_next + ); + + if (is_hash(sub)) { + append_result(auth); + + while (filter_begin < authorized_filter.end()) { + append_result(*filter_begin); + ++filter_begin; + } + + return result; + } + + if (is_plus(auth)) { + append_result(sub); + } + else if (is_plus(sub)) { + append_result(auth); + } + else { + if (auth != sub) { + return nullopt; + } + + append_result(auth); + } + + if (subscription_next == subscription_filter.end()) break; + subscription_begin = std::next(subscription_next); + subscription_next = + topic_filter_tokenizer_next( + subscription_begin, + subscription_filter.end() + ); + } + + if (filter_begin < authorized_filter.end()) { + return nullopt; + } + + return result; + } + + static bool is_subscribe_denied( + std::vector const& deny_filter, + string_view subscription_filter + ) { + bool result = true; + auto filter_begin = deny_filter.begin(); + + auto tokens_count = + topic_filter_tokenizer( + subscription_filter, + [&](auto sub) { + if (filter_begin == deny_filter.end()) { + result = false; + return false; + }; + + std::string deny = *filter_begin; + ++filter_begin; + + if (deny != sub) { + if (is_hash(deny)) { + result = true; + return false; + } + + if (is_hash(sub)) { + result = false; + return false; + } + + if (is_plus(deny)) { + result = true; + return true; + } + + result = false; + return false; + } + + return true; + } + ); + + return result && (tokens_count == deny_filter.size()); + } + + std::vector + get_auth_sub_topics(string_view username, string_view topic_filter) const { + std::vector auth_topics; + get_auth_sub_by_user( + username, + [&](authorization const& i) { + if (i.sub_type == authorization::type::allow) { + auto entry = is_subscribe_allowed(i.topic_tokens, topic_filter); + if (entry) { + auth_topics.push_back(entry.value()); + } + } + else { + for (auto j = auth_topics.begin(); j != auth_topics.end();) { + if (is_subscribe_denied(i.topic_tokens, topic_filter)) { + j = auth_topics.erase(j); + } + else { + ++j; + } + } + } + } + ); + return auth_topics; + } + + /** + * @brief Determine if user is allowed to subscribe to the specified topic filter + * @param username The username to check + * @param topic_filter Topic filter the user would like to subscribe to + * @return true if the user is authorized + */ + bool is_subscribe_authorized(string_view username, string_view topic_filter) const { + return !get_auth_sub_topics(username, topic_filter).empty(); + } + + // Get the individual path elements of the topic filter + static std::vector get_topic_filter_tokens(string_view topic_filter) { + std::vector result; + topic_filter_tokenizer( + topic_filter, + [&result](auto str) { + result.push_back(std::string(str)); + return true; + } + ); + + return result; + } + + std::map authentication_; + std::map groups_; + + std::vector authorization_; + + optional anonymous; + optional unauthenticated; + + using auth_map_type = multiple_subscription_map>; + auth_map_type auth_pub_map; + auth_map_type auth_sub_map; + +private: + void validate_entry(std::string const& context, std::string const& name) const { + if (is_valid_group_name(name) && groups_.find(name) == groups_.end()) { + throw std::runtime_error("An invalid group name was specified for " + context + ": " + name); + } + if (is_valid_user_name(name) && authentication_.find(name) == authentication_.end()) { + throw std::runtime_error("An invalid username name was specified for " + context + ": " + name); + } + } + + void validate() { + for (auto const& i : groups_) { + for (auto const& j : i.second.members) { + auto iter = authentication_.find(j); + if(is_valid_user_name(j) && iter == authentication_.end()) + throw std::runtime_error("An invalid username name was specified for group " + i.first + ": " + j); + } + } + + std::string unsalted; + for (auto const& i : authentication_) { + if (i.second.auth_method == authentication::method::sha256 && i.second.salt.empty()) { + if (!unsalted.empty()) unsalted += ", "; + unsalted += i.first; + } + } + + if (!unsalted.empty()) { + MQTT_LOG("mqtt_broker", warning) + << "The following users have no salt specified: " + << unsalted; + } + + for (auto const& i : authorization_) { + for (auto const& j: i.sub) { + validate_entry("topic " + i.topic, j); + + if (is_valid_user_name(j) || is_valid_group_name(j)) { + auth_sub_map.insert_or_assign(i.topic, j, std::make_pair(i.sub_type, i.rule_nr)); + } + } + for (auto const& j: i.pub) { + validate_entry("topic " + i.topic, j); + + if(is_valid_user_name(j) || is_valid_group_name(j)) { + auth_pub_map.insert_or_assign(i.topic, j, std::make_pair(i.pub_type, i.rule_nr)); + } + } + } + } + +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SECURITY_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/session_state.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/session_state.hpp new file mode 100644 index 000000000..6f0ab8ba6 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/session_state.hpp @@ -0,0 +1,654 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SESSION_STATE_HPP) +#define MQTT_BROKER_SESSION_STATE_HPP + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +namespace as = boost::asio; +namespace mi = boost::multi_index; + +class session_states; + +/** + * http://docs.oasis-open.org/mqtt/mqtt/v5.0/cs02/mqtt-v5.0-cs02.html#_Session_State + * + * 4.1 Session State + * In order to implement QoS 1 and QoS 2 protocol flows the Client and Server need to associate state with the Client Identifier, this is referred to as the Session State. The Server also stores the subscriptions as part of the Session State. + * The session can continue across a sequence of Network Connections. It lasts as long as the latest Network Connection plus the Session Expiry Interval. + * The Session State in the Server consists of: + * · The existence of a Session, even if the rest of the Session State is empty. + * · The Clients subscriptions, including any Subscription Identifiers. + * · QoS 1 and QoS 2 messages which have been sent to the Client, but have not been completely acknowledged. + * · QoS 1 and QoS 2 messages pending transmission to the Client and OPTIONALLY QoS 0 messages pending transmission to the Client. + * · QoS 2 messages which have been received from the Client, but have not been completely acknowledged. + * · The Will Message and the Will Delay Interval + * · If the Session is currently not connected, the time at which the Session will end and Session State will be discarded. + * + * Retained messages do not form part of the Session State in the Server, they are not deleted as a result of a Session ending. + */ +struct session_state { + using will_sender_t = std::function< + void( + session_state const& source_ss, + buffer topic, + buffer contents, + publish_options pubopts, + v5::properties props + ) + >; + + session_state( + as::io_context& timer_ioc, + mutex& mtx_subs_map, + sub_con_map& subs_map, + shared_target& shared_targets, + con_sp_t con, + buffer client_id, + std::string const& username, + optional will, + will_sender_t will_sender, + optional will_expiry_interval, + optional session_expiry_interval) + :timer_ioc_(timer_ioc), + mtx_subs_map_(mtx_subs_map), + subs_map_(subs_map), + shared_targets_(shared_targets), + con_(force_move(con)), + version_(con_->get_protocol_version()), + client_id_(force_move(client_id)), + username_(username), + session_expiry_interval_(force_move(session_expiry_interval)), + tim_will_delay_(timer_ioc_), + will_sender_(force_move(will_sender)), + remain_after_close_( + [&] { + if (version_ == protocol_version::v3_1_1) { + return !con_->clean_session(); + } + else { + BOOST_ASSERT(version_ == protocol_version::v5); + return + session_expiry_interval_ && + session_expiry_interval_.value() != std::chrono::steady_clock::duration::zero(); + } + } () + ) + { + update_will(timer_ioc, will, will_expiry_interval); + } + + ~session_state() { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "session destroy"; + send_will_impl(); + clean(); + } + + bool online() const { + return bool(con_); + } + + template + void become_offline(SessionExpireHandler&& h) { + BOOST_ASSERT(con_); + con_->for_each_store_with_life_keeper( + [this] (store_message_variant msg, any life_keeper) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "store inflight message"; + + std::shared_ptr tim_message_expiry; + + MQTT_NS::visit( + make_lambda_visitor( + [&](v5::basic_publish_message const& m) { + auto v = get_property(m.props()); + if (v) { + tim_message_expiry = + std::make_shared(timer_ioc_, std::chrono::seconds(v.value().val())); + tim_message_expiry->async_wait( + [this, wp = std::weak_ptr(tim_message_expiry)] + (error_code ec) { + if (auto sp = wp.lock()) { + if (!ec) { + erase_inflight_message_by_expiry(sp); + } + } + } + ); + } + }, + [&](auto const&) {} + ), + msg + ); + + insert_inflight_message( + force_move(msg), + force_move(life_keeper), + force_move(tim_message_expiry) + ); + } + ); + qos2_publish_handled_ = con_->get_qos2_publish_handled_pids(); + con_.reset(); + + if (session_expiry_interval_ && + session_expiry_interval_.value() != std::chrono::seconds(session_never_expire)) { + + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "session expiry interval timer set"; + + tim_session_expiry_ = std::make_shared(timer_ioc_, session_expiry_interval_.value()); + tim_session_expiry_->async_wait( + [this, wp = std::weak_ptr(tim_session_expiry_), h = std::forward(h)] + (error_code ec) { + if (auto sp = wp.lock()) { + if (!ec) { + MQTT_LOG("mqtt_broker", info) + << MQTT_ADD_VALUE(address, this) + << "session expired"; + h(sp); + } + } + } + ); + } + } + + void renew_session_expiry(optional v) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "renew_session expiry"; + session_expiry_interval_ = force_move(v); + tim_session_expiry_.reset(); + } + + void publish( + as::io_context& timer_ioc, + buffer pub_topic, + buffer contents, + publish_options pubopts, + v5::properties props) { + + BOOST_ASSERT(online()); + + std::lock_guard g(mtx_offline_messages_); + if (offline_messages_.empty()) { + auto qos_value = pubopts.get_qos(); + if (qos_value == qos::at_least_once || + qos_value == qos::exactly_once) { + if (auto pid = con_->acquire_unique_packet_id_no_except()) { + con_->async_publish( + pid.value(), + force_move(pub_topic), + force_move(contents), + pubopts, + force_move(props), + any{}, + [con = con_] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", warning) + << MQTT_ADD_VALUE(address, con.get()) + << ec.message(); + } + } + ); + return; + } + } + else { + con_->async_publish( + force_move(pub_topic), + force_move(contents), + pubopts, + force_move(props), + any{}, + [con = con_] + (error_code ec) { + if (ec) { + MQTT_LOG("mqtt_broker", warning) + << MQTT_ADD_VALUE(address, con.get()) + << ec.message(); + } + } + ); + return; + } + } + + // offline_messages_ is not empty or packet_id_exhausted + offline_messages_.push_back( + timer_ioc, + force_move(pub_topic), + force_move(contents), + pubopts, + force_move(props) + ); + } + + void deliver( + as::io_context& timer_ioc, + buffer pub_topic, + buffer contents, + publish_options pubopts, + v5::properties props) { + + if (online()) { + publish( + timer_ioc, + force_move(pub_topic), + force_move(contents), + pubopts, + force_move(props) + ); + } + else { + std::lock_guard g(mtx_offline_messages_); + offline_messages_.push_back( + timer_ioc, + force_move(pub_topic), + force_move(contents), + pubopts, + force_move(props) + ); + } + } + + void set_clean_handler(std::function handler) { + clean_handler_ = force_move(handler); + } + + void clean() { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "clean"; + if (clean_handler_) clean_handler_(); + { + std::lock_guard g(mtx_inflight_messages_); + inflight_messages_.clear(); + } + { + std::lock_guard g(mtx_offline_messages_); + offline_messages_.clear(); + } + shared_targets_.erase(*this); + unsubscribe_all(); + } + + template + void subscribe( + buffer share_name, + buffer topic_filter, + subscribe_options subopts, + PublishRetainHandler&& h, + optional sid = nullopt + ) { + if (!share_name.empty()) { + shared_targets_.insert(share_name, topic_filter, *this); + } + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "subscribe" + << " share_name:" << share_name + << " topic_filter:" << topic_filter + << " qos:" << subopts.get_qos(); + + subscription sub {*this, force_move(share_name), topic_filter, subopts, sid }; + auto handle_ret = + [&] { + std::lock_guard g{mtx_subs_map_}; + return subs_map_.insert_or_assign( + force_move(topic_filter), + client_id_, + force_move(sub) + ); + } (); + + auto rh = subopts.get_retain_handling(); + + if (handle_ret.second) { // insert + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "subscription inserted"; + + handles_.insert(handle_ret.first); + if (rh == retain_handling::send || + rh == retain_handling::send_only_new_subscription) { + std::forward(h)(); + } + } + else { // update + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "subscription updated"; + + if (rh == retain_handling::send) { + std::forward(h)(); + } + } + } + + void unsubscribe(buffer const& share_name, buffer const& topic_filter) { + if (!share_name.empty()) { + shared_targets_.erase(share_name, topic_filter, *this); + } + std::lock_guard g{mtx_subs_map_}; + auto handle = subs_map_.lookup(topic_filter); + if (handle) { + handles_.erase(handle.value()); + subs_map_.erase(handle.value(), client_id_); + } + } + + void unsubscribe_all() { + { + std::lock_guard g{mtx_subs_map_}; + for (auto const& h : handles_) { + subs_map_.erase(h, client_id_); + } + } + handles_.clear(); + } + + void update_will( + as::io_context& timer_ioc, + optional will, + optional will_expiry_interval) { + tim_will_expiry_.reset(); + will_value_ = force_move(will); + + if (will_value_ && will_expiry_interval) { + tim_will_expiry_ = std::make_shared(timer_ioc, will_expiry_interval.value()); + tim_will_expiry_->async_wait( + [this, wp = std::weak_ptr(tim_will_expiry_)] + (error_code ec) { + if (auto sp = wp.lock()) { + if (!ec) { + clear_will(); + } + } + } + ); + } + } + + void clear_will() { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "clear will. cid:" << client_id_; + tim_will_expiry_.reset(); + will_value_ = nullopt; + } + + void send_will() { + if (!will_value_) return; + + auto wd_sec = + [&] () -> std::size_t { + if (auto wd_opt = get_property( + will_value_.value().props() + ) + ) { + return wd_opt.value().val(); + } + return 0; + } (); + + if (remain_after_close_ && wd_sec != 0) { + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "set will_delay. cid:" << client_id_ << " delay:" << wd_sec; + tim_will_delay_.expires_after(std::chrono::seconds(wd_sec)); + tim_will_delay_.async_wait( + [this] + (error_code ec) { + if (!ec) { + send_will_impl(); + } + } + ); + } + else { + send_will_impl(); + } + } + + void insert_inflight_message( + store_message_variant msg, + any life_keeper, + std::shared_ptr tim_message_expiry + ) { + std::lock_guard g(mtx_inflight_messages_); + inflight_messages_.insert( + force_move(msg), + force_move(life_keeper), + force_move(tim_message_expiry) + ); + } + + void send_inflight_messages() { + BOOST_ASSERT(con_); + std::lock_guard g(mtx_inflight_messages_); + inflight_messages_.send_all_messages(*con_); + } + + void erase_inflight_message_by_expiry(std::shared_ptr const& sp) { + std::lock_guard g(mtx_inflight_messages_); + inflight_messages_.get().erase(sp); + } + + void erase_inflight_message_by_packet_id(packet_id_t packet_id) { + std::lock_guard g(mtx_inflight_messages_); + auto& idx = inflight_messages_.get(); + idx.erase(packet_id); + } + + void send_all_offline_messages() { + BOOST_ASSERT(con_); + std::lock_guard g(mtx_offline_messages_); + offline_messages_.send_until_fail(*con_); + } + + void send_offline_messages_by_packet_id_release() { + BOOST_ASSERT(con_); + std::lock_guard g(mtx_offline_messages_); + offline_messages_.send_until_fail(*con_); + } + + protocol_version get_protocol_version() const { + return version_; + } + + buffer const& client_id() const { + return client_id_; + } + + void set_username(std::string const& username) { + username_ = username; + } + std::string const& get_username() const { + return username_; + } + + void renew(con_sp_t con, bool clean_start) { + tim_will_delay_.cancel(); + if (clean_start) { + // send previous will + send_will_impl(); + qos2_publish_handled_.clear(); + } + else { + // cancel will + clear_will(); + con->restore_qos2_publish_handled_pids(qos2_publish_handled_); + } + con_ = force_move(con); + } + + con_sp_t const& con() const { + return con_; + } + + optional session_expiry_interval() const { + return session_expiry_interval_; + } + + void set_response_topic(std::string topic) { + response_topic_.emplace(force_move(topic)); + } + + optional get_response_topic() const { + return response_topic_; + } + +private: + void send_will_impl() { + if (!will_value_) return; + + MQTT_LOG("mqtt_broker", trace) + << MQTT_ADD_VALUE(address, this) + << "send will. cid:" << client_id_; + + auto topic = force_move(will_value_.value().topic()); + auto payload = force_move(will_value_.value().message()); + auto opts = will_value_.value().get_qos() | will_value_.value().get_retain(); + auto props = force_move(will_value_.value().props()); + will_value_ = nullopt; + if (tim_will_expiry_) { + auto d = + std::chrono::duration_cast( + tim_will_expiry_->expiry() - std::chrono::steady_clock::now() + ).count(); + if (d < 0) d = 0; + set_property( + props, + v5::property::message_expiry_interval( + static_cast(d) + ) + ); + } + if (will_sender_) { + will_sender_( + *this, + force_move(topic), + force_move(payload), + opts, + force_move(props) + ); + } + } + +private: + friend class session_states; + + as::io_context& timer_ioc_; + std::shared_ptr tim_will_expiry_; + optional will_value_; + + mutex& mtx_subs_map_; + sub_con_map& subs_map_; + shared_target& shared_targets_; + con_sp_t con_; + protocol_version version_; + buffer client_id_; + + std::string username_; + + optional session_expiry_interval_; + std::shared_ptr tim_session_expiry_; + + mutable mutex mtx_inflight_messages_; + inflight_messages inflight_messages_; + + mutable mutex mtx_offline_messages_; + offline_messages offline_messages_; + + std::set handles_; // to efficient remove + + as::steady_timer tim_will_delay_; + will_sender_t will_sender_; + bool remain_after_close_; + + std::set qos2_publish_handled_; + + optional response_topic_; + std::function clean_handler_; +}; + +class session_states { +public: + template + decltype(auto) get() { + return entries_.get(); + } + + template + decltype(auto) get() const { + return entries_.get(); + } + + void clear() { + entries_.clear(); + } + +private: + // The mi_session_online container holds the relevant data about an active connection with the broker. + // It can be queried either with the clientid, or with the shared pointer to the mqtt endpoint object + using mi_session_state = mi::multi_index_container< + session_state, + mi::indexed_by< + // non is nullable + mi::ordered_non_unique< + mi::tag, + BOOST_MULTI_INDEX_MEMBER(session_state, con_sp_t, con_) + >, + mi::ordered_unique< + mi::tag, + mi::composite_key< + session_state, + BOOST_MULTI_INDEX_MEMBER(session_state, std::string, username_), + BOOST_MULTI_INDEX_MEMBER(session_state, buffer, client_id_) + > + >, + mi::ordered_non_unique< + mi::tag, + BOOST_MULTI_INDEX_MEMBER(session_state, std::shared_ptr, tim_session_expiry_) + > + > + >; + + mi_session_state entries_; +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SESSION_STATE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/session_state_fwd.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/session_state_fwd.hpp new file mode 100644 index 000000000..96cf38f2c --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/session_state_fwd.hpp @@ -0,0 +1,24 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SESSION_STATE_FWD_HPP) +#define MQTT_BROKER_SESSION_STATE_FWD_HPP + +#include + +#include // reference_wrapper + +#include + +MQTT_BROKER_NS_BEGIN + +struct session_state; + +using session_state_ref = std::reference_wrapper; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SESSION_STATE_FWD_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/shared_target.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/shared_target.hpp new file mode 100644 index 000000000..f17daf3b8 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/shared_target.hpp @@ -0,0 +1,79 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SHARED_TARGET_HPP) +#define MQTT_BROKER_SHARED_TARGET_HPP + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +namespace mi = boost::multi_index; + +class shared_target { +public: + void insert(buffer share_name, buffer topic_filter, session_state& ss); + void erase(buffer share_name, buffer topic_filter, session_state const& ss); + void erase(session_state const& ss); + optional get_target(buffer const& share_name, buffer const& topic_filter); + +private: + struct entry { + entry(buffer share_name, session_state& ss, time_point_t tp); + + buffer const& client_id() const; + buffer share_name; + session_state_ref ssr; + time_point_t tp; + std::set topic_filters; + }; + + using mi_shared_target = mi::multi_index_container< + entry, + mi::indexed_by< + mi::ordered_unique< + mi::tag, + mi::composite_key< + entry, + BOOST_MULTI_INDEX_CONST_MEM_FUN(entry, buffer const&, client_id), + BOOST_MULTI_INDEX_MEMBER(entry, buffer, share_name) + > + >, + mi::ordered_non_unique< + mi::tag, + mi::composite_key< + entry, + BOOST_MULTI_INDEX_MEMBER(entry, buffer, share_name), + BOOST_MULTI_INDEX_MEMBER(entry, time_point_t, tp) + > + > + > + >; + + mutable mutex mtx_targets_; + mi_shared_target targets_; +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SHARED_TARGET_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/shared_target_impl.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/shared_target_impl.hpp new file mode 100644 index 000000000..c97f13689 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/shared_target_impl.hpp @@ -0,0 +1,105 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SHARED_TARGET_IMPL_HPP) +#define MQTT_BROKER_SHARED_TARGET_IMPL_HPP + +#include +#include + +MQTT_BROKER_NS_BEGIN + +inline void shared_target::insert(buffer share_name, buffer topic_filter, session_state& ss) { + std::lock_guard g{mtx_targets_}; + auto& idx = targets_.get(); + auto it = idx.lower_bound(std::make_tuple(ss.client_id(), share_name)); + if (it == idx.end() || (it->share_name != share_name || it->client_id() != ss.client_id())) { + it = idx.emplace_hint(it, force_move(share_name), ss, std::chrono::steady_clock::now()); + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& st = const_cast(*it); + bool inserted; + std::tie(std::ignore, inserted) = st.topic_filters.insert(force_move(topic_filter)); + BOOST_ASSERT(inserted); + } + else { + // entry exists + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& st = const_cast(*it); + st.topic_filters.insert(force_move(topic_filter)); // ignore overwrite + } +} + +inline void shared_target::erase(buffer share_name, buffer topic_filter, session_state const& ss) { + std::lock_guard g{mtx_targets_}; + auto& idx = targets_.get(); + auto it = idx.find(std::make_tuple(ss.client_id(), share_name)); + if (it == idx.end()) { + MQTT_LOG("mqtt_broker", warning) + << "attempt to erase non exist entry" + << " share_name:" << share_name + << " topic_filtere:" << topic_filter + << " client_id:" << ss.client_id(); + return; + } + + // entry exists + + // const_cast is appropriate here + // See https://github.com/boostorg/multi_index/issues/50 + auto& st = const_cast(*it); + st.topic_filters.erase(topic_filter); + if (it->topic_filters.empty()) { + idx.erase(it); + } +} + +inline void shared_target::erase(session_state const& ss) { + std::lock_guard g{mtx_targets_}; + auto& idx = targets_.get(); + auto r = idx.equal_range(ss.client_id()); + idx.erase(r.first, r.second); +} + +inline optional shared_target::get_target(buffer const& share_name, buffer const& topic_filter) { + std::lock_guard g{mtx_targets_}; + // get share_name matched range ordered by timestamp (ascending) + auto& idx = targets_.get(); + auto r = idx.equal_range(share_name); + for (; r.first != r.second; ++r.first) { + auto const& elem = *r.first; + auto it = elem.topic_filters.find(topic_filter); + + // no share_name/topic_filter matched + if (it == elem.topic_filters.end()) continue; + + // matched + // update timestamp (timestamp is key) + idx.modify(r.first, [](auto& e) { e.tp = std::chrono::steady_clock::now(); }); + return elem.ssr; + } + return nullopt; +} + +inline shared_target::entry::entry( + buffer share_name, + session_state& ss, + time_point_t tp) + : share_name { force_move(share_name) }, + ssr { ss }, + tp { force_move(tp) } +{} + +inline buffer const& shared_target::entry::client_id() const { + return ssr.get().client_id(); +} + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SHARED_TARGET_IMPL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/sub_con_map.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/sub_con_map.hpp new file mode 100644 index 000000000..ba6c85063 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/sub_con_map.hpp @@ -0,0 +1,30 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SUB_CON_MAP_HPP) +#define MQTT_BROKER_SUB_CON_MAP_HPP + +#include + +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +struct buffer_hasher { + std::size_t operator()(buffer const& b) const noexcept { + std::size_t result = 0; + boost::hash_combine(result, b); + return result; + } +}; + +using sub_con_map = multiple_subscription_map; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SUB_CON_MAP_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/subscription.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/subscription.hpp new file mode 100644 index 000000000..7b7bc6c15 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/subscription.hpp @@ -0,0 +1,47 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SUBSCRIPTION_HPP) +#define MQTT_BROKER_SUBSCRIPTION_HPP + +#include + +#include +#include +#include +#include +#include + +MQTT_BROKER_NS_BEGIN + +struct subscription { + subscription( + session_state_ref ss, + buffer share_name, + buffer topic_filter, + subscribe_options subopts, + optional sid) + :ss { ss }, + share_name { force_move(share_name) }, + topic_filter { force_move(topic_filter) }, + subopts { subopts }, + sid { sid } + {} + + session_state_ref ss; + buffer share_name; + buffer topic_filter; + subscribe_options subopts; + optional sid; +}; + +inline bool operator<(subscription const& lhs, subscription const& rhs) { + return &lhs.ss.get() < &rhs.ss.get(); +} + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SUBSCRIPTION_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/subscription_map.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/subscription_map.hpp new file mode 100644 index 000000000..464681f72 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/subscription_map.hpp @@ -0,0 +1,742 @@ +// Copyright Wouter van Kleunen 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_SUBSCRIPTION_MAP_HPP) +#define MQTT_BROKER_SUBSCRIPTION_MAP_HPP + +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +MQTT_BROKER_NS_BEGIN + +/** + * + * In MQTT we have: + * Clients subscribed with certain topic filters, topic filters are path with may contain wildcards such as + * + and # + * . A subscription to "#" will not receive any messages published to a topic beginning with a $ + * · A subscription to "+/monitor/Clients" will not receive any messages published to "$SYS/monitor/Clients" + * · A subscription to "$SYS/#" will receive messages published to topics beginning with "$SYS/" + * · A subscription to "$SYS/monitor/Clients/+" will receive messages published to "$SYS/monitor/Clients/" + * · For a Client to receive messages from topics that begin with $SYS/ and from topics that don’t begin with a $, it has to subscribe to both “#” and “$SYS/#” + * Check whether a string is a valid subscription using 'mqtt_valid_subscription' + * + * Topics being published, a topic is a sort of path and does not contain wildcards + * · $SYS/ has been widely adopted as a prefix to topics that contain Server-specific information or control APIs + * · Applications cannot use a topic with a leading $ character for their own purposes + * Check whether a string is a valid topic using 'mqtt_valid_topic' + * + * + * We introduce two data structures: + * . A subscription map, storing a topic_filter -> data + * Using a published topic, we can find all topic filters which match the specified topic + * . A stored topic map, storing topic -> data + * Using a new topic filter, we can find all stored topics which match the specified topic filter + * + * Subscription map stores all entries in a tree + * the tree starts from a root node, and topic filters are tokenized and stored in the tree + * + * For example if the topic_filter example/monitor/Clients is stored, the following nodes are created: + * root -> example -> monitor -> Clients + * + * Every node in the tree may store one or multiple subscribers. Nodes store a reference count to the number of subscribers + * so for example, if we store the following topic_filters: + * example/ + * example/monitor/Clients + * + * the subscription map looks as follows: + * root(2) -> example(2) -> monitor(1) -> Clients (1) + * + * hash and + are stored as normal nodes within the tree, but the parent node knows if a hash child is available. This + * improves the matching, no extra lookup is required to see if a # or + child is available in a child node: + * + * example/# + * + * stores the following tree: + * root -> example (hash: yes) -> # + * + * and + * + * example/+ + * + * stores the following tree: + * root -> example (plus: yes) -> # + * + * all node entries are stored in a single hash map. The key for every node is: (parent node id, path) + * + * so if we store: root/example/test + * root (id:1) -> example (id:2, key:1,example) -> test (id:3, key:2,test) + * + * also, every node stores the key of its parent, allowing quick traversing from leaf to root of the tree + */ + +// Combined storage for count and flags +// we can have 32bit or 64bit version + +// Compile error on other platforms (not 32 or 64 bit) +template +struct count_storage { + static_assert(N == 4 || N == 8, "Subscription map count_storage only knows how to handle architectures with 32 or 64 bit size_t: please update to support your platform."); +}; + +template<> +struct count_storage<4> { +public: + count_storage(std::uint32_t v = 1) + : value_(v & 0x3fffffffUL), has_hash_child_(false), has_plus_child_(false) + { } + + static constexpr std::size_t max() { return std::numeric_limits::max() >> 2; } + + std::uint32_t value() const { return value_; } + void set_value(std::uint32_t v) { + value_ = v & 0x3fffffffUL; + } + void increment_value() { + ++value_; + } + void decrement_value() { + --value_; + } + + bool has_hash_child() const { return has_hash_child_; } + void set_hash_child(bool v) { + has_hash_child_ = v; + } + + bool has_plus_child() const { return has_plus_child_; } + void set_plus_child(bool v) { + has_plus_child_ = v; + } + +private: + std::uint32_t value_ : 30; + std::uint32_t has_hash_child_ : 1; + std::uint32_t has_plus_child_ : 1; + +}; + +template<> +struct count_storage<8> { +public: + count_storage(std::uint64_t v= 1) + : value_(v & 0x3fffffffffffffffULL), has_hash_child_(false), has_plus_child_(false) + { } + + static constexpr std::uint64_t max() { return std::numeric_limits::max() >> 2; } + + std::uint64_t value() const { return value_; } + void set_value(std::uint64_t v) { + value_ = v & 0x3fffffffffffffffULL; + } + void increment_value() { + ++value_; + } + void decrement_value() { + --value_; + } + + bool has_hash_child() const { return has_hash_child_; } + void set_hash_child(bool v) { + has_hash_child_ = v; + } + + bool has_plus_child() const { return has_plus_child_; } + void set_plus_child(bool v) { + has_plus_child_ = v; + } + + +private: + std::uint64_t value_ : 62; + std::uint64_t has_hash_child_ : 1; + std::uint64_t has_plus_child_ : 1; +}; + +template +class subscription_map_base { +public: + using node_id_t = std::size_t; + using path_entry_key = std::pair; + using handle = path_entry_key; + +private: + + // Generate a node id for a new node + node_id_t generate_node_id() { + if(next_node_id == std::numeric_limits::max()) + throw_max_stored_topics(); + return ++next_node_id; + } + + using count_storage_t = count_storage; + + struct path_entry { + node_id_t id; + path_entry_key parent; + + count_storage_t count; + + Value value; + + path_entry(node_id_t id, path_entry_key parent) + : id(id), parent(parent) + {} + }; + + // Increase the subscription count for a specific node + static void increase_count_storage(count_storage_t &count) { + if(count.value() == count_storage_t::max()) { + throw_max_stored_topics(); + } + + count.increment_value(); + } + + // Decrease the subscription count for a specific node + static void decrease_count_storage(count_storage_t& count) { + BOOST_ASSERT(count.value() > 0); + count.decrement_value(); + } + + using this_type = subscription_map_base; + + // Use boost hash to hash pair in path_entry_key + using map_type = std::unordered_map< path_entry_key, path_entry, boost::hash< path_entry_key > >; + + map_type map; + using map_type_iterator = typename map_type::iterator; + using map_type_const_iterator = typename map_type::const_iterator; + + node_id_t next_node_id = 0; + +protected: + // Key and id of the root key + path_entry_key root_key; + node_id_t root_node_id; + + // Return the iterator of the root + map_type_iterator get_root() { return map.find(root_key); }; + map_type_const_iterator get_root() const { return map.find(root_key); }; + + + // Map size tracks the total number of subscriptions within the map + size_t map_size = 0; + + map_type_iterator get_key(path_entry_key key) { return map.find(key); } + map_type_iterator begin() { return map.begin(); } + map_type_iterator end() { return map.end(); } + map_type const& get_map() const { return map; } + + handle path_to_handle(std::vector< map_type_iterator > const& path) const { + return path.back()->first; + } + + std::vector< map_type_iterator> find_topic_filter(string_view topic_filter) { + auto parent_id = get_root()->second.id; + std::vector< map_type_iterator > path; + + topic_filter_tokenizer( + topic_filter, + [this, &path, &parent_id](string_view t) mutable { + auto entry = map.find(path_entry_key(parent_id, t)); + + if (entry == map.end()) { + path.clear(); + return false; + } + + path.push_back(entry); + parent_id = entry->second.id; + return true; + } + ); + + return path; + } + + std::vector create_topic_filter(string_view topic_filter) { + auto parent = get_root(); + + std::vector result; + + topic_filter_tokenizer( + topic_filter, + [this, &parent, &result](string_view t) mutable { + auto entry = map.find(path_entry_key(parent->second.id, t)); + + if (entry == map.end()) { + entry = + map.emplace( + path_entry_key( + parent->second.id, + allocate_buffer(t) + ), + path_entry(generate_node_id(), parent->first) + ).first; + + parent->second.count.set_plus_child(parent->second.count.has_plus_child() | (t == "+")); + parent->second.count.set_hash_child(parent->second.count.has_hash_child() | (t == "#")); + } + else { + increase_count_storage(entry->second.count); + } + + result.push_back(entry); + parent = entry; + return true; + } + ); + + return result; + } + + // Remove a value at the specified path + void remove_topic_filter(std::vector< map_type_iterator > const& path) { + bool remove_plus_child_flag = false; + bool remove_hash_child_flag = false; + + // Go through entries to remove + for (auto& entry : boost::adaptors::reverse(path)) { + if (remove_plus_child_flag) { + entry->second.count.set_plus_child(false); + remove_plus_child_flag = false; + } + + if (remove_hash_child_flag) { + entry->second.count.set_hash_child(false); + remove_hash_child_flag = false; + } + + decrease_count_storage(entry->second.count); + if (entry->second.count.value() == 0) { + remove_plus_child_flag = (entry->first.second == "+"); + remove_hash_child_flag = (entry->first.second == "#"); + + // Erase in unordered map only invalidates erased iterator + // other iterators are unaffected + map.erase(entry->first); + } + } + + auto root = get_root(); + if (remove_plus_child_flag) { + root->second.count.set_plus_child(false); + } + + if (remove_hash_child_flag) { + root->second.count.set_hash_child(false); + } + } + + template + static void find_match_impl(ThisType& self, string_view topic, Output&& callback) { + using iterator_type = decltype(self.map.end()); // const_iterator or iterator depends on self + + std::vector entries; + entries.push_back(self.get_root()); + + topic_filter_tokenizer( + topic, + [&self, &entries, &callback](string_view t) { + std::vector new_entries; + + for (auto& entry : entries) { + auto parent = entry->second.id; + auto i = self.map.find(path_entry_key(parent, t)); + if (i != self.map.end()) { + new_entries.push_back(i); + } + + if (entry->second.count .has_plus_child()) { + i = self.map.find(path_entry_key(parent, string_view("+"))); + if (i != self.map.end()) { + if (parent != self.root_node_id || t.empty() || t[0] != '$') { + new_entries.push_back(i); + } + } + } + + if (entry->second.count.has_hash_child()) { + i = self.map.find(path_entry_key(parent, string_view("#"))); + if (i != self.map.end()) { + if (parent != self.root_node_id || t.empty() || t[0] != '$'){ + callback(i->second.value); + } + } + } + } + + std::swap(entries, new_entries); + return !entries.empty(); + } + ); + + for (auto& entry : entries) { + callback(entry->second.value); + } + } + + // Find all topic filters that match the specified topic + template + void find_match(string_view topic, Output&& callback) const { + find_match_impl(*this, topic, std::forward(callback)); + } + + // Find all topic filters and allow modification + template + void modify_match(string_view topic, Output&& callback) { + find_match_impl(*this, topic, std::forward(callback)); + } + + template + static void handle_to_iterators(ThisType& self, handle const &h, Output&& output) { + auto i = h; + while(i != self.root_key) { + auto entry_iter = self.map.find(i); + if (entry_iter == self.map.end()) { + throw_invalid_handle(); + } + + output(entry_iter); + i = entry_iter->second.parent; + } + } + + // Exceptions used + static void throw_invalid_topic_filter() { throw std::runtime_error("Subscription map invalid topic filter was specified"); } + static void throw_invalid_handle() { throw std::runtime_error("Subscription map invalid handle was specified"); } + static void throw_max_stored_topics() { throw std::overflow_error("Subscription map maximum number of stored topic filters reached"); } + + // Get the iterators of a handle + std::vector handle_to_iterators(handle const &h) { + std::vector result; + handle_to_iterators(*this, h, [&result](map_type_iterator i) { result.push_back(i); }); + std::reverse(result.begin(), result.end()); + return result; + } + + // Increase the number of subscriptions for this handle + void increase_subscriptions(handle const &h) { + handle_to_iterators(*this, h, [](map_type_iterator i) { + increase_count_storage(i->second.count); + }); + } + + // Increase the map size (total number of subscriptions stored) + void increase_map_size() { + if(map_size == std::numeric_limits::max()) { + throw_max_stored_topics(); + } + + ++map_size; + } + + // Decrease the map size (total number of subscriptions stored) + void decrease_map_size() { + BOOST_ASSERT(map_size > 0); + --map_size; + } + + // Increase the number of subscriptions for this path + void increase_subscriptions(std::vector const &path) { + for (auto i : path) { + increase_count_storage(i->second.count); + } + } + + subscription_map_base() + { + // Create the root node + root_node_id = generate_node_id(); + root_key = path_entry_key(generate_node_id(), buffer()); + map.emplace(root_key, path_entry(root_node_id, path_entry_key())); + } + +public: + // Return the number of elements in the tree + std::size_t internal_size() const { return map.size(); } + + // Return the number of registered topic filters + std::size_t size() const { return this->map_size; } + + // Lookup a topic filter + optional lookup(string_view topic_filter) { + auto path = this->find_topic_filter(topic_filter); + if(path.empty()) + return optional(); + else + return this->path_to_handle(force_move(path)); + } + + // Get path of topic_filter + std::string handle_to_topic_filter(handle const &h) const { + std::string result; + + handle_to_iterators(*this, h, [&result](map_type_const_iterator i) { + if (result.empty()) { + result = std::string(i->first.second); + } + else { + result = std::string(i->first.second) + "/" + result; + } + }); + + return result; + } +}; + +template +class single_subscription_map + : public subscription_map_base< optional > { + +public: + + // Handle of an entry + using handle = typename subscription_map_base< Value >::handle; + + // Insert a value at the specified topic_filter + template + std::pair insert(string_view topic_filter, V&& value) { + auto existing_subscription = this->find_topic_filter(topic_filter); + if (!existing_subscription.empty()) { + if(existing_subscription.back()->second.value) + return std::make_pair(this->path_to_handle(force_move(existing_subscription)), false); + + existing_subscription.back()->second.value.emplace(std::forward(value)); + return std::make_pair(this->path_to_handle(force_move(existing_subscription)), true); + } + + auto new_topic_filter = this->create_topic_filter(topic_filter); + new_topic_filter.back()->second.value = value; + this->increase_map_size(); + return std::make_pair(this->path_to_handle(force_move(new_topic_filter)), true); + } + + // Update a value at the specified topic filter + template + void update(string_view topic_filter, V&& value) { + auto path = this->find_topic_filter(topic_filter); + if (path.empty()) { + this->throw_invalid_topic_filter(); + } + + path.back()->second.value.emplace(std::forward(value)); + } + + template + void update(handle const &h, V&& value) { + auto entry_iter = this->get_key(h); + if (entry_iter == this->end()) { + this->throw_invalid_topic_filter(); + } + entry_iter->second.value.emplace(std::forward(value)); + } + + // Remove a value at the specified topic filter + std::size_t erase(string_view topic_filter) { + auto path = this->find_topic_filter(topic_filter); + if (path.empty() || !path.back()->second.value) { + return 0; + } + + this->remove_topic_filter(path); + this->decrease_map_size(); + return 1; + } + + // Remove a value using a handle + std::size_t erase(handle const &h) { + auto path = this->handle_to_iterators(h); + if (path.empty() || !path.back()->second.value) { + return 0; + } + + this->remove_topic_filter(path); + this->decrease_map_size(); + return 1; + } + + // Find all topic filters that match the specified topic + template + void find(string_view topic, Output&& callback) const { + this->find_match( + topic, + [&callback]( optional const& value ) { + if (value) { + callback(value.value()); + } + } + ); + } + +}; + +template, class Pred = std::equal_to, class Cont = std::unordered_map > > > +class multiple_subscription_map + : public subscription_map_base< Cont > +{ + +public: + using container_t = Cont; + + // Handle of an entry + using handle = typename subscription_map_base< Value >::handle; + + // Insert a key => value at the specified topic filter + // returns the handle and true if key was inserted, false if key was updated + template + std::pair insert_or_assign(string_view topic_filter, K&& key, V&& value) { + auto path = this->find_topic_filter(topic_filter); + if (path.empty()) { + auto new_topic_filter = this->create_topic_filter(topic_filter); + new_topic_filter.back()->second.value.emplace(std::forward(key), std::forward(value)); + this->increase_map_size(); + return std::make_pair(this->path_to_handle(force_move(new_topic_filter)), true); + } + else { + auto& subscription_set = path.back()->second.value; + +#if __cpp_lib_unordered_map_try_emplace >= 201411L + auto insert_result = subscription_set.insert_or_assign(std::forward(key), std::forward(value)); + if(insert_result.second) { + this->increase_subscriptions(path); + this->increase_map_size(); + } + return std::make_pair(this->path_to_handle(force_move(path)), insert_result.second); +#else + auto iter = subscription_set.find(key); + if(iter == subscription_set.end()) { + subscription_set.emplace(std::forward(key), std::forward(value)); + this->increase_subscriptions(path); + this->increase_map_size(); + } else { + iter->second = std::forward(value); + } + return std::make_pair(this->path_to_handle(force_move(path)), iter == subscription_set.end()); + +#endif + } + } + + // Insert a key => value with a handle to the topic filter + // returns the handle and true if key was inserted, false if key was updated + template + std::pair insert_or_assign(handle const &h, K&& key, V&& value) { + auto h_iter = this->get_key(h); + if (h_iter == this->end()) { + this->throw_invalid_handle(); + } + + auto& subscription_set = h_iter->second.value; + +#if __cpp_lib_unordered_map_try_emplace >= 201411L + auto insert_result = subscription_set.insert_or_assign(std::forward(key), std::forward(value)); + if(insert_result.second) { + this->increase_subscriptions(h); + this->increase_map_size(); + } + return std::make_pair(h, insert_result.second); +#else + auto iter = subscription_set.find(key); + if(iter == subscription_set.end()) { + subscription_set.emplace(std::forward(key), std::forward(value)); + this->increase_subscriptions(h); + this->increase_map_size(); + } else { + iter->second = std::forward(value); + } + return std::make_pair(h, iter == subscription_set.end()); +#endif + } + + // Remove a value at the specified handle + // returns the number of removed elements + std::size_t erase(handle const &h, Key const& key) { + // Find the handle in the map + auto h_iter = this->get_key(h); + if (h_iter == this->end()) { + this->throw_invalid_handle(); + } + + // Remove the specified value + auto result = h_iter->second.value.erase(key); + if (result) { + this->remove_topic_filter(this->handle_to_iterators(h)); + this->decrease_map_size(); + } + + return result; + } + + // Remove a value at the specified topic filter + // returns the number of removed elements + std::size_t erase(string_view topic_filter, Key const& key) { + // Find the topic filter in the map + auto path = this->find_topic_filter(topic_filter); + if (path.empty()) { + return 0; + } + + // Remove the specified value + auto result = path.back()->second.value.erase(key); + if (result) { + this->decrease_map_size(); + this->remove_topic_filter(path); + } + + return result; + } + + // Find all topic filters that match the specified topic + template + void find(string_view topic, Output&& callback) const { + this->find_match( + topic, + [&callback]( Cont const &values ) { + for (auto const& i : values) { + callback(i.first, i.second); + } + } + ); + } + + // Find all topic filters that match and allow modification + template + void modify(string_view topic, Output&& callback) { + this->modify_match( + topic, + [&callback]( Cont &values ) { + for (auto& i : values) { + callback(i.first, i.second); + } + } + ); + } + + template + void dump(Output &out) { + out << "Root node id: " << this->root_node_id << std::endl; + for (auto const& i: this->get_map()) { + out << "(" << i.first.first << ", " << i.first.second << "): id: " << i.second.id << ", size: " << i.second.value.size() << ", value: " << i.second.count.value << std::endl; + } + } + +}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_SUBSCRIPTION_MAP_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/tags.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/tags.hpp new file mode 100644 index 000000000..7957166a2 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/tags.hpp @@ -0,0 +1,30 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_TAGS_HPP) +#define MQTT_BROKER_TAGS_HPP + +#include + +#include + +MQTT_BROKER_NS_BEGIN + +struct tag_seq {}; +struct tag_con {}; +struct tag_topic{}; +struct tag_topic_filter{}; +struct tag_con_topic_filter {}; +struct tag_cid {}; +struct tag_cid_topic_filter {}; +struct tag_tim {}; +struct tag_pid {}; +struct tag_sn_tp {}; +struct tag_cid_sn {}; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_TAGS_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/time_point_t.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/time_point_t.hpp new file mode 100644 index 000000000..393b7b39a --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/time_point_t.hpp @@ -0,0 +1,22 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_TIME_POINT_T_HPP) +#define MQTT_BROKER_TIME_POINT_T_HPP + +#include + +#include + +#include + +MQTT_BROKER_NS_BEGIN + +using time_point_t = std::chrono::time_point; + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_TIME_POINT_T_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/topic_filter.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/topic_filter.hpp new file mode 100644 index 000000000..055f0b80c --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/topic_filter.hpp @@ -0,0 +1,279 @@ +// Copyright wkl04 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_TOPIC_FILTER_HPP) +#define MQTT_BROKER_TOPIC_FILTER_HPP + +#include + +#include +#include + +#include + +MQTT_BROKER_NS_BEGIN + +static constexpr char topic_filter_separator = '/'; + +template +inline Iterator topic_filter_tokenizer_next(Iterator first, Iterator last) { + return std::find(first, last, topic_filter_separator); +} + +template +inline std::size_t topic_filter_tokenizer(Iterator first, Iterator last, Output write) { + std::size_t count = 1; + auto pos = topic_filter_tokenizer_next(first, last); + while (write(first, pos) && pos != last) { + first = std::next(pos); + pos = topic_filter_tokenizer_next(first, last); + ++count; + } + return count; +} + + +template +inline std::size_t topic_filter_tokenizer(string_view str, Output write) { + return topic_filter_tokenizer( + std::begin(str), + std::end(str), + [&write](string_view::const_iterator token_begin, string_view::const_iterator token_end) { + return write( + make_string_view( + token_begin, + token_end + ) + ); + } + ); +} + +#if defined(MQTT_STD_STRING_VIEW) +#define MQTT_STRING_VIEW_CONSTEXPR constexpr +#else // defined(MQTT_STD_STRING_VIEW) +#define MQTT_STRING_VIEW_CONSTEXPR +#endif // defined(MQTT_STD_STRING_VIEW) + + +// TODO: Technically this function is simply wrong, since it's treating the +// topic pattern as if it were an ASCII sequence. +// To make this function correct per the standard, it would be necessary +// to conduct the search for the wildcard characters using a proper +// UTF-8 API to avoid problems of interpreting parts of multi-byte characters +// as if they were individual ASCII characters +MQTT_STRING_VIEW_CONSTEXPR +inline bool validate_topic_filter(string_view topic_filter) { + /* + * Confirm the topic pattern is valid before registering it. + * Use rules from http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106 + */ + + // All Topic Names and Topic Filters MUST be at least one character long + // Topic Names and Topic Filters are UTF-8 Encoded Strings; they MUST NOT encode to more than 65,535 bytes + if (topic_filter.empty() || (topic_filter.size() > std::numeric_limits::max())) { + return false; + } + + for (string_view::size_type idx = topic_filter.find_first_of(string_view("\0+#", 3)); + string_view::npos != idx; + idx = topic_filter.find_first_of(string_view("\0+#", 3), idx+1)) { + BOOST_ASSERT( + ('\0' == topic_filter[idx]) + || ('+' == topic_filter[idx]) + || ('#' == topic_filter[idx]) + ); + if ('\0' == topic_filter[idx]) { + // Topic Names and Topic Filters MUST NOT include the null character (Unicode U+0000) + return false; + } + else if ('+' == topic_filter[idx]) { + /* + * Either must be the first character, + * or be preceeded by a topic seperator. + */ + if ((0 != idx) && ('/' != topic_filter[idx-1])) { + return false; + } + + /* + * Either must be the last character, + * or be followed by a topic seperator. + */ + if ((topic_filter.size()-1 != idx) && ('/' != topic_filter[idx+1])) { + return false; + } + } + // multilevel wildcard + else if ('#' == topic_filter[idx]) { + /* + * Must be absolute last character. + * Must only be one multi level wild card. + */ + if (idx != topic_filter.size()-1) { + return false; + } + + /* + * If not the first character, then the + * immediately preceeding character must + * be a topic level separator. + */ + if ((0 != idx) && ('/' != topic_filter[idx-1])) { + return false; + } + } + else { + return false; + } + } + return true; +} + +#if defined(MQTT_STD_STRING_VIEW) +// The following rules come from https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901247 +static_assert( ! validate_topic_filter(""), "All Topic Names and Topic Filters MUST be at least one character long"); +static_assert(validate_topic_filter("/"), "A Topic Name or Topic Filter consisting only of the ‘/’ character is valid"); +static_assert( ! validate_topic_filter(string_view("\0", 1)), "Topic Names and Topic Filters MUST NOT include the null character (Unicode U+0000)"); +static_assert(validate_topic_filter(" "), "Topic Names and Topic Filters can include the space character"); +static_assert(validate_topic_filter("/////"), "Topic level separators can appear anywhere in a Topic Filter or Topic Name. Adjacent Topic level separators indicate a zero-length topic level"); +static_assert(validate_topic_filter("#"), "The multi-level wildcard character MUST be specified either on its own or following a topic level separator"); +static_assert(validate_topic_filter("/#"), "The multi-level wildcard character MUST be specified either on its own or following a topic level separator"); +static_assert(validate_topic_filter("+/#"), "The multi-level wildcard character MUST be specified either on its own or following a topic level separator"); +static_assert( ! validate_topic_filter("+#"), "The multi-level wildcard character MUST be specified either on its own or following a topic level separator"); +static_assert( ! validate_topic_filter("++"), "The multi-level wildcard character MUST be specified either on its own or following a topic level separator"); +static_assert( ! validate_topic_filter("f#"), "The multi-level wildcard character MUST be specified either on its own or following a topic level separator"); +static_assert( ! validate_topic_filter("#/"), "In either case the multi-level wildcard character MUST be the last character specified in the Topic Filter"); + +static_assert(validate_topic_filter("+"), "The single-level wildcard can be used at any level in the Topic Filter, including first and last levels"); +static_assert(validate_topic_filter("+/bob/alice/sue"), "The single-level wildcard can be used at any level in the Topic Filter, including first and last levels"); +static_assert(validate_topic_filter("bob/alice/sue/+"), "The single-level wildcard can be used at any level in the Topic Filter, including first and last levels"); +static_assert(validate_topic_filter("+/bob/alice/sue/+"), "The single-level wildcard can be used at any level in the Topic Filter, including first and last levels"); +static_assert(validate_topic_filter("+/bob/+/sue/+"), "The single-level wildcard can be used at any level in the Topic Filter, including first and last levels"); +static_assert(validate_topic_filter("+/bob/+/sue/#"), "The single-level wildcard can be used at more than one level in the Topic Filter and can be used in conjunction with the multi-level wildcard"); +static_assert( ! validate_topic_filter("+a"), "Where it is used, the single-level wildcard MUST occupy an entire level of the filter."); +static_assert( ! validate_topic_filter("a+"), "Where it is used, the single-level wildcard MUST occupy an entire level of the filter."); +static_assert( ! validate_topic_filter("/a+"), "Where it is used, the single-level wildcard MUST occupy an entire level of the filter."); +static_assert( ! validate_topic_filter("a+/"), "Where it is used, the single-level wildcard MUST occupy an entire level of the filter."); +static_assert( ! validate_topic_filter("/a+/"), "Where it is used, the single-level wildcard MUST occupy an entire level of the filter."); +#endif // defined(MQTT_STD_STRING_VIEW) + +MQTT_STRING_VIEW_CONSTEXPR +inline bool validate_topic_name(string_view topic_name) { + /* + * Confirm the topic name is valid + * Use rules from https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901247 + */ + + // All Topic Names and Topic Filters MUST be at least one character long + // Topic Names and Topic Filters are UTF-8 Encoded Strings; they MUST NOT encode to more than 65,535 bytes + // The wildcard characters can be used in Topic Filters, but MUST NOT be used within a Topic Name + // Topic Names and Topic Filters MUST NOT include the null character (Unicode U+0000) + return + ! topic_name.empty() + && (topic_name.size() <= std::numeric_limits::max()) + && (string_view::npos == topic_name.find_first_of(string_view("\0+#", 3))); +} + +#if defined(MQTT_STD_STRING_VIEW) +// The following rules come from https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901247 +static_assert( ! validate_topic_name(""), "All Topic Names and Topic Filters MUST be at least one character long"); +static_assert(validate_topic_name("/"), "A Topic Name or Topic Filter consisting only of the ‘/’ character is valid"); +static_assert( ! validate_topic_name(string_view("\0", 1)), "Topic Names and Topic Filters MUST NOT include the null character (Unicode U+0000)"); +static_assert(validate_topic_name(" "), "Topic Names and Topic Filters can include the space character"); +static_assert(validate_topic_name("/////"), "Topic level separators can appear anywhere in a Topic Filter or Topic Name. Adjacent Topic level separators indicate a zero-length topic level"); +static_assert( ! validate_topic_name("#"), "The wildcard characters can be used in Topic Filters, but MUST NOT be used within a Topic Name"); +static_assert( ! validate_topic_name("+"), "The wildcard characters can be used in Topic Filters, but MUST NOT be used within a Topic Name"); +static_assert( ! validate_topic_name("/#"), "The wildcard characters can be used in Topic Filters, but MUST NOT be used within a Topic Name"); +static_assert( ! validate_topic_name("+/#"), "The wildcard characters can be used in Topic Filters, but MUST NOT be used within a Topic Name"); +static_assert( ! validate_topic_name("f#"), "The wildcard characters can be used in Topic Filters, but MUST NOT be used within a Topic Name"); +static_assert( ! validate_topic_name("#/"), "The wildcard characters can be used in Topic Filters, but MUST NOT be used within a Topic Name"); +#endif // defined(MQTT_STD_STRING_VIEW) + +MQTT_STRING_VIEW_CONSTEXPR +inline bool compare_topic_filter(string_view topic_filter, string_view topic_name) { + if ( ! validate_topic_filter(topic_filter)) { + BOOST_ASSERT(validate_topic_filter(topic_filter)); + return false; + } + + if ( ! validate_topic_name(topic_name)) { + BOOST_ASSERT(validate_topic_name(topic_name)); + return false; + } + + // TODO: The Server MUST NOT match Topic Filters starting with a wildcard character (# or +) with Topic Names beginning with a $ character + for (string_view::size_type idx = topic_filter.find_first_of("+#"); + string_view::npos != idx; + idx = topic_filter.find_first_of("+#")) { + BOOST_ASSERT( + ('+' == topic_filter[idx]) + || ('#' == topic_filter[idx]) + ); + + if ('+' == topic_filter[idx]) { + // Compare everything up to the first + + if (topic_filter.substr(0, idx) == topic_name.substr(0, idx)) { + /* + * We already know thanks to the topic filter being validated + * that the + symbol is directly touching '/'s on both sides + * (if not the first or last character), so we don't need to + * double check that. + * + * By simply removing the prefix that we've compared and letting + * the loop continue, we get the proper comparison of the '/'s + * automatically when the loop continues. + */ + topic_filter.remove_prefix(idx+1); + /* + * It's a bit more complicated for the incoming topic though + * as we need to remove everything up to the next seperator. + */ + topic_name.remove_prefix(topic_name.find('/', idx)); + } + else { + return false; + } + } + // multilevel wildcard + else { + /* + * Compare up to where the multilevel wild card is found + * and then anything after that matches the wildcard. + */ + return topic_filter.substr(0, idx) == topic_name.substr(0, idx); + } + } + + // No + or # found in the remaining topic filter. Just do a string compare. + return topic_filter == topic_name; +} + +#if defined(MQTT_STD_STRING_VIEW) +static_assert(compare_topic_filter("bob", "bob"), "Topic Names and Topic Filters are case sensitive"); +static_assert( ! compare_topic_filter("Bob", "bob"), "Topic Names and Topic Filters are case sensitive"); +static_assert( ! compare_topic_filter("bob", "boB"), "Topic Names and Topic Filters are case sensitive"); +static_assert( ! compare_topic_filter("/bob", "bob"), "A leading or trailing ‘/’ creates a distinct Topic Name or Topic Filter"); +static_assert( ! compare_topic_filter("bob/", "bob"), "A leading or trailing ‘/’ creates a distinct Topic Name or Topic Filter"); +static_assert( ! compare_topic_filter("bob", "/bob"), "A leading or trailing ‘/’ creates a distinct Topic Name or Topic Filter"); +static_assert( ! compare_topic_filter("bob", "bob/"), "A leading or trailing ‘/’ creates a distinct Topic Name or Topic Filter"); +static_assert(compare_topic_filter("bob/alice", "bob/alice"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("bob/alice/sue", "bob/alice/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("bob//////sue", "bob//////sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("bob/#", "bob//////sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert( ! compare_topic_filter("bob///#", "bob/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("bob/+/sue", "bob/alice/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert( ! compare_topic_filter("bob/+/sue", "bob/alice/mary/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("#", "bob/alice/mary/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("bob/#", "bob/alice/mary/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("bob/alice/#", "bob/alice/mary/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert(compare_topic_filter("bob/alice/mary/#", "bob/alice/mary/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +static_assert( ! compare_topic_filter("bob/alice/mary/sue/#", "bob/alice/mary/sue"), "Each non-wildcarded level in the Topic Filter has to match the corresponding level in the Topic Name character for character for the match to succeed"); +#endif // defined(MQTT_STD_STRING_VIEW) + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_TOPIC_FILTER_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/uuid.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/uuid.hpp new file mode 100644 index 000000000..ba59a8db0 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/broker/uuid.hpp @@ -0,0 +1,28 @@ +// Copyright Takatoshi Kondo 2021 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BROKER_UUID_HPP) +#define MQTT_BROKER_UUID_HPP + +#include + +#include +#include +#include + +#include + +MQTT_BROKER_NS_BEGIN + +inline std::string create_uuid_string() { + // See https://github.com/boostorg/uuid/issues/121 + thread_local auto gen = boost::uuids::random_generator(); + return boost::uuids::to_string(gen()); +} + +MQTT_BROKER_NS_END + +#endif // MQTT_BROKER_UUID_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/buffer.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/buffer.hpp new file mode 100644 index 000000000..94a0caf50 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/buffer.hpp @@ -0,0 +1,260 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_BUFFER_HPP) +#define MQTT_BUFFER_HPP + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +/** + * @brief buffer that has string_view interface + * This class provides string_view interface. + * This class hold string_view target's lifetime optionally. + */ +class buffer : public string_view { +public: + /** + * @brief string_view constructor + * @param sv string_view + * This constructor doesn't hold the sv target's lifetime. + * It behaves as string_view. Caller needs to manage the target lifetime. + */ + explicit constexpr buffer(string_view sv = string_view()) + : string_view(force_move(sv)) {} + + /** + * @brief string constructor (deleted) + * @param string + * This constructor is intentionally deleted. + * Consider `buffer(std::string("ABC"))`, the buffer points to dangling reference. + */ + explicit buffer(std::string) = delete; // to avoid misuse + + /** + * @brief string_view and lifetime constructor + * @param sv string_view + * @param spa shared_ptr_array that holds sv target's lifetime + * If user creates buffer via this constructor, spa's lifetime is held by the buffer. + */ + buffer(string_view sv, const_shared_ptr_array spa) + : string_view(force_move(sv)), + lifetime_(force_move(spa)) { + } + + /** + * @brief get substring + * The returned buffer ragnge is the same as std::string_view::substr(). + * In addition the lifetime is shared between returned buffer and this buffer. + * @param offset offset point of the buffer + * @param length length of the buffer, If the length is string_view::npos + * then the length is from offset to the end of string. + */ + buffer substr(std::size_t offset, std::size_t length = string_view::npos) const& { + // range is checked in string_view::substr. + return buffer(string_view::substr(offset, length), lifetime_); + } + + /** + * @brief get substring + * The returned buffer ragnge is the same as std::string_view::substr(). + * In addition the lifetime is moved to returned buffer. + * @param offset offset point of the buffer + * @param length length of the buffer, If the length is string_view::npos + * then the length is from offset to the end of string. + */ + buffer substr(std::size_t offset, std::size_t length = string_view::npos) && { + // range is checked in string_view::substr. + return buffer(string_view::substr(offset, length), force_move(lifetime_)); + } + + /** + * @brief check the buffer has lifetime. + * @return true the buffer has lifetime. + * false the buffer doesn't have lifetime, This means the buffer is a pure view. + */ + bool has_life() const { + return lifetime_.get(); + } + +private: + const_shared_ptr_array lifetime_; +}; + +inline namespace literals { + +/** + * @brief user defined literals for buffer + * If user use this out of mqtt scope, then user need to declare + * `using namespace literals`. + * When user write "ABC"_mb, then this function is called. + * The created buffer doesn't hold any lifetimes because the string literals + * has static strage duration, so buffer doesn't need to hold the lifetime. + * + * @param str the address of the string literal + * @param length the length of the string literal + * @return buffer + */ +inline buffer operator""_mb(char const* str, std::size_t length) { + return buffer(string_view(str, length)); +} + +} // namespace literals + +/** + * @brief create buffer from the pair of iterators + * It copies string that from b to e into shared_ptr_array. + * Then create buffer and return it. + * The buffer holds the lifetime of shared_ptr_array. + * + * @param b begin position iterator + * @param e end position iterator + * @return buffer + */ +template +inline buffer allocate_buffer(Iterator b, Iterator e) { + auto size = static_cast(std::distance(b, e)); + auto spa = make_shared_ptr_array(size); + std::copy(b, e, spa.get()); + auto view = string_view(spa.get(), size); + return buffer(view, force_move(spa)); +} + +/** + * @brief create buffer from the string_view + * It copies string that from string_view into shared_ptr_array. + * Then create buffer and return it. + * The buffer holds the lifetime of shared_ptr_array. + * + * @param sv the source string_view + * @return buffer + */ +inline buffer allocate_buffer(string_view sv) { + return allocate_buffer(sv.begin(), sv.end()); +} + +inline buffer const* buffer_sequence_begin(buffer const& buf) { + return std::addressof(buf); +} + +inline buffer const* buffer_sequence_end(buffer const& buf) { + return std::addressof(buf) + 1; +} + +template +inline typename Col::const_iterator buffer_sequence_begin(Col const& col) { + return col.cbegin(); +} + +template +inline typename Col::const_iterator buffer_sequence_end(Col const& col) { + return col.cend(); +} + +namespace detail { + +template +char buffer_sequence_begin_helper(...); + +template +char (&buffer_sequence_begin_helper( + T* t, + typename std::enable_if< + !std::is_same< + decltype(buffer_sequence_begin(*t)), + void + >::value + >::type*) +)[2]; + +template +char buffer_sequence_end_helper(...); + +template +char (&buffer_sequence_end_helper( + T* t, + typename std::enable_if< + !std::is_same< + decltype(buffer_sequence_end(*t)), + void + >::value + >::type*) +)[2]; + +template +char (&buffer_sequence_element_type_helper(...))[2]; + +template +char buffer_sequence_element_type_helper( + T* t, + typename std::enable_if< + std::is_convertible< + decltype(*buffer_sequence_begin(*t)), + Buffer + >::value + >::type* +); + +template +struct is_buffer_sequence_class + : std::integral_constant(0, 0)) != 1 && + sizeof(buffer_sequence_end_helper(0, 0)) != 1 && + sizeof(buffer_sequence_element_type_helper(0, 0)) == 1> +{ +}; + +} // namespace detail + +template +struct is_buffer_sequence : + std::conditional< + std::is_class::value, + detail::is_buffer_sequence_class, + std::false_type + >::type +{ +}; + +template <> +struct is_buffer_sequence : std::true_type +{ +}; + +} // namespace MQTT_NS + +namespace boost { +namespace asio { + +/** + * @brief create boost::asio::const_buffer from the MQTT_NS::buffer + * boost::asio::const_buffer is a kind of view class. + * So the class doesn't hold any lifetimes. + * The caller needs to manage data's lifetime. + * + * @param data source MQTT_NS::buffer + * @return boost::asio::const_buffer + */ +inline const_buffer buffer(MQTT_NS::buffer const& data) { + return buffer(data.data(), data.size()); +} + +} // namespace asio +} // namespace boost + +#endif // MQTT_BUFFER_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/callable_overlay.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/callable_overlay.hpp new file mode 100644 index 000000000..0dbf03c65 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/callable_overlay.hpp @@ -0,0 +1,2131 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CALLABLE_OVERLAY_HPP) +#define MQTT_CALLABLE_OVERLAY_HPP + +#include // should be top to configure variant limit + +#include +#include +#include +#include + +namespace MQTT_NS { +template +struct callable_overlay final : public Impl +{ + using base = Impl; + using packet_id_t = typename base::packet_id_t; + + template + callable_overlay(Args && ... args) + : base(std::forward(args)...) + { } + ~callable_overlay() = default; + callable_overlay(callable_overlay&&) = default; + callable_overlay(callable_overlay const&) = default; + callable_overlay& operator=(callable_overlay&&) = default; + callable_overlay& operator=(callable_overlay const&) = default; + + // MQTT Common handlers + + /** + * @brief Pingreq handler + * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718086
+ * 3.13 PINGREQ – PING request + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_pingreq() noexcept override final { + return ! h_pingreq_ || h_pingreq_(); + } + + /** + * @brief Pingresp handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901200
+ * 3.13 PINGRESP – PING response + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_pingresp() noexcept override final { + return ! h_pingresp_ || h_pingresp_(); + } + + // MQTT v3_1_1 handlers + + /** + * @brief Connect handler + * @param client_id + * Client Identifier.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349245
+ * 3.1.3.1 Client Identifier + * @param user_name + * User Name.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349245
+ * 3.1.3.4 User Name + * @param password + * Password.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349246
+ * 3.1.3.5 Password + * @param will + * Will. It contains retain, QoS, topic, and message.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349232
+ * 3.1.2.5 Will Flag
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349233
+ * 3.1.2.6 Will QoS
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349234
+ * 3.1.2.7 Will Retain
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349243
+ * 3.1.3.2 Will Topic
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349244
+ * 3.1.3.3 Will Message
+ * @param clean_session + * Clean Session
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349231
+ * 3.1.2.4 Clean Session + * @param keep_alive + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349237
+ * 3.1.2.10 Keep Alive + * @return if the handler returns true, then continue receiving, otherwise quit. + * + */ + MQTT_ALWAYS_INLINE bool on_connect(buffer client_id, + optional user_name, + optional password, + optional will, + bool clean_session, + std::uint16_t keep_alive) noexcept override final { + return ! h_connect_ + || h_connect_(force_move(client_id), + force_move(user_name), + force_move(password), + force_move(will), + clean_session, + keep_alive); + } + + /** + * @brief Connack handler + * @param session_present + * Session present flag.
+ * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718036
+ * 3.2.2.2 Session Present + * @param return_code + * connect_return_code
+ * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718036
+ * 3.2.2.3 Connect Return code + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_connack(bool session_present, connect_return_code return_code) noexcept override final { + return ! h_connack_ + || h_connack_(session_present, return_code); + } + + /** + * @brief Publish handler + * @param packet_id + * packet identifier
+ * If received publish's QoS is 0, packet_id is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718039
+ * 3.3.2 Variable header + * @param fixed_header + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718038
+ * 3.3.1 Fixed header
+ * You can check the fixed header using publish functions. + * @param topic_name + * Topic name + * @param contents + * Published contents + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_publish(optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents) noexcept override final { + return ! h_publish_ + || h_publish_(packet_id, + pubopts, + force_move(topic_name), + force_move(contents)); + } + + /** + * @brief Puback handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718045
+ * 3.4.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_puback(packet_id_t packet_id) noexcept override final { + return ! h_puback_ + || h_puback_(packet_id); + } + + /** + * @brief Pubrec handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718050
+ * 3.5.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_pubrec(packet_id_t packet_id) noexcept override final { + return ! h_pubrec_ + || h_pubrec_(packet_id); + } + + /** + * @brief Pubrel handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349791
+ * 3.6.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_pubrel(packet_id_t packet_id) noexcept override final { + return ! h_pubrel_ + || h_pubrel_(packet_id); + } + + /** + * @brief Pubcomp handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718060
+ * 3.7.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_pubcomp(packet_id_t packet_id) noexcept override final { + return ! h_pubcomp_ + || h_pubcomp_(packet_id); + } + + /** + * @brief Subscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349801
+ * 3.8.2 Variable header + * @param entries + * Collection of Share Name, Topic Filter, and QoS.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349802
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_subscribe(packet_id_t packet_id, + std::vector entries) noexcept override final { + return ! h_subscribe_ + || h_subscribe_(packet_id, force_move(entries)); + } + + /** + * @brief Suback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718070
+ * 3.9.2 Variable header + * @param qoss + * Collection of QoS that is corresponding to subscribed topic order.
+ * If subscription is failure, the value is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718071
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_suback(packet_id_t packet_id, + std::vector reasons) noexcept override final { + return ! h_suback_ + || h_suback_(packet_id, force_move(reasons)); + } + + /** + * @brief Unsubscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349810
+ * 3.10.2 Variable header + * @param topics + * Collection of Share Name and Topic Filter
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc384800448
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_unsubscribe(packet_id_t packet_id, + std::vector entries) noexcept override final { + return ! h_unsubscribe_ + || h_unsubscribe_(packet_id, force_move(entries)); + } + + /** + * @brief Unsuback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718045
+ * 3.11.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_unsuback(packet_id_t packet_id) noexcept override final { + return ! h_unsuback_ + || h_unsuback_(packet_id); + } + + /** + * @brief Disconnect handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc384800463
+ * 3.14 DISCONNECT – Disconnect notification + */ + MQTT_ALWAYS_INLINE void on_disconnect() noexcept override final { + if(h_disconnect_) h_disconnect_(); + } + + // MQTT v5 handlers + + /** + * @brief Connect handler + * @param client_id + * Client Identifier.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier + * @param user_name + * User Name.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.4 User Name + * @param password + * Password.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.5 Password + * @param will + * Will. It contains retain, QoS, propertied, topic, and message.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901040
+ * 3.1.2.5 Will Flag
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901041
+ * 3.1.2.6 Will QoS
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901042
+ * 3.1.2.7 Will Retain
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901060
+ * 3.1.3.2 Will Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901069
+ * 3.1.3.3 Will Topic
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901070
+ * 3.1.3.3 Will Payload
+ * @param clean_start + * Clean Start
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039
+ * 3.1.2.4 Clean Session + * @param keep_alive + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + * + */ + MQTT_ALWAYS_INLINE bool on_v5_connect(buffer client_id, + optional user_name, + optional password, + optional will, + bool clean_start, + std::uint16_t keep_alive, + v5::properties props) noexcept override final { + return ! h_v5_connect_ + || h_v5_connect_(force_move(client_id), + force_move(user_name), + force_move(password), + force_move(will), + clean_start, + keep_alive, + force_move(props)); + } + + /** + * @brief Connack handler + * @param session_present + * Session present flag.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078
+ * 3.2.2.1.1 Session Present + * @param reason_code + * Connect Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901079
+ * 3.2.2.2 Connect Reason code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901080
+ * 3.2.2.3 CONNACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_connack(bool session_present, + v5::connect_reason_code reason_code, + v5::properties props) noexcept override final { + return ! h_v5_connack_ + || h_v5_connack_(session_present, reason_code, force_move(props)); + } + + /** + * @brief Publish handler + * @param packet_id + * packet identifier
+ * If received publish's QoS is 0, packet_id is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901108
+ * 3.3.2.2 Packet Identifier + * @param fixed_header + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901101
+ * 3.3.1 Fixed header
+ * You can check the fixed header using publish functions. + * @param topic_name + * Topic name
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107
+ * 3.3.2.1 Topic Name
+ * @param contents + * Publish Payload
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119
+ * 3.3.3 PUBLISH Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_publish(optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents, + v5::properties props) noexcept override final { + return ! h_v5_publish_ + || h_v5_publish_(packet_id, + pubopts, + force_move(topic_name), + force_move(contents), + force_move(props)); + } + + /** + * @brief Puback handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901123
+ * 3.4.2 Variable header + * @param reason_code + * PUBACK Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
+ * 3.4.2.1 PUBACK Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901125
+ * 3.4.2.2 PUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_puback(packet_id_t packet_id, + v5::puback_reason_code reason_code, + v5::properties props) noexcept override final { + return ! h_v5_puback_ + || h_v5_puback_(packet_id, reason_code, force_move(props)); + } + + /** + * @brief Pubrec handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901133
+ * 3.5.2 Variable header + * @param reason_code + * PUBREC Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
+ * 3.5.2.1 PUBREC Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901135
+ * 3.5.2.2 PUBREC Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_pubrec(packet_id_t packet_id, + v5::pubrec_reason_code reason_code, + v5::properties props) noexcept override final { + return ! h_v5_pubrec_ + || h_v5_pubrec_(packet_id, reason_code, force_move(props)); + } + + /** + * @brief Pubrel handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901143
+ * 3.6.2 Variable header + * @param reason_code + * PUBREL Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
+ * 3.6.2.1 PUBREL Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901145
+ * 3.6.2.2 PUBREL Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_pubrel(packet_id_t packet_id, + v5::pubrel_reason_code reason_code, + v5::properties props) noexcept override final { + return ! h_v5_pubrel_ + || h_v5_pubrel_(packet_id, reason_code, force_move(props)); + } + + /** + * @brief Pubcomp handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901153
+ * 3.7.2 Variable header + * @param reason_code + * PUBCOMP Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
+ * 3.7.2.1 PUBCOMP Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901155
+ * 3.7.2.2 PUBCOMP Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_pubcomp(packet_id_t packet_id, + v5::pubcomp_reason_code reason_code, + v5::properties props) noexcept override final { + return ! h_v5_pubcomp_ + || h_v5_pubcomp_(packet_id, reason_code, force_move(props)); + } + + /** + * @brief Subscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901163
+ * 3.8.2 Variable header + * @param entries + * Collection of Share Name, Topic Filter, and QoS.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901168
+ * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_subscribe(packet_id_t packet_id, + std::vector entries, + v5::properties props) noexcept override final { + return ! h_v5_subscribe_ + || h_v5_subscribe_(packet_id, force_move(entries), force_move(props)); + } + + /** + * @brief Suback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901173
+ * 3.9.2 Variable header + * @param reasons + * Collection of reason_code.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174
+ * 3.9.2.1 SUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_suback(packet_id_t packet_id, + std::vector reasons, + v5::properties props) noexcept override final { + return ! h_v5_suback_ + || h_v5_suback_(packet_id, force_move(reasons), force_move(props)); + } + + /** + * @brief Unsubscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901181
+ * 3.10.2 Variable header + * @param entries + * Collection of Share Name and Topic Filter
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901185
+ * 3.10.3 UNSUBSCRIBE Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_unsubscribe(packet_id_t packet_id, + std::vector entries, + v5::properties props) noexcept override final { + return ! h_v5_unsubscribe_ + || h_v5_unsubscribe_(packet_id, force_move(entries), force_move(props)); + } + + /** + * @brief Unsuback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901189
+ * 3.11.2 Variable header + * @param reasons + * Collection of reason_code.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901190
+ * 3.11.2.1 UNSUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_unsuback(packet_id_t packet_id, + std::vector reasons, + v5::properties props) noexcept override final { + return ! h_v5_unsuback_ + || h_v5_unsuback_(packet_id, force_move(reasons), force_move(props)); + } + + /** + * @brief Disconnect handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * 3.14 DISCONNECT – Disconnect notification + * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + */ + MQTT_ALWAYS_INLINE void on_v5_disconnect(v5::disconnect_reason_code reason_code, + v5::properties props) noexcept override final { + if (h_v5_disconnect_) h_v5_disconnect_(reason_code, force_move(props)); + } + + /** + * @brief Auth handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901217
+ * 3.15 AUTH – Authentication exchange + * @param reason_code + * AUTH Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
+ * 3.15.2.1 Authenticate Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901221
+ * 3.15.2.2 AUTH Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + MQTT_ALWAYS_INLINE bool on_v5_auth(v5::auth_reason_code reason_code, + v5::properties props) noexcept override final { + return ! h_v5_auth_ + || h_v5_auth_(reason_code, force_move(props)); + + } + + // Original handlers + + /** + * @brief Close handler + * + * This handler is called if the client called `disconnect()` and the server closed the socket cleanly. + * If the socket is closed by other reasons, error_handler is called. + * This calls base::on_close() prior to calling the provided callback, if any. + */ + MQTT_ALWAYS_INLINE void on_close() noexcept override final { + base::on_close(); + if (h_close_) h_close_(); + } + + /** + * @brief Error handler + * + * This handler is called if the socket is closed without client's `disconnect()` call. + * This calls base::on_error() prior to calling the provided callback, if any. + * + * @param ec error code + */ + MQTT_ALWAYS_INLINE void on_error(error_code ec) noexcept override final { + base::on_error(ec); + if (h_error_) h_error_(ec); + } + + /** + * @brief Publish response sent handler + * This function is called just after puback sent on QoS1, or pubcomp sent on QoS2. + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901026
+ * 2.2.1 Packet Identifier + */ + MQTT_ALWAYS_INLINE void on_pub_res_sent(packet_id_t packet_id) noexcept override final { + if (h_pub_res_sent_) h_pub_res_sent_(packet_id); + } + + /** + * @brief Serialize publish handler + * You can serialize the publish message. + * To restore the message, use restore_serialized_message(). + * @param msg publish message + */ + MQTT_ALWAYS_INLINE void on_serialize_publish_message(basic_publish_message msg) noexcept override final { + if (h_serialize_publish_) h_serialize_publish_(msg); + } + + /** + * @brief Serialize publish handler + * You can serialize the publish message. + * To restore the message, use restore_serialized_message(). + * @param msg v5::publish message + */ + MQTT_ALWAYS_INLINE void on_serialize_v5_publish_message(v5::basic_publish_message msg) noexcept override final { + if (h_serialize_v5_publish_) h_serialize_v5_publish_(msg); + } + + /** + * @brief Serialize pubrel handler + * You can serialize the pubrel message. + * If your storage has already had the publish message that has the same packet_id, + * then you need to replace the publish message to pubrel message. + * To restore the message, use restore_serialized_message(). + * @param msg pubrel message + */ + MQTT_ALWAYS_INLINE void on_serialize_pubrel_message(basic_pubrel_message msg) noexcept override final { + if (h_serialize_pubrel_) h_serialize_pubrel_(msg); + } + + /** + * @brief Serialize pubrel handler + * You can serialize the pubrel message. + * If your storage has already had the publish message that has the same packet_id, + * then you need to replace the publish message to pubrel message. + * To restore the message, use restore_serialized_message(). + * @param msg pubrel message + */ + MQTT_ALWAYS_INLINE void on_serialize_v5_pubrel_message(v5::basic_pubrel_message msg) noexcept override final { + if (h_serialize_v5_pubrel_) h_serialize_v5_pubrel_(msg); + } + + /** + * @brief Remove serialized message + * @param packet_id packet identifier of the removing message + */ + MQTT_ALWAYS_INLINE void on_serialize_remove(packet_id_t packet_id) noexcept override final { + if (h_serialize_remove_) h_serialize_remove_(packet_id); + } + + /** + * @brief Pre-send handler + * This handler is called when any mqtt control packet is decided to send. + */ + MQTT_ALWAYS_INLINE void on_pre_send() noexcept override final { + base::on_pre_send(); + if (h_pre_send_) h_pre_send_(); + } + + /** + * @brief is valid length handler + * This handler is called when remaining length is received. + * @param control_packet_type control_packet_type that has variable length + * @param remaining length + * @return true if check is success, otherwise false + */ + MQTT_ALWAYS_INLINE bool check_is_valid_length(control_packet_type packet_type, std::size_t remaining_length) noexcept override final { + return ! h_is_valid_length_ + || h_is_valid_length_(packet_type, remaining_length); + } + + /** + * @brief next read handler + * This handler is called when the current mqtt message has been processed. + * This calls base::on_mqtt_message_processed() only if mqtt_message_processed handler is not set. + * * `client` inherits `endpoint` and override `on_pre_send()`, `on_close()`, and `on_error()`. + * And implement important process *1 in the override definition (timer reset, timer cancel). + * * `client` has `set_pre_send_handler()`, `set_on_close()`, and `set_on_error()`. + * If a user of `client` call them, and the event happens, set handler should be called. + * Either the user set handlers or not, *1 should be executed automatically. + * * `endpoint` has the default definition of `on_mqtt_message_processed()`. + * `client` doesn't override `on_mqtt_message_processed()`. + * If a user override this, then the default definition shouldn't be called. It makes conflict behavior. + * * Other `on_*()` doesn't have the default definition. `callable_overlay` calls the corresponding + * handler only if it is set. + * @param func A callback function that is called when async operation will finish. + */ + MQTT_ALWAYS_INLINE void on_mqtt_message_processed(any session_life_keeper) noexcept override final { + if(h_mqtt_message_processed_) { + h_mqtt_message_processed_(force_move(session_life_keeper)); + } + else { + base::on_mqtt_message_processed(force_move(session_life_keeper)); + } + } + + /** + * @brief Pingreq handler + * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718086
+ * 3.13 PINGREQ – PING request + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using pingreq_handler = std::function; + + /** + * @brief Pingresp handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901200
+ * 3.13 PINGRESP – PING response + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using pingresp_handler = std::function; + + + // MQTT v3_1_1 handlers + + /** + * @brief Connect handler + * @param client_id + * Client Identifier.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349245
+ * 3.1.3.1 Client Identifier + * @param user_name + * User Name.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349245
+ * 3.1.3.4 User Name + * @param password + * Password.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349246
+ * 3.1.3.5 Password + * @param will + * Will. It contains retain, QoS, topic, and message.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349232
+ * 3.1.2.5 Will Flag
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349233
+ * 3.1.2.6 Will QoS
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349234
+ * 3.1.2.7 Will Retain
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349243
+ * 3.1.3.2 Will Topic
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349244
+ * 3.1.3.3 Will Message
+ * @param clean_session + * Clean Session
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349231
+ * 3.1.2.4 Clean Session + * @param keep_alive + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349237
+ * 3.1.2.10 Keep Alive + * @return if the handler returns true, then continue receiving, otherwise quit. + * + */ + using connect_handler = std::function< + bool(buffer client_id, + optional user_name, + optional password, + optional will, + bool clean_session, + std::uint16_t keep_alive)>; + + /** + * @brief Connack handler + * @param session_present + * Session present flag.
+ * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718036
+ * 3.2.2.2 Session Present + * @param return_code + * connect_return_code
+ * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718036
+ * 3.2.2.3 Connect Return code + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using connack_handler = std::function; + + /** + * @brief Publish handler + * @param fixed_header + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718038
+ * 3.3.1 Fixed header
+ * You can check the fixed header using publish functions. + * @param packet_id + * packet identifier
+ * If received publish's QoS is 0, packet_id is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718039
+ * 3.3.2 Variable header + * @param topic_name + * Topic name + * @param contents + * Published contents + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using publish_handler = std::function packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents)>; + + /** + * @brief Puback handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718045
+ * 3.4.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using puback_handler = std::function; + + /** + * @brief Pubrec handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718050
+ * 3.5.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using pubrec_handler = std::function; + + /** + * @brief Pubrel handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349791
+ * 3.6.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using pubrel_handler = std::function; + + /** + * @brief Pubcomp handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718060
+ * 3.7.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using pubcomp_handler = std::function; + + /** + * @brief Subscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349801
+ * 3.8.2 Variable header + * @param entries + * Collection of Share Name, Topic Filter, and QoS.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349802
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using subscribe_handler = std::function entries)>; + + /** + * @brief Suback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718070
+ * 3.9.2 Variable header + * @param qoss + * Collection of QoS that is corresponding to subscribed topic order.
+ * If subscription is failure, the value is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718071
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using suback_handler = std::function qoss)>; + + /** + * @brief Unsubscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349810
+ * 3.10.2 Variable header + * @param entries + * Collection of Share Name and Topic Filter
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc384800448
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using unsubscribe_handler = std::function entries)>; + + /** + * @brief Unsuback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718045
+ * 3.11.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using unsuback_handler = std::function; + + /** + * @brief Disconnect handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc384800463
+ * 3.14 DISCONNECT – Disconnect notification + */ + using disconnect_handler = std::function; + + // MQTT v5 handlers + + /** + * @brief Connect handler + * @param client_id + * Client Identifier.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier + * @param user_name + * User Name.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.4 User Name + * @param password + * Password.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.5 Password + * @param will + * Will. It contains retain, QoS, propertied, topic, and message.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901040
+ * 3.1.2.5 Will Flag
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901041
+ * 3.1.2.6 Will QoS
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901042
+ * 3.1.2.7 Will Retain
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901060
+ * 3.1.3.2 Will Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901069
+ * 3.1.3.3 Will Topic
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901070
+ * 3.1.3.3 Will Payload
+ * @param clean_start + * Clean Start
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039
+ * 3.1.2.4 Clean Session + * @param keep_alive + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + * + */ + using v5_connect_handler = std::function< + bool(buffer client_id, + optional user_name, + optional password, + optional will, + bool clean_start, + std::uint16_t keep_alive, + v5::properties props) + >; + + /** + * @brief Connack handler + * @param session_present + * Session present flag.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078
+ * 3.2.2.1.1 Session Present + * @param reason_code + * Connect Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901079
+ * 3.2.2.2 Connect Reason code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901080
+ * 3.2.2.3 CONNACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_connack_handler = std::function< + bool(bool session_present, + v5::connect_reason_code reason_code, + v5::properties props) + >; + + /** + * @brief Publish handler + * @param packet_id + * packet identifier
+ * If received publish's QoS is 0, packet_id is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901108
+ * 3.3.2.2 Packet Identifier + * @param fixed_header + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901101
+ * 3.3.1 Fixed header
+ * You can check the fixed header using publish functions. + * @param topic_name + * Topic name
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107
+ * 3.3.2.1 Topic Name
+ * @param contents + * Publish Payload
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119
+ * 3.3.3 PUBLISH Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_publish_handler = std::function< + bool(optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents, + v5::properties props) + >; + + /** + * @brief Puback handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901123
+ * 3.4.2 Variable header + * @param reason_code + * PUBACK Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
+ * 3.4.2.1 PUBACK Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901125
+ * 3.4.2.2 PUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_puback_handler = std::function< + bool(packet_id_t packet_id, + v5::puback_reason_code reason_code, + v5::properties props) + >; + + /** + * @brief Pubrec handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901133
+ * 3.5.2 Variable header + * @param reason_code + * PUBREC Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
+ * 3.5.2.1 PUBREC Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901135
+ * 3.5.2.2 PUBREC Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_pubrec_handler = std::function< + bool(packet_id_t packet_id, + v5::pubrec_reason_code reason_code, + v5::properties props) + >; + + /** + * @brief Pubrel handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901143
+ * 3.6.2 Variable header + * @param reason_code + * PUBREL Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
+ * 3.6.2.1 PUBREL Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901145
+ * 3.6.2.2 PUBREL Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_pubrel_handler = std::function< + bool(packet_id_t packet_id, + v5::pubrel_reason_code reason_code, + v5::properties props) + >; + + /** + * @brief Pubcomp handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901153
+ * 3.7.2 Variable header + * @param reason_code + * PUBCOMP Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
+ * 3.7.2.1 PUBCOMP Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901155
+ * 3.7.2.2 PUBCOMP Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_pubcomp_handler = std::function< + bool(packet_id_t packet_id, + v5::pubcomp_reason_code reason_code, + v5::properties props) + >; + + /** + * @brief Subscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901163
+ * 3.8.2 Variable header + * @param entries + * Collection of Share Name, Topic Filter, and Subscribe Options.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901168
+ * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_subscribe_handler = std::function< + bool(packet_id_t packet_id, + std::vector entries, + v5::properties props) + >; + + /** + * @brief Suback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901173
+ * 3.9.2 Variable header + * @param reasons + * Collection of reason_code.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174
+ * 3.9.2.1 SUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_suback_handler = std::function< + bool(packet_id_t packet_id, + std::vector reasons, + v5::properties props) + >; + + /** + * @brief Unsubscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901181
+ * 3.10.2 Variable header + * @param entries + * Collection of Share Name and Topic Filter
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901185
+ * 3.10.3 UNSUBSCRIBE Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_unsubscribe_handler = std::function< + bool(packet_id_t packet_id, + std::vector entries, + v5::properties props) + >; + + /** + * @brief Unsuback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901189
+ * 3.11.2 Variable header + * @param reasons + * Collection of reason_code.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901190
+ * 3.11.2.1 UNSUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_unsuback_handler = std::function< + bool(packet_id_t, + std::vector reasons, + v5::properties props) + >; + + /** + * @brief Disconnect handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * 3.14 DISCONNECT – Disconnect notification + * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + */ + using v5_disconnect_handler = std::function< + void(v5::disconnect_reason_code reason_code, + v5::properties props) + >; + + /** + * @brief Auth handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901217
+ * 3.15 AUTH – Authentication exchange + * @param reason_code + * AUTH Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
+ * 3.15.2.1 Authenticate Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901221
+ * 3.15.2.2 AUTH Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + using v5_auth_handler = std::function< + bool(v5::auth_reason_code reason_code, + v5::properties props) + >; + + + // Original handlers + + /** + * @brief Close handler + * + * This handler is called if the client called `disconnect()` and the server closed the socket cleanly. + * If the socket is closed by other reasons, error_handler is called. + */ + using close_handler = std::function; + + /** + * @brief Error handler + * + * This handler is called if the socket is closed without client's `disconnect()` call. + * + * @param ec error code + */ + using error_handler = std::function; + + /** + * @brief Publish response sent handler + * This function is called just after puback sent on QoS1, or pubcomp sent on QoS2. + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901026
+ * 2.2.1 Packet Identifier + */ + using pub_res_sent_handler = std::function; + + /** + * @brief Serialize publish handler + * You can serialize the publish message. + * To restore the message, use restore_serialized_message(). + * @param msg publish message + */ + using serialize_publish_message_handler = std::function msg)>; + + /** + * @brief Serialize publish handler + * You can serialize the publish message. + * To restore the message, use restore_serialized_message(). + * @param msg v5::publish message + */ + using serialize_v5_publish_message_handler = std::function msg)>; + + /** + * @brief Serialize publish handler + * You can serialize the publish message. + * To restore the message, use restore_serialized_message(). + * @param packet_id packet identifier of the serializing message + * @param data pointer to the serializing message + * @param size size of the serializing message + */ + using serialize_publish_handler = std::function; + + /** + * @brief Serialize pubrel handler + * You can serialize the pubrel message. + * If your storage has already had the publish message that has the same packet_id, + * then you need to replace the publish message to pubrel message. + * To restore the message, use restore_serialized_message(). + * @param msg pubrel message + */ + using serialize_pubrel_message_handler = std::function msg)>; + + /** + * @brief Serialize pubrel handler + * You can serialize the pubrel message. + * If your storage has already had the publish message that has the same packet_id, + * then you need to replace the publish message to pubrel message. + * To restore the message, use restore_serialized_message(). + * @param msg pubrel message + */ + using serialize_v5_pubrel_message_handler = std::function msg)>; + + /** + * @brief Serialize pubrel handler + * You can serialize the pubrel message. + * If your storage has already had the publish message that has the same packet_id, + * then you need to replace the publish message to pubrel message. + * To restore the message, use restore_serialized_message(). + * @param packet_id packet identifier of the serializing message + * @param data pointer to the serializing message + * @param size size of the serializing message + */ + using serialize_pubrel_handler = std::function; + + /** + * @brief Remove serialized message + * @param packet_id packet identifier of the removing message + */ + using serialize_remove_handler = std::function; + + /** + * @brief Pre-send handler + * This handler is called when any mqtt control packet is decided to send. + */ + using pre_send_handler = std::function; + + /** + * @brief is valid length handler + * This handler is called when remaining length is received. + * @param control_packet_type control_packet_type that has variable length + * @param remaining length + * @return true if check is success, otherwise false + */ + using is_valid_length_handler = + std::function; + + /** + * @brief next read handler + * This handler is called when the current mqtt message has been processed. + * @param func A callback function that is called when async operation will finish. + */ + using mqtt_message_processed_handler = + std::function; + + + + // MQTT Common handlers + + /** + * @brief Set pingreq handler + * @param h handler + */ + void set_pingreq_handler(pingreq_handler h = pingreq_handler()) { + h_pingreq_ = force_move(h); + } + + /** + * @brief Set pingresp handler + * @param h handler + */ + void set_pingresp_handler(pingresp_handler h = pingresp_handler()) { + h_pingresp_ = force_move(h); + } + + + /** + * @brief Get pingreq handler + * @return handler + */ + pingreq_handler const& get_pingreq_handler() const { + return h_pingreq_; + } + + /** + * @brief Get pingresp handler + * @return handler + */ + pingresp_handler const& get_pingresp_handler() const { + return h_pingresp_; + } + + + // MQTT v3_1_1 handlers + + /** + * @brief Set connect handler + * @param h handler + */ + void set_connect_handler(connect_handler h = connect_handler()) { + h_connect_ = force_move(h); + } + + /** + * @brief Set connack handler + * @param h handler + */ + void set_connack_handler(connack_handler h = connack_handler()) { + h_connack_ = force_move(h); + } + + /** + * @brief Set publish handler + * @param h handler + */ + void set_publish_handler(publish_handler h = publish_handler()) { + h_publish_ = force_move(h); + } + + /** + * @brief Set puback handler + * @param h handler + */ + void set_puback_handler(puback_handler h = puback_handler()) { + h_puback_ = force_move(h); + } + + /** + * @brief Set pubrec handler + * @param h handler + */ + void set_pubrec_handler(pubrec_handler h = pubrec_handler()) { + h_pubrec_ = force_move(h); + } + + /** + * @brief Set pubrel handler + * @param h handler + */ + void set_pubrel_handler(pubrel_handler h = pubrel_handler()) { + h_pubrel_ = force_move(h); + } + + /** + * @brief Set pubcomp handler + * @param h handler + */ + void set_pubcomp_handler(pubcomp_handler h = pubcomp_handler()) { + h_pubcomp_ = force_move(h); + } + + /** + * @brief Set subscribe handler + * @param h handler + */ + void set_subscribe_handler(subscribe_handler h = subscribe_handler()) { + h_subscribe_ = force_move(h); + } + + /** + * @brief Set suback handler + * @param h handler + */ + void set_suback_handler(suback_handler h = suback_handler()) { + h_suback_ = force_move(h); + } + + /** + * @brief Set unsubscribe handler + * @param h handler + */ + void set_unsubscribe_handler(unsubscribe_handler h = unsubscribe_handler()) { + h_unsubscribe_ = force_move(h); + } + + /** + * @brief Set unsuback handler + * @param h handler + */ + void set_unsuback_handler(unsuback_handler h = unsuback_handler()) { + h_unsuback_ = force_move(h); + } + + /** + * @brief Set disconnect handler + * @param h handler + */ + void set_disconnect_handler(disconnect_handler h = disconnect_handler()) { + h_disconnect_ = force_move(h); + } + + /** + * @brief Get connect handler + * @return handler + */ + connect_handler const& get_connect_handler() const { + return h_connect_; + } + + /** + * @brief Get connack handler + * @return handler + */ + connack_handler const& get_connack_handler() const { + return h_connack_; + } + + /** + * @brief Set publish handler + * @return handler + */ + publish_handler const& get_publish_handler() const { + return h_publish_; + } + + /** + * @brief Get puback handler + * @return handler + */ + puback_handler const& get_puback_handler() const { + return h_puback_; + } + + /** + * @brief Get pubrec handler + * @return handler + */ + pubrec_handler const& get_pubrec_handler() const { + return h_pubrec_; + } + + /** + * @brief Get pubrel handler + * @return handler + */ + pubrel_handler const& get_pubrel_handler() const { + return h_pubrel_; + } + + /** + * @brief Get pubcomp handler + * @return handler + */ + pubcomp_handler const& get_pubcomp_handler() const { + return h_pubcomp_; + } + + /** + * @brief Get subscribe handler + * @return handler + */ + subscribe_handler const& get_subscribe_handler() const { + return h_subscribe_; + } + + /** + * @brief Get suback handler + * @return handler + */ + suback_handler const& get_suback_handler() const { + return h_suback_; + } + + /** + * @brief Get unsubscribe handler + * @return handler + */ + unsubscribe_handler const& get_unsubscribe_handler() const { + return h_unsubscribe_; + } + + /** + * @brief Get unsuback handler + * @return handler + */ + unsuback_handler const& get_unsuback_handler() const { + return h_unsuback_; + } + + /** + * @brief Get disconnect handler + * @return handler + */ + disconnect_handler const& get_disconnect_handler() const { + return h_disconnect_; + } + + // MQTT v5 handlers + + /** + * @brief Set connect handler + * @param h handler + */ + void set_v5_connect_handler(v5_connect_handler h = v5_connect_handler()) { + h_v5_connect_ = force_move(h); + } + + /** + * @brief Set connack handler + * @param h handler + */ + void set_v5_connack_handler(v5_connack_handler h = v5_connack_handler()) { + h_v5_connack_ = force_move(h); + } + + /** + * @brief Set publish handler + * @param h handler + */ + void set_v5_publish_handler(v5_publish_handler h = v5_publish_handler()) { + h_v5_publish_ = force_move(h); + } + + /** + * @brief Set puback handler + * @param h handler + */ + void set_v5_puback_handler(v5_puback_handler h = v5_puback_handler()) { + h_v5_puback_ = force_move(h); + } + + /** + * @brief Set pubrec handler + * @param h handler + */ + void set_v5_pubrec_handler(v5_pubrec_handler h = v5_pubrec_handler()) { + h_v5_pubrec_ = force_move(h); + } + + /** + * @brief Set pubrel handler + * @param h handler + */ + void set_v5_pubrel_handler(v5_pubrel_handler h = v5_pubrel_handler()) { + h_v5_pubrel_ = force_move(h); + } + + /** + * @brief Set pubcomp handler + * @param h handler + */ + void set_v5_pubcomp_handler(v5_pubcomp_handler h = v5_pubcomp_handler()) { + h_v5_pubcomp_ = force_move(h); + } + + /** + * @brief Set subscribe handler + * @param h handler + */ + void set_v5_subscribe_handler(v5_subscribe_handler h = v5_subscribe_handler()) { + h_v5_subscribe_ = force_move(h); + } + + /** + * @brief Set suback handler + * @param h handler + */ + void set_v5_suback_handler(v5_suback_handler h = v5_suback_handler()) { + h_v5_suback_ = force_move(h); + } + + /** + * @brief Set unsubscribe handler + * @param h handler + */ + void set_v5_unsubscribe_handler(v5_unsubscribe_handler h = v5_unsubscribe_handler()) { + h_v5_unsubscribe_ = force_move(h); + } + + /** + * @brief Set unsuback handler + * @param h handler + */ + void set_v5_unsuback_handler(v5_unsuback_handler h = v5_unsuback_handler()) { + h_v5_unsuback_ = force_move(h); + } + + /** + * @brief Set disconnect handler + * @param h handler + */ + void set_v5_disconnect_handler(v5_disconnect_handler h = v5_disconnect_handler()) { + h_v5_disconnect_ = force_move(h); + } + + /** + * @brief Set auth handler + * @param h handler + */ + void set_v5_auth_handler(v5_auth_handler h = v5_auth_handler()) { + h_v5_auth_ = force_move(h); + } + + /** + * @brief Get connect handler + * @return handler + */ + v5_connect_handler const& get_v5_connect_handler() const { + return h_v5_connect_; + } + + /** + * @brief Get connack handler + * @return handler + */ + v5_connack_handler const& get_v5_connack_handler() const { + return h_v5_connack_; + } + + /** + * @brief Set publish handler + * @return handler + */ + v5_publish_handler const& get_v5_publish_handler() const { + return h_v5_publish_; + } + + /** + * @brief Get puback handler + * @return handler + */ + v5_puback_handler const& get_v5_puback_handler() const { + return h_v5_puback_; + } + + /** + * @brief Get pubrec handler + * @return handler + */ + v5_pubrec_handler const& get_v5__handler() const { + return h_v5_pubrec_; + } + + /** + * @brief Get pubrel handler + * @return handler + */ + v5_pubrel_handler const& get_v5_pubrel_handler() const { + return h_v5_pubrel_; + } + + /** + * @brief Get pubcomp handler + * @return handler + */ + v5_pubcomp_handler const& get_v5_pubcomp_handler() const { + return h_v5_pubcomp_; + } + + /** + * @brief Get subscribe handler + * @return handler + */ + v5_subscribe_handler const& get_v5_subscribe_handler() const { + return h_v5_subscribe_; + } + + /** + * @brief Get suback handler + * @return handler + */ + v5_suback_handler const& get_v5_suback_handler() const { + return h_v5_suback_; + } + + /** + * @brief Get unsubscribe handler + * @return handler + */ + v5_unsubscribe_handler const& get_v5_unsubscribe_handler() const { + return h_v5_unsubscribe_; + } + + /** + * @brief Get unsuback handler + * @return handler + */ + v5_unsuback_handler const& get_v5_unsuback_handler() const { + return h_v5_unsuback_; + } + + /** + * @brief Get disconnect handler + * @return handler + */ + v5_disconnect_handler const& get_v5_disconnect_handler() const { + return h_v5_disconnect_; + } + + /** + * @brief Get auth handler + * @return handler + */ + v5_auth_handler const& get_v5_auth_handler() const { + return h_v5_auth_; + } + + + // Original handlers + + /** + * @brief Set pubcomp handler + * @param h handler + */ + void set_pub_res_sent_handler(pub_res_sent_handler h = pub_res_sent_handler()) { + h_pub_res_sent_ = force_move(h); + } + + /** + * @brief Set serialize handlers + * @param h_publish serialize handler for publish message + * @param h_pubrel serialize handler for pubrel message + * @param h_remove remove handler for serialized message + */ + void set_serialize_handlers( + serialize_publish_message_handler h_publish, + serialize_pubrel_message_handler h_pubrel, + serialize_remove_handler h_remove) { + h_serialize_publish_ = force_move(h_publish); + h_serialize_pubrel_ = force_move(h_pubrel); + h_serialize_remove_ = force_move(h_remove); + } + + /** + * @brief Set serialize handlers + * @param h_publish serialize handler for publish message + * @param h_pubrel serialize handler for pubrel message + * @param h_remove remove handler for serialized message + */ + void set_v5_serialize_handlers( + serialize_v5_publish_message_handler h_publish, + serialize_v5_pubrel_message_handler h_pubrel, + serialize_remove_handler h_remove) { + h_serialize_v5_publish_ = force_move(h_publish); + h_serialize_v5_pubrel_ = force_move(h_pubrel); + h_serialize_remove_ = force_move(h_remove); + } + + /** + * @brief Set serialize handlers + * @param h_publish serialize handler for publish message + * @param h_pubrel serialize handler for pubrel message + * @param h_remove remove handler for serialized message + */ + void set_serialize_handlers( + serialize_publish_handler h_publish, + serialize_pubrel_handler h_pubrel, + serialize_remove_handler h_remove) { + h_serialize_publish_ = + [h_publish = force_move(h_publish)] + (basic_publish_message msg) { + if (h_publish) { + auto buf = msg.continuous_buffer(); + h_publish(msg.packet_id(), buf.data(), buf.size()); + } + }; + h_serialize_pubrel_ = + [h_pubrel = force_move(h_pubrel)] + (basic_pubrel_message msg) { + if (h_pubrel) { + auto buf = msg.continuous_buffer(); + h_pubrel(msg.packet_id(), buf.data(), buf.size()); + } + }; + h_serialize_remove_ = force_move(h_remove); + } + + /** + * @brief Set serialize handlers + * @param h_publish serialize handler for publish message + * @param h_pubrel serialize handler for pubrel message + * @param h_remove remove handler for serialized message + */ + void set_v5_serialize_handlers( + serialize_publish_handler h_publish, + serialize_pubrel_handler h_pubrel, + serialize_remove_handler h_remove) { + h_serialize_v5_publish_ = + [h_publish = force_move(h_publish)] + (v5::basic_publish_message msg) { + if (h_publish) { + auto buf = msg.continuous_buffer(); + h_publish(msg.packet_id(), buf.data(), buf.size()); + } + }; + h_serialize_v5_pubrel_ = + [h_pubrel = force_move(h_pubrel)] + (v5::basic_pubrel_message msg) { + if (h_pubrel) { + auto buf = msg.continuous_buffer(); + h_pubrel(msg.packet_id(), buf.data(), buf.size()); + } + }; + h_serialize_remove_ = force_move(h_remove); + } + + /** + * @brief Clear serialize handlers + */ + void set_serialize_handlers() { + h_serialize_publish_ = serialize_publish_message_handler(); + h_serialize_pubrel_ = serialize_pubrel_message_handler(); + h_serialize_v5_publish_ = serialize_v5_publish_message_handler(); + h_serialize_v5_pubrel_ = serialize_v5_pubrel_message_handler(); + h_serialize_remove_ = serialize_remove_handler(); + } + + /** + * @brief Set pre-send handler + * @param h handler + */ + void set_pre_send_handler(pre_send_handler h = pre_send_handler()) { + h_pre_send_ = force_move(h); + } + + /** + * @brief Set check length handler + * @param h handler + */ + void set_is_valid_length_handler(is_valid_length_handler h = is_valid_length_handler()) { + h_is_valid_length_ = force_move(h); + } + + /** + * @brief Get publish response sent handler + * @return handler + */ + pub_res_sent_handler const& get_pub_res_sent_handler() const { + return h_pub_res_sent_; + } + + /** + * @brief Get serialize publish handler + * @return handler + */ + serialize_publish_message_handler const& get_serialize_publish_message_handler() const { + return h_serialize_publish_; + } + + /** + * @brief Get serialize pubrel handler + * @return handler + */ + serialize_pubrel_message_handler const& get_serialize_pubrel_message_handler() const { + return h_serialize_pubrel_; + } + + /** + * @brief Get serialize publish handler + * @return handler + */ + serialize_v5_publish_message_handler const& get_serialize_v5_publish_message_handler() const { + return h_serialize_v5_publish_; + } + + /** + * @brief Get serialize pubrel handler + * @return handler + */ + serialize_v5_pubrel_message_handler const& get_serialize_v5_pubrel_message_handler() const { + return h_serialize_v5_pubrel_; + } + + /** + * @brief Get serialize remove handler + * @return handler + */ + serialize_remove_handler const& get_serialize_remove_handler() const { + return h_serialize_remove_; + } + + /** + * @brief Get pre-send handler + * @return handler + */ + pre_send_handler const& get_pre_send_handler() const { + return h_pre_send_; + } + + /** + * @brief Get check length handler + * @return handler + */ + is_valid_length_handler const& get_is_valid_length_handler() const { + return h_is_valid_length_; + } + + /** + * @brief Set custom mqtt_message_processed_handler. + * The default setting is calling async_read_control_packet_type(). + * (See endpoint() constructor). + * The typical usecase of this function is delaying the next + * message reading timing. + * In order to do that + * 1) store func parameter of the mqtt_message_processed_handler. + * 2) call async_read_next_message with the stored func if + * you are ready to read the next mqtt message. + * @param h mqtt_message_processed_handler. + */ + void set_mqtt_message_processed_handler( + mqtt_message_processed_handler h = mqtt_message_processed_handler()) { + if (h) { + h_mqtt_message_processed_ = force_move(h); + } + else { + h_mqtt_message_processed_ = {}; + } + } + + /** + * @brief Get mqtt_message_processed_handler. + * @return mqtt_message_processed_handler. + */ + mqtt_message_processed_handler get_mqtt_message_processed_handler() const { + return h_mqtt_message_processed_; + } + + /** + * @brief Set close handler + * @param h handler + */ + void set_close_handler(close_handler h = close_handler()) { + h_close_ = force_move(h); + } + + /** + * @brief Set error handler + * @param h handler + */ + void set_error_handler(error_handler h = error_handler()) { + h_error_ = force_move(h); + } + + /** + * @brief Get close handler + * @return handler + */ + close_handler get_close_handler() const { + return h_close_; + } + + /** + * @brief Get error handler + * @return handler + */ + error_handler get_error_handler() const { + return h_error_; + } + +private: + // MQTT common handlers + pingreq_handler h_pingreq_; + pingresp_handler h_pingresp_; + + // MQTT v3_1_1 handlers + connect_handler h_connect_; + connack_handler h_connack_; + publish_handler h_publish_; + puback_handler h_puback_; + pubrec_handler h_pubrec_; + pubrel_handler h_pubrel_; + pubcomp_handler h_pubcomp_; + subscribe_handler h_subscribe_; + suback_handler h_suback_; + unsubscribe_handler h_unsubscribe_; + unsuback_handler h_unsuback_; + disconnect_handler h_disconnect_; + + // MQTT v5 handlers + v5_connect_handler h_v5_connect_; + v5_connack_handler h_v5_connack_; + v5_publish_handler h_v5_publish_; + v5_puback_handler h_v5_puback_; + v5_pubrec_handler h_v5_pubrec_; + v5_pubrel_handler h_v5_pubrel_; + v5_pubcomp_handler h_v5_pubcomp_; + v5_subscribe_handler h_v5_subscribe_; + v5_suback_handler h_v5_suback_; + v5_unsubscribe_handler h_v5_unsubscribe_; + v5_unsuback_handler h_v5_unsuback_; + v5_disconnect_handler h_v5_disconnect_; + v5_auth_handler h_v5_auth_; + + // original handlers + close_handler h_close_; + error_handler h_error_; + pub_res_sent_handler h_pub_res_sent_; + serialize_publish_message_handler h_serialize_publish_; + serialize_v5_publish_message_handler h_serialize_v5_publish_; + serialize_pubrel_message_handler h_serialize_pubrel_; + serialize_v5_pubrel_message_handler h_serialize_v5_pubrel_; + serialize_remove_handler h_serialize_remove_; + pre_send_handler h_pre_send_; + is_valid_length_handler h_is_valid_length_; + mqtt_message_processed_handler h_mqtt_message_processed_; +}; // callable_overlay + +} // namespace MQTT_NS + +#endif // MQTT_CALLABLE_OVERLAY_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/client.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/client.hpp new file mode 100644 index 000000000..939252801 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/client.hpp @@ -0,0 +1,2372 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CLIENT_HPP) +#define MQTT_CLIENT_HPP + +#include // should be top to configure variant limit + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; +namespace mi = boost::multi_index; + +template +class client : public endpoint { + using this_type = client; + using base = endpoint; +protected: + struct constructor_access{}; +public: + using async_handler_t = typename base::async_handler_t; + + /** + * Constructor used by factory functions at the end of this file. + */ + template + explicit client(constructor_access, Args && ... args) + : client(std::forward(args)...) + { } + + /** + * @brief Create no tls client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > + make_client(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create no tls client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > + make_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object. + * strand is controlled by ws_endpoint, not endpoint, so client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > + make_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > + make_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + /** + * @brief Create tls client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > + make_tls_client(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create tls client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > + make_tls_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object. + * strand is controlled by ws_endpoint, not endpoint, so client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + strand + > + > + > + > + make_tls_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > + make_tls_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) +#endif // defined(MQTT_USE_TLS) + + /** + * @brief Create no tls client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > + make_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create no tls client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > + make_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object. + * strand is controlled by ws_endpoint, not endpoint, so client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > + make_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > + make_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + /** + * @brief Create tls client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > + make_tls_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create tls client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > + make_tls_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object. + * strand is controlled by ws_endpoint, not endpoint, so client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > + make_tls_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return client object + */ + friend std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > + make_tls_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) +#endif // defined(MQTT_USE_TLS) + + /** + * @brief Set host. + * @param host host to connect + * + * The host is used from the next connect() or async_connect() call. + */ + void set_host(std::string host) { + host_ = force_move(host); + } + + /** + * @brief Set port. + * @param port port tp connect + * + * The port is used from the next connect() or async_connect() call. + */ + void set_port(std::string port) { + port_ = force_move(port); + } + + /** + * @brief Set clean session. + * @param cs clean session + * + * This function should be called before calling connect().
+ * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349231
+ * 3.1.2.4 Clean Session
+ * After constructing a endpoint, the clean session is set to false. + */ + void set_clean_session(bool cs) { + set_clean_start(cs); + } + + /** + * @brief Set clean start. + * @param cs clean start + * + * This function should be called before calling connect().
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039
+ * 3.1.2.4 Clean Start
+ * After constructing a endpoint, the clean start is set to false. + */ + void set_clean_start(bool cs) { + base::clean_start_ = cs; + } + + /** + * @brief Set username. + * @param name username + * + * This function should be called before calling connect().
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.5 User Name + */ + void set_user_name(std::string name) { + user_name_ = force_move(name); + } + + /** + * @brief Set password. + * @param password password + * + * This function should be called before calling connect().
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.6 Password + */ + void set_password(std::string password) { + password_ = force_move(password); + } + + /** + * @brief Set will. + * @param w will + * + * This function should be called before calling connect().
+ * 'will' would be send when endpoint is disconnected without calling disconnect(). + */ + void set_will(will w) { + will_ = force_move(w); + } + + /** + * @brief Clear will. + * + * This function should be called before calling connect().
+ */ + void set_will() { + will_ = nullopt; + } + + template + void set_will(Args && ... args) { + will_.emplace(std::forward(args)...); + } + +#if defined(MQTT_USE_TLS) + + /** + * @brief Get boost asio ssl context. + * @return ssl context + */ + tls::context& get_ssl_context() { + static_assert(has_tls>::value, "Client is required to support TLS."); + return ctx_; + } + + /** + * @brief Get boost asio ssl context. + * @return ssl context + */ + tls::context const& get_ssl_context() const { + static_assert(has_tls>::value, "Client is required to support TLS."); + return ctx_; + } + +#endif // defined(MQTT_USE_TLS) + + + /** + * @brief Set a keep alive second and a ping duration. + * @param keep_alive_sec keep alive seconds + * @param ping_ms ping sending interval + * + * When a endpoint connects to a broker, the endpoint notifies keep_alive_sec to + * the broker. + * After connecting, the broker starts counting a timeout, and the endpoint starts + * sending ping packets for each ping_ms. + * When the broker receives a ping packet, timeout timer is reset. + * If the broker doesn't receive a ping packet within keep_alive_sec, the endpoint + * is disconnected.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc464635115
+ * 3.1.2.10 Keep Alive + */ + void set_keep_alive_sec(std::uint16_t keep_alive_sec, std::chrono::steady_clock::duration ping) { + if ((ping_duration_ != std::chrono::steady_clock::duration::zero()) && base::connected() && (ping == std::chrono::steady_clock::duration::zero())) { + tim_ping_.cancel(); + } + keep_alive_sec_ = keep_alive_sec; + ping_duration_ = force_move(ping); + } + + /** + * @brief Set a keep alive second and a ping milli seconds. + * @param keep_alive_sec keep alive seconds + * @param ping_ms ping sending interval + * + * When a endpoint connects to a broker, the endpoint notifies keep_alive_sec to + * the broker. + * After connecting, the broker starts counting a timeout, and the endpoint starts + * sending ping packets for each ping_ms. + * When the broker receives a ping packet, timeout timer is reset. + * If the broker doesn't receive a ping packet within keep_alive_sec, the endpoint + * is disconnected.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc464635115
+ * 3.1.2.10 Keep Alive + */ + void set_keep_alive_sec_ping_ms(std::uint16_t keep_alive_sec, std::size_t ping_ms) { + set_keep_alive_sec(keep_alive_sec, std::chrono::milliseconds(ping_ms)); + } + + /** + * @brief Set a keep alive second and a ping milli seconds. + * @param keep_alive_sec keep alive seconds + * + * Call set_keep_alive_sec(keep_alive_sec, std::chrono::seconds(keep_alive_sec / 2))
+ * ping_ms is set to a half of keep_alive_sec.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc464635115
+ * 3.1.2.10 Keep Alive + */ + void set_keep_alive_sec(std::uint16_t keep_alive_sec) { + set_keep_alive_sec(keep_alive_sec, std::chrono::seconds(keep_alive_sec / 2)); + } + + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect(any session_life_keeper = any()) { + connect(v5::properties{}, force_move(session_life_keeper)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param ec error code + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect(boost::system::error_code& ec, any session_life_keeper = any()) { + connect(v5::properties{}, ec, force_move(session_life_keeper)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect(v5::properties props, any session_life_keeper = any()) { + setup_socket(socket_); + connect_impl(force_move(props), force_move(session_life_keeper)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param ec error code + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect( + v5::properties props, + boost::system::error_code& ec, + any session_life_keeper = any()) { + setup_socket(socket_); + connect_impl(force_move(props), force_move(session_life_keeper), ec); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect(std::shared_ptr&& socket, any session_life_keeper = any()) { + connect(force_move(socket), v5::properties{}, force_move(session_life_keeper)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param ec error code + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect( + std::shared_ptr&& socket, + boost::system::error_code& ec, + any session_life_keeper = any()) { + connect(force_move(socket), v5::properties{}, ec, force_move(session_life_keeper)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect( + std::shared_ptr&& socket, + v5::properties props, + any session_life_keeper = any()) { + socket_ = force_move(socket); + base::socket_sp_ref() = socket_; + connect_impl(force_move(props), force_move(session_life_keeper)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param ec error code + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + void connect( + std::shared_ptr&& socket, + v5::properties props, + boost::system::error_code& ec, + any session_life_keeper = any()) { + socket_ = force_move(socket); + base::socket_sp_ref() = socket_; + connect_impl(force_move(props), force_move(session_life_keeper), ec); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + */ + void async_connect() { + async_connect(any(), async_handler_t()); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + template + // to avoid ambiguousness between any and async_handler_t + std::enable_if_t< + !std::is_convertible::value + > + async_connect(T session_life_keeper) { + async_connect(force_move(session_life_keeper), async_handler_t()); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(async_handler_t func) { + async_connect(any(), force_move(func)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param session_life_keeper the passed object lifetime will be kept during the session. + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(any session_life_keeper, async_handler_t func) { + async_connect(v5::properties{}, force_move(session_life_keeper), force_move(func)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + template + // to avoid ambiguousness between any and async_handler_t + std::enable_if_t< + !std::is_convertible::value + > + async_connect(v5::properties props, T session_life_keeper) { + async_connect(force_move(props), force_move(session_life_keeper), async_handler_t()); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(v5::properties props, async_handler_t func) { + async_connect(force_move(props), any(), force_move(func)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param session_life_keeper the passed object lifetime will be kept during the session. + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(v5::properties props, any session_life_keeper, async_handler_t func) { + setup_socket(socket_); + async_connect_impl(force_move(props), force_move(session_life_keeper), force_move(func)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + */ + void async_connect(std::shared_ptr&& socket) { + async_connect(force_move(socket), v5::properties{}, any(), async_handler_t()); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + template + // to avoid ambiguousness between any and async_handler_t + std::enable_if_t< + !std::is_convertible::value + > + async_connect(std::shared_ptr&& socket, T session_life_keeper) { + async_connect(force_move(socket), v5::properties{}, force_move(session_life_keeper), async_handler_t()); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(std::shared_ptr&& socket, async_handler_t func) { + async_connect(force_move(socket), v5::properties{}, any(), force_move(func)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param session_life_keeper the passed object lifetime will be kept during the session. + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(std::shared_ptr&& socket, any session_life_keeper, async_handler_t func) { + async_connect(force_move(socket), v5::properties{}, force_move(session_life_keeper), force_move(func)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + */ + void async_connect(std::shared_ptr&& socket, v5::properties props) { + async_connect(force_move(socket), force_move(props), any(), async_handler_t()); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param session_life_keeper the passed object lifetime will be kept during the session. + */ + template + // to avoid ambiguousness between any and async_handler_t + std::enable_if_t< + !std::is_convertible::value + > + async_connect(std::shared_ptr&& socket, v5::properties props, T session_life_keeper) { + async_connect(force_move(socket), force_move(props), force_move(session_life_keeper), async_handler_t()); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(std::shared_ptr&& socket, v5::properties props, async_handler_t func) { + async_connect(force_move(socket), force_move(props), any(), force_move(func)); + } + + /** + * @brief Connect to a broker + * Before calling connect(), call set_xxx member functions to configure the connection. + * @param socket The library uses the socket instead of internal generation. + * You can configure the socket prior to connect. + * @param props properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param session_life_keeper the passed object lifetime will be kept during the session. + * @param func finish handler that is called when the underlying connection process is finished + */ + void async_connect(std::shared_ptr&& socket, v5::properties props, any session_life_keeper, async_handler_t func) { + socket_ = force_move(socket); + base::socket_sp_ref() = socket_; + async_connect_impl(force_move(props), force_move(session_life_keeper), force_move(func)); + } + + /** + * @brief Disconnect + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * @param timeout after timeout elapsed, force_disconnect() is automatically called. + * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + */ + void disconnect( + std::chrono::steady_clock::duration timeout, + v5::disconnect_reason_code reason_code = v5::disconnect_reason_code::normal_disconnection, + v5::properties props = {} + ) { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + if (base::connected()) { + std::weak_ptr wp(std::static_pointer_cast(this->shared_from_this())); + tim_close_.expires_after(force_move(timeout)); + tim_close_.async_wait( + [wp = force_move(wp)](error_code ec) { + if (auto sp = wp.lock()) { + if (!ec) { + sp->socket()->post( + [sp] { + sp->force_disconnect(); + } + ); + } + } + } + ); + base::disconnect(reason_code, force_move(props)); + } + } + + /** + * @brief Disconnect + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + */ + void disconnect( + v5::disconnect_reason_code reason_code = v5::disconnect_reason_code::normal_disconnection, + v5::properties props = {} + ) { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + if (base::connected()) { + base::disconnect(reason_code, force_move(props)); + } + } + + /** + * @brief Disconnect + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * @param timeout after timeout elapsed, force_disconnect() is automatically called. + * @param func A callback function that is called when async operation will finish. + */ + void async_disconnect( + std::chrono::steady_clock::duration timeout, + async_handler_t func = async_handler_t()) { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + if (base::connected()) { + std::weak_ptr wp(std::static_pointer_cast(this->shared_from_this())); + tim_close_.expires_after(force_move(timeout)); + tim_close_.async_wait( + [wp = force_move(wp)](error_code ec) { + if (auto sp = wp.lock()) { + if (!ec) { + sp->socket()->post( + [sp] { + sp->force_disconnect(); + } + ); + } + } + } + ); + base::async_disconnect(force_move(func)); + } + } + + /** + * @brief Disconnect + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * @param timeout after timeout elapsed, force_disconnect() is automatically called. + * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + * @param func A callback function that is called when async operation will finish. + */ + void async_disconnect( + std::chrono::steady_clock::duration timeout, + v5::disconnect_reason_code reason_code, + v5::properties props, + async_handler_t func = async_handler_t()) { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + if (base::connected()) { + std::weak_ptr wp(std::static_pointer_cast(this->shared_from_this())); + tim_close_.expires_after(force_move(timeout)); + tim_close_.async_wait( + [wp = force_move(wp)](error_code ec) { + if (auto sp = wp.lock()) { + if (!ec) { + sp->socket()->post( + [sp] { + sp->force_disconnect(); + } + ); + } + } + } + ); + base::async_disconnect(reason_code, force_move(props), force_move(func)); + } + } + + /** + * @brief Disconnect + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * @param func A callback function that is called when async operation will finish. + */ + void async_disconnect( + async_handler_t func = async_handler_t()) { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + if (base::connected()) { + base::async_disconnect(force_move(func)); + } + } + + /** + * @brief Disconnect + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + * @param func A callback function that is called when async operation will finish. + */ + void async_disconnect( + v5::disconnect_reason_code reason_code, + v5::properties props, + async_handler_t func = async_handler_t()) { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + if (base::connected()) { + base::async_disconnect(reason_code, force_move(props), force_move(func)); + } + } + + /** + * @brief Disconnect by endpoint + * Force disconnect. It is not a clean disconnect sequence.
+ * When the endpoint disconnects using force_disconnect(), a will will send.
+ */ + void force_disconnect() { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + tim_close_.cancel(); + base::force_disconnect(); + } + + /** + * @brief Disconnect by endpoint + * @param func A callback function that is called when async operation will finish. + * Force disconnect. It is not a clean disconnect sequence.
+ * When the endpoint disconnects using force_disconnect(), a will will send.
+ */ + void async_force_disconnect( + async_handler_t func = async_handler_t()) { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + tim_close_.cancel(); + base::async_force_disconnect(force_move(func)); + } + + std::shared_ptr const& socket() const { + return socket_; + } + + std::shared_ptr& socket() { + return socket_; + } + +protected: + client(as::io_context& ioc, + std::string host, + std::string port +#if defined(MQTT_USE_WS) + , + std::string path = "/" +#endif // defined(MQTT_USE_WS) + , + protocol_version version = protocol_version::v3_1_1, + bool async_operation = false + ) + :base(ioc, version, async_operation), + ioc_(ioc), + tim_ping_(ioc_), + tim_close_(ioc_), + host_(force_move(host)), + port_(force_move(port)), + async_operation_(async_operation) +#if defined(MQTT_USE_WS) + , + path_(force_move(path)) +#endif // defined(MQTT_USE_WS) + { +#if defined(MQTT_USE_TLS) + ctx_.set_verify_mode(tls::verify_peer); +#endif // defined(MQTT_USE_TLS) + setup_socket(socket_); + } + +private: + template + void setup_socket(std::shared_ptr>& socket) { + socket = std::make_shared(ioc_); + base::socket_sp_ref() = socket; + } + +#if defined(MQTT_USE_WS) + template + void setup_socket(std::shared_ptr>& socket) { + socket = std::make_shared(ioc_); + base::socket_sp_ref() = socket; + } +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + template + void setup_socket(std::shared_ptr, Strand>>& socket) { + socket = std::make_shared(ioc_, ctx_); + base::socket_sp_ref() = socket; + } + +#if defined(MQTT_USE_WS) + template + void setup_socket(std::shared_ptr, Strand>>& socket) { + socket = std::make_shared(ioc_, ctx_); + base::socket_sp_ref() = socket; + } +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + void start_session(v5::properties props, any session_life_keeper) { + base::async_read_control_packet_type(force_move(session_life_keeper)); + // sync base::connect() refer to parameters only in the function. + // So they can be passed as view. + base::connect( + buffer(string_view(base::get_client_id())), + ( user_name_ ? buffer(string_view(user_name_.value())) + : optional() ), + ( password_ ? buffer(string_view(password_.value())) + : optional() ), + will_, + keep_alive_sec_, + force_move(props) + ); + } + + void async_start_session(v5::properties props, any session_life_keeper, async_handler_t func) { + base::async_read_control_packet_type(force_move(session_life_keeper)); + // sync base::connect() refer to parameters only in the function. + // So they can be passed as view. + base::async_connect( + buffer(string_view(base::get_client_id())), + ( user_name_ ? buffer(string_view(user_name_.value())) + : optional() ), + ( password_ ? buffer(string_view(password_.value())) + : optional() ), + will_, + keep_alive_sec_, + force_move(props), + force_move(func) + ); + } + + template + void handshake_socket( + tcp_endpoint&, + v5::properties props, + any session_life_keeper) { + start_session(force_move(props), force_move(session_life_keeper)); + } + + template + void handshake_socket( + tcp_endpoint&, + v5::properties props, + any session_life_keeper, + boost::system::error_code& ec) { + start_session(force_move(props), force_move(session_life_keeper)); + ec = boost::system::errc::make_error_code(boost::system::errc::success); + } + +#if defined(MQTT_USE_WS) + + template + void handshake_socket( + ws_endpoint& socket, + v5::properties props, + any session_life_keeper) { + socket.handshake(host_, path_); + start_session(force_move(props), force_move(session_life_keeper)); + } + + template + void handshake_socket( + ws_endpoint& socket, + v5::properties props, + any session_life_keeper, + boost::system::error_code& ec) { + socket.handshake(host_, path_, ec); + if (ec) return; + start_session(force_move(props), force_move(session_life_keeper)); + } + +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + + template + void handshake_socket( + tcp_endpoint, Strand>& socket, + v5::properties props, + any session_life_keeper) { + socket.handshake(tls::stream_base::client); + start_session(force_move(props), force_move(session_life_keeper)); + } + + template + void handshake_socket( + tcp_endpoint, Strand>& socket, + v5::properties props, + any session_life_keeper, + boost::system::error_code& ec) { + socket.handshake(tls::stream_base::client, ec); + if (ec) return; + start_session(force_move(props), force_move(session_life_keeper)); + } + +#if defined(MQTT_USE_WS) + + template + void handshake_socket( + ws_endpoint, Strand>& socket, + v5::properties props, + any session_life_keeper) { + socket.next_layer().handshake(tls::stream_base::client); + socket.handshake(host_, path_); + start_session(force_move(props), force_move(session_life_keeper)); + } + + template + void handshake_socket( + ws_endpoint, Strand>& socket, + v5::properties props, + any session_life_keeper, + boost::system::error_code& ec) { + socket.next_layer().handshake(tls::stream_base::client, ec); + if (ec) return; + socket.handshake(host_, path_, ec); + if (ec) return; + start_session(force_move(props), force_move(session_life_keeper)); + } + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + template + void async_handshake_socket( + tcp_endpoint&, + v5::properties props, + any session_life_keeper, + async_handler_t func) { + async_start_session(force_move(props), force_move(session_life_keeper), force_move(func)); + } + +#if defined(MQTT_USE_WS) + template + void async_handshake_socket( + ws_endpoint& socket, + v5::properties props, + any session_life_keeper, + async_handler_t func) { + socket.async_handshake( + host_, + path_, + [ + this, + self = this->shared_from_this(), + session_life_keeper = force_move(session_life_keeper), + props = force_move(props), + func = force_move(func) + ] + (error_code ec) mutable { + if (ec) { + if (func) func(ec); + return; + } + async_start_session(force_move(props), force_move(session_life_keeper), force_move(func)); + }); + } +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + + template + void async_handshake_socket( + tcp_endpoint, Strand>& socket, + v5::properties props, + any session_life_keeper, + async_handler_t func) { + socket.async_handshake( + tls::stream_base::client, + [ + this, + self = this->shared_from_this(), + session_life_keeper = force_move(session_life_keeper), + props = force_move(props), + func = force_move(func) + ] + (error_code ec) mutable { + if (ec) { + if (func) func(ec); + return; + } + async_start_session(force_move(props), force_move(session_life_keeper), force_move(func)); + }); + } + +#if defined(MQTT_USE_WS) + template + void async_handshake_socket( + ws_endpoint, Strand>& socket, + v5::properties props, + any session_life_keeper, + async_handler_t func) { + socket.next_layer().async_handshake( + tls::stream_base::client, + [ + this, + self = this->shared_from_this(), + session_life_keeper = force_move(session_life_keeper), + &socket, + props = force_move(props), + func = force_move(func) + ] + (error_code ec) mutable { + if (ec) { + if (func) func(ec); + return; + } + socket.async_handshake( + host_, + path_, + [ + this, + self, + session_life_keeper = force_move(session_life_keeper), + props = force_move(props), + func = force_move(func) + ] + (error_code ec) mutable { + if (ec) { + if (func) func(ec); + return; + } + async_start_session(force_move(props), force_move(session_life_keeper), force_move(func)); + }); + }); + } +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + void connect_impl( + v5::properties props, + any session_life_keeper) { + as::ip::tcp::resolver r(ioc_); + auto eps = r.resolve(host_, port_); + as::connect(socket_->lowest_layer(), eps.begin(), eps.end()); + base::set_connect(); + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) { + set_timer(); + } + handshake_socket(*socket_, force_move(props), force_move(session_life_keeper)); + } + + void connect_impl( + v5::properties props, + any session_life_keeper, + boost::system::error_code& ec) { + as::ip::tcp::resolver r(ioc_); + auto eps = r.resolve(host_, port_, ec); + if (ec) return; + as::connect(socket_->lowest_layer(), eps.begin(), eps.end(), ec); + if (ec) return; + base::set_connect(); + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) { + set_timer(); + } + handshake_socket(*socket_, force_move(props), force_move(session_life_keeper), ec); + } + + void async_connect_impl( + v5::properties props, + any session_life_keeper, + async_handler_t func) { + auto r = std::make_shared(ioc_); + auto p = r.get(); + p->async_resolve( + host_, + port_, + [ + this, + self = this->shared_from_this(), + props = force_move(props), + session_life_keeper = force_move(session_life_keeper), + func = force_move(func), + r = force_move(r) + ] + ( + error_code ec, + as::ip::tcp::resolver::results_type eps + ) mutable { + if (ec) { + if (func) func(ec); + return; + } + as::async_connect( + socket_->lowest_layer(), eps.begin(), eps.end(), + [ + this, + self = force_move(self), + props = force_move(props), + session_life_keeper = force_move(session_life_keeper), + func = force_move(func) + ] + (error_code ec, auto /* unused */) mutable { + if (ec) { + if (func) func(ec); + return; + } + base::set_connect(); + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) { + set_timer(); + } + async_handshake_socket(*socket_, force_move(props), force_move(session_life_keeper), force_move(func)); + } + ); + } + ); + } + +protected: + void on_pre_send() noexcept override { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) { + reset_timer(); + } + } + +private: + void handle_timer(error_code ec) { + if (!ec) { + if (async_operation_) { + base::async_pingreq(); + } + else { + base::pingreq(); + } + } + } + + void set_timer() { + tim_ping_.expires_after(ping_duration_); + std::weak_ptr wp(std::static_pointer_cast(this->shared_from_this())); + tim_ping_.async_wait( + [wp = force_move(wp)](error_code ec) { + if (auto sp = wp.lock()) { + sp->handle_timer(ec); + } + } + ); + } + + void reset_timer() { + tim_ping_.cancel(); + set_timer(); + } + +protected: + void on_close() noexcept override { + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + } + + void on_error(error_code ec) noexcept override { + (void)ec; + if (ping_duration_ != std::chrono::steady_clock::duration::zero()) tim_ping_.cancel(); + } + + // Ensure that only code that knows the *exact* type of an object + // inheriting from this abstract base class can destruct it. + // This avoids issues of the destructor not triggering destruction + // of derived classes, and any member variables contained in them. + // Note: Not virtual to avoid need for a vtable when possible. + ~client() = default; + +private: + +#if defined(MQTT_USE_TLS) + + template + struct has_tls : std::false_type { + }; + + template + struct has_tls, U>>> : std::true_type { + }; + +#if defined(MQTT_USE_WS) + + template + struct has_tls, U>>> : std::true_type { + }; + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + std::shared_ptr socket_; + as::io_context& ioc_; + as::steady_timer tim_ping_; + as::steady_timer tim_close_; + std::string host_; + std::string port_; + std::uint16_t keep_alive_sec_{0}; + std::chrono::steady_clock::duration ping_duration_{std::chrono::steady_clock::duration::zero()}; + optional will_; + optional user_name_; + optional password_; + bool async_operation_ = false; +#if defined(MQTT_USE_TLS) + tls::context ctx_{tls::context::tlsv12}; +#endif // defined(MQTT_USE_TLS) +#if defined(MQTT_USE_WS) + std::string path_; +#endif // defined(MQTT_USE_WS) +}; + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_client(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_client(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_client( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_client_no_strand(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_client_no_strand( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_client_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_client_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_client_no_strand_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_client_no_strand_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_client(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + tls::stream, + strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_client(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_client( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + tls::stream, + null_strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_client_no_strand(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_client_no_strand( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + tls::stream, + strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_client_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_client_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + tls::stream, + null_strand + > + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_client_no_strand_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_client_no_strand_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + +// 32bit Packet Id (experimental) + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_client_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_client_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_client_no_strand_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_client_no_strand_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_client_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_client_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_client_no_strand_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_client_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_client_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_client_no_strand_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_client_no_strand_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + tls::stream, + strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_client_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_client_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using client_t = client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + >; + return std::make_shared>( + client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_client_no_strand_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + +} // namespace MQTT_NS + +#endif // MQTT_CLIENT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/config.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/config.hpp new file mode 100644 index 000000000..7b6ddd587 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/config.hpp @@ -0,0 +1,57 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CONFIG_HPP) +#define MQTT_CONFIG_HPP + +#if !defined(MQTT_STD_VARIANT) + +// Use boost variant + +// user intentionally defined BOOST_MPL_LIMIT_LIST_SIZE but size is too small +// NOTE: if BOOST_MPL_LIMIT_LIST_SIZE is not defined, the value is evaluate as 0. +#if defined(BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS) && BOOST_MPL_LIMIT_LIST_SIZE < 40 + +#error BOOST_MPL_LIMIT_LIST_SIZE need to greator or equal to 40 + +#else // defined(BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS) && BOOST_MPL_LIMIT_LIST_SIZE < 40 + +// user doesn't define BOOST_MPL_LIMIT_LIST_SIZE intentionally +// but the defult value could be defined + +#undef BOOST_MPL_LIMIT_LIST_SIZE +#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS +#define BOOST_MPL_LIMIT_LIST_SIZE 40 + +#endif // defined(BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS) && BOOST_MPL_LIMIT_LIST_SIZE < 40 + + +#endif // !defined(MQTT_STD_VARIANT) + + +// Check whether to use standard executors only +#if defined(MQTT_NO_TS_EXECUTORS) + +// Determine Boost Asio version +#include + +// Make sure standard executors are supported by Boost Asio +#if BOOST_ASIO_VERSION < 101800 +#error Boost Asio version 1.18.0 required for no TS-style executors +#endif // BOOST_ASIO_VERSION < 101800 + +#else // defined(MQTT_NO_TS_EXECUTORS) + +// Force no TS executors if Boost Asio accepts these only +#if defined(BOOST_ASIO_NO_TS_EXECUTORS) +#define MQTT_NO_TS_EXECUTORS +#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS) + +#endif // defined(MQTT_NO_TS_EXECUTORS) + +#define BOOST_UUID_FORCE_AUTO_LINK + +#endif // MQTT_CONFIG_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/connect_flags.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/connect_flags.hpp new file mode 100644 index 000000000..108a94c71 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/connect_flags.hpp @@ -0,0 +1,63 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CONNECT_FLAGS_HPP) +#define MQTT_CONNECT_FLAGS_HPP + +#include +#include +#include + +namespace MQTT_NS { + +namespace connect_flags { + +constexpr char const clean_session = 0b00000010; +constexpr char const clean_start = 0b00000010; +constexpr char const will_flag = 0b00000100; +constexpr char const will_retain = 0b00100000; +constexpr char const password_flag = 0b01000000; +constexpr char const user_name_flag = static_cast(0b10000000u); + +constexpr bool has_clean_session(char v) { + return (v & clean_session) != 0; +} + +constexpr bool has_clean_start(char v) { + return (v & clean_start) != 0; +} + +constexpr bool has_will_flag(char v) { + return (v & will_flag) != 0; +} + +constexpr retain has_will_retain(char v) { + return ((v & will_retain) != 0) + ? retain::yes + : retain::no; +} + +constexpr bool has_password_flag(char v) { + return (v & password_flag) != 0; +} + +constexpr bool has_user_name_flag(char v) { + return (v & user_name_flag) != 0; +} + +constexpr void set_will_qos(char& v, qos qos_value) { + v |= static_cast(static_cast(qos_value) << 3); +} + +constexpr qos will_qos(char v) { + return static_cast((v & 0b00011000) >> 3); +} + +} // namespace connect_flags + +} // namespace MQTT_NS + +#endif // MQTT_CONNECT_FLAGS_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/connect_return_code.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/connect_return_code.hpp new file mode 100644 index 000000000..6b0d504f5 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/connect_return_code.hpp @@ -0,0 +1,51 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CONNECT_RETURN_CODE_HPP) +#define MQTT_CONNECT_RETURN_CODE_HPP + +#include +#include + +#include + +namespace MQTT_NS { + +enum class connect_return_code : std::uint8_t { + + accepted = 0, + unacceptable_protocol_version = 1, + identifier_rejected = 2, + server_unavailable = 3, + bad_user_name_or_password = 4, + not_authorized = 5, + +}; + +constexpr +char const* connect_return_code_to_str(connect_return_code v) { + char const * const str[] = { + "accepted", + "unacceptable_protocol_version", + "identifier_rejected", + "server_unavailable", + "bad_user_name_or_password", + "not_authorized" + }; + if (static_cast(v) < sizeof(str)) return str[static_cast(v)]; + return "unknown_connect_return_code"; +} + +inline +std::ostream& operator<<(std::ostream& os, connect_return_code val) +{ + os << connect_return_code_to_str(val); + return os; +} + +} // namespace MQTT_NS + +#endif // MQTT_CONNECT_RETURN_CODE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/const_buffer_util.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/const_buffer_util.hpp new file mode 100644 index 000000000..52599aa62 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/const_buffer_util.hpp @@ -0,0 +1,27 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CONST_BUFFER_UTIL_HPP) +#define MQTT_CONST_BUFFER_UTIL_HPP + +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +inline char const* get_pointer(as::const_buffer const& cb) { + return static_cast(cb.data()); +} + +inline std::size_t get_size(as::const_buffer const& cb) { + return cb.size(); +} + +} // namespace MQTT_NS + +#endif // MQTT_CONST_BUFFER_UTIL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/constant.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/constant.hpp new file mode 100644 index 000000000..3b9b748bc --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/constant.hpp @@ -0,0 +1,29 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CONSTANT_HPP) +#define MQTT_CONSTANT_HPP + +#include +#include + +#include +#include + +namespace MQTT_NS { + +static constexpr session_expiry_interval_t session_never_expire = 0xffffffffUL; +static constexpr topic_alias_t topic_alias_max = 0xffff; +static constexpr std::size_t packet_size_no_limit = + 1 + // fixed header + 4 + // remaining length + 128 * 128 * 128 * 128; // maximum value of remainin length +static constexpr receive_maximum_t receive_maximum_max = 0xffff; +static constexpr auto shutdown_timeout = std::chrono::seconds(3); + +} // namespace MQTT_NS + +#endif // MQTT_CONSTANT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/control_packet_type.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/control_packet_type.hpp new file mode 100644 index 000000000..9d82c18e9 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/control_packet_type.hpp @@ -0,0 +1,138 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_CONTROL_PACKET_TYPE_HPP) +#define MQTT_CONTROL_PACKET_TYPE_HPP + +#include +#include + +#include +#include + +namespace MQTT_NS { + +enum class control_packet_type : std::uint8_t { + + // reserved = 0b0000000, + connect = 0b00010000, // 1 + connack = 0b00100000, // 2 + publish = 0b00110000, // 3 + puback = 0b01000000, // 4 + pubrec = 0b01010000, // 5 + pubrel = 0b01100000, // 6 + pubcomp = 0b01110000, // 7 + subscribe = 0b10000000, // 8 + suback = 0b10010000, // 9 + unsubscribe = 0b10100000, // 10 + unsuback = 0b10110000, // 11 + pingreq = 0b11000000, // 12 + pingresp = 0b11010000, // 13 + disconnect = 0b11100000, // 14 + auth = 0b11110000, // 15 + +}; + +constexpr control_packet_type get_control_packet_type(std::uint8_t v) { + return static_cast(v & 0b11110000); +} + +constexpr +char const* control_packet_type_to_str(control_packet_type v) { + switch(v) + { + // case control_packet_type::reserved: return "reserved"; + case control_packet_type::connect: return "connect"; + case control_packet_type::connack: return "connack"; + case control_packet_type::publish: return "publish"; + case control_packet_type::puback: return "puback"; + case control_packet_type::pubrec: return "pubrec"; + case control_packet_type::pubrel: return "pubrel"; + case control_packet_type::pubcomp: return "pubcomp"; + case control_packet_type::subscribe: return "subscribe"; + case control_packet_type::suback: return "suback"; + case control_packet_type::unsubscribe: return "unsubscribe"; + case control_packet_type::unsuback: return "unsuback"; + case control_packet_type::pingreq: return "pingreq"; + case control_packet_type::pingresp: return "pingresp"; + case control_packet_type::disconnect: return "disconnect"; + case control_packet_type::auth: return "auth"; + default: return "unknown_control_packet_type"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, control_packet_type val) +{ + os << control_packet_type_to_str(val); + return os; +} + +enum class control_packet_reserved_bits : std::uint8_t { + connect = 0b00000000, + connack = 0b00000000, + // publish = dup qos retain, + puback = 0b00000000, + pubrec = 0b00000000, + pubrel = 0b00000010, + pubcomp = 0b00000000, + subscribe = 0b00000010, + suback = 0b00000000, + unsubscribe = 0b00000010, + unsuback = 0b00000000, + pingreq = 0b00000000, + pingresp = 0b00000000, + disconnect = 0b00000000, + auth = 0b00000000, +}; + +inline optional get_control_packet_type_with_check(std::uint8_t v) { + auto cpt = static_cast(v & 0b11110000); + auto valid = + [&] { + auto rsv = static_cast(v & 0b00001111); + switch (cpt) { + case control_packet_type::connect: + return rsv == control_packet_reserved_bits::connect; + case control_packet_type::connack: + return rsv == control_packet_reserved_bits::connack; + case control_packet_type::publish: + return true; + case control_packet_type::puback: + return rsv == control_packet_reserved_bits::puback; + case control_packet_type::pubrec: + return rsv == control_packet_reserved_bits::pubrec; + case control_packet_type::pubrel: + return rsv == control_packet_reserved_bits::pubrel; + case control_packet_type::pubcomp: + return rsv == control_packet_reserved_bits::pubcomp; + case control_packet_type::subscribe: + return rsv == control_packet_reserved_bits::subscribe; + case control_packet_type::suback: + return rsv == control_packet_reserved_bits::suback; + case control_packet_type::unsubscribe: + return rsv == control_packet_reserved_bits::unsubscribe; + case control_packet_type::unsuback: + return rsv == control_packet_reserved_bits::unsuback; + case control_packet_type::pingreq: + return rsv == control_packet_reserved_bits::pingreq; + case control_packet_type::pingresp: + return rsv == control_packet_reserved_bits::pingresp; + case control_packet_type::disconnect: + return rsv == control_packet_reserved_bits::disconnect; + case control_packet_type::auth: + return rsv == control_packet_reserved_bits::auth; + default: + return false; + } + } (); + if (valid) return cpt; + return nullopt; +} + +} // namespace MQTT_NS + +#endif // MQTT_CONTROL_PACKET_TYPE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/deprecated.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/deprecated.hpp new file mode 100644 index 000000000..8383279b6 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/deprecated.hpp @@ -0,0 +1,36 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_DEPRECATED_HPP) +#define MQTT_DEPRECATED_HPP + +#if defined(MQTT_USE_DEPRECATED) + +#define MQTT_DEPRECATED(msg) // for test, ignore it + +#else // defined(MQTT_USE_DEPRECATED) + +#if __cplusplus >= 201402L + +#if defined(_MSC_VER) + +#define MQTT_DEPRECATED(msg) __declspec(deprecated(msg)) + +#else // _MSC_VER 1914+ with /Zc:__cplusplus, @see https://docs.microsoft.com/cpp/build/reference/zc-cplusplus + +#define MQTT_DEPRECATED(msg) [[deprecated(msg)]] + +#endif + +#else // __cplusplus >= 201402L + +#define MQTT_DEPRECATED(msg) + +#endif // __cplusplus >= 201402L + +#endif // defined(MQTT_USE_DEPRECATED) + +#endif // MQTT_DEPRECATED_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/deprecated_msg.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/deprecated_msg.hpp new file mode 100644 index 000000000..34b07e0e4 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/deprecated_msg.hpp @@ -0,0 +1,86 @@ +#if !defined(MQTT_DEPRECATED_MSG_HPP) +#define MQTT_DEPRECATED_MSG_HPP + +#define MQTT_DEPRECATED_MSG_SUBACK "Use\n" \ +"suback(\n" \ +" packet_id_t packet_id,\n" \ +" variant reason,\n" \ +" v5::properties props = {}\n" \ +")\n" \ +"or\n" \ +"suback(\n" \ +" packet_id_t packet_id,\n" \ +" variant, std::vector> reasons,\n" \ +" v5::properties props = {}\n" \ +")\n" + +#define MQTT_DEPRECATED_MSG_UNSUBACK "Use\n" \ +"unsuback(\n" \ +" packet_id_t packet_id,\n" \ +" variant reason,\n" \ +" v5::properties props = {}\n" \ +")\n" \ +"or\n" \ +"unsuback(\n" \ +" packet_id_t packet_id,\n" \ +" variant, std::vector> reasons,\n" \ +" v5::properties props = {}\n" \ +")\n" + +#define MQTT_DEPRECATED_MSG_ASYNC_SUBACK "Use\n" \ +"async_suback(\n" \ +" packet_id_t packet_id,\n" \ +" variant reason,\n" \ +" any session_life_keeper = any()\n" \ +")\n" \ +"or\n" \ +"async_suback(\n" \ +" packet_id_t packet_id,\n" \ +" variant reason,\n" \ +" v5::properties props,\n" \ +" any session_life_keeper = any()\n" \ +")\n" \ +"or\n" \ +"async_suback(\n" \ +" packet_id_t packet_id,\n" \ +" variant, std::vector> reasons,\n" \ +" any session_life_keeper = any()\n" \ +")\n" \ +"or\n" \ +"async_suback(\n" \ +" packet_id_t packet_id,\n" \ +" variant, std::vector> reasons,\n" \ +" v5::properties props,\n" \ +" any session_life_keeper = any()\n" \ +")\n" + +#define MQTT_DEPRECATED_MSG_ASYNC_UNSUBACK "Use\n" \ +"async_unsuback(\n" \ +" packet_id_t packet_id,\n" \ +" variant reason,\n" \ +" any session_life_keeper = any()\n" \ +")\n" \ +"or\n" \ +"async_unsuback(\n" \ +" packet_id_t packet_id,\n" \ +" variant reason,\n" \ +" v5::properties props,\n" \ +" any session_life_keeper = any()\n" \ +")\n" \ +"or\n" \ +"async_unsuback(\n" \ +" packet_id_t packet_id,\n" \ +" variant, std::vector> reasons,\n" \ +" any session_life_keeper = any()\n" \ +")\n" \ +"or\n" \ +"async_unsuback(\n" \ +" packet_id_t packet_id,\n" \ +" variant, std::vector> reasons,\n" \ +" v5::properties props,\n" \ +" any session_life_keeper = any()\n" \ +")\n" + + + +#endif // MQTT_DEPRECATED_MSG_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/endpoint.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/endpoint.hpp new file mode 100644 index 000000000..991fe760f --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/endpoint.hpp @@ -0,0 +1,11819 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_ENDPOINT_HPP) +#define MQTT_ENDPOINT_HPP + +#include // should be top to configure variant limit + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(MQTT_USE_WS) +#include +#endif // defined(MQTT_USE_WS) + +// When https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90415 is fixed, +// update the condition. + +// https://gcc.gnu.org/develop.html#timeline +#define MQTT_LIBSTDCXX_GCC_730 20180125 // workaround required +#define MQTT_LIBSTDCXX_GCC_740 20181206 // workaround required +#define MQTT_LIBSTDCXX_GCC_750 20191114 // workaround required +#define MQTT_LIBSTDCXX_GCC_810 20180502 // workaround required +#define MQTT_LIBSTDCXX_GCC_820 20180726 +#define MQTT_LIBSTDCXX_GCC_830 20190222 +#define MQTT_LIBSTDCXX_GCC_910 20190503 // workaround required +#define MQTT_LIBSTDCXX_GCC_920 20190812 // workaround required + +#if !defined(MQTT_DISABLE_LIBSTDCXX_TUPLE_ANY_WORKAROUND) +#if defined(MQTT_STD_ANY) && defined(__GLIBCXX__) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_820) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_830) + +template <> +struct std::is_constructible> : std::true_type { +}; + +template <> +struct std::is_constructible, std::tuple const&> : std::true_type { +}; + +template <> +struct std::is_copy_constructible> : std::true_type { +}; + +template <> +struct std::is_copy_constructible> : std::true_type { +}; + +template <> +struct std::is_constructible, std::_Head_base<0, std::any, false> const&> : std::true_type { +}; + +#endif // defined(MQTT_STD_ANY) && defined(__GLIBCXX__) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_820) && (__GLIBCXX__ != MQTT_LIBSTDCXX_GCC_830) +#endif // !defined(MQTT_DISABLE_LIBSTDCXX_TUPLE_ANY_WORKAROUND) + +#undef MQTT_LIBSTDCXX_GCC_730 +#undef MQTT_LIBSTDCXX_GCC_740 +#undef MQTT_LIBSTDCXX_GCC_750 +#undef MQTT_LIBSTDCXX_GCC_810 +#undef MQTT_LIBSTDCXX_GCC_820 +#undef MQTT_LIBSTDCXX_GCC_830 +#undef MQTT_LIBSTDCXX_GCC_910 +#undef MQTT_LIBSTDCXX_GCC_920 + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#endif // defined(__GNUC__) + +#include + +namespace MQTT_NS { + +namespace detail { + + +template +constexpr +std::enable_if_t< ! std::is_convertible, publish_options>::value, bool> +check_qos_value(T const&) { + return false; +} + +constexpr bool check_qos_value(publish_options pubopts) { + return pubopts.get_qos() != qos::at_most_once; +} + +template +constexpr bool should_generate_packet_id(Params const& ... params) { +#if __cplusplus >= 201703L + return (check_qos_value(params) || ...); // defaults to false for empty. +#else // __cplusplus >= 201703L + const bool results[] = {false, check_qos_value(params)... }; + bool ret = false; + for(const bool val : results) + { + ret |= val; + } + return ret; +#endif // __cplusplus >= 201703L +} + +} // namespace detail + +namespace as = boost::asio; +namespace mi = boost::multi_index; + +template class LockGuard = std::lock_guard, std::size_t PacketIdBytes = 2> +class endpoint : public std::enable_shared_from_this> { + using this_type = endpoint; + using this_type_sp = std::shared_ptr; + +public: + using async_handler_t = std::function; + using packet_id_t = typename packet_id_type::type; + + /** + * @brief Constructor for client + * @param ioc io_context + * @param version protocol_version + * @param async_operation + * This flag effects the following automatic operation. + * - puback/pubrec/pubrel/pubcomp if auto_pub_response_ is true. + * - send store data (publish QoS1,2 and pubrel) on connack receive. + * - disconnect + * MQTT protocol requests sending connack/disconnect packet with error reason code if some error happens.
+ * This function choose sync/async connack/disconnect.
+ */ + endpoint(as::io_context& ioc, protocol_version version = protocol_version::undetermined, bool async_operation = false) + :async_operation_{async_operation}, + version_(version), + tim_pingresp_(ioc), + tim_shutdown_(ioc) + { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "create" + << " version:" << version + << " async_operation:" << std::boolalpha << async_operation; + } + + /** + * @brief Constructor for server. + * @param ioc io_context + * @param socket connected socket. It should have already been connected with another endpoint. + * @param version protocol_version + * @param async_operation + * This flag effects the following automatic operation. + * - puback/pubrec/pubrel/pubcomp if auto_pub_response_ is true. + * - send store data (publish QoS1,2 and pubrel) on connack receive. + * - disconnect + * MQTT protocol requests sending connack/disconnect packet with error reason code if some error happens.
+ * This function choose sync/async connack/disconnect.
+ */ + explicit endpoint(as::io_context& ioc, std::shared_ptr socket, protocol_version version = protocol_version::undetermined, bool async_operation = false) + :socket_(force_move(socket)), + connected_(true), + async_operation_{async_operation}, + version_(version), + tim_pingresp_(ioc), + tim_shutdown_(ioc) + { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "create" + << " version:" << version + << " async_operation:" << std::boolalpha << async_operation; + } + + // MQTT Common handlers + +private: + /** + * @brief Pingreq handler + * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718086
+ * 3.13 PINGREQ – PING request + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_pingreq() noexcept = 0; + + /** + * @brief Pingresp handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901200
+ * 3.13 PINGRESP – PING response + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_pingresp() noexcept = 0; + + + // MQTT v3_1_1 handlers + + /** + * @brief Connect handler + * @param client_id + * Client Identifier.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349245
+ * 3.1.3.1 Client Identifier + * @param user_name + * User Name.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349245
+ * 3.1.3.4 User Name + * @param password + * Password.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349246
+ * 3.1.3.5 Password + * @param will + * Will. It contains retain, QoS, topic, and message.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349232
+ * 3.1.2.5 Will Flag
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349233
+ * 3.1.2.6 Will QoS
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349234
+ * 3.1.2.7 Will Retain
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349243
+ * 3.1.3.2 Will Topic
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349244
+ * 3.1.3.3 Will Message
+ * @param clean_session + * Clean Session
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349231
+ * 3.1.2.4 Clean Session + * @param keep_alive + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349237
+ * 3.1.2.10 Keep Alive + * @return if the handler returns true, then continue receiving, otherwise quit. + * + */ + virtual bool on_connect(buffer client_id, + optional user_name, + optional password, + optional will, + bool clean_session, + std::uint16_t keep_alive) noexcept = 0; + + /** + * @brief Connack handler + * @param session_present + * Session present flag.
+ * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718036
+ * 3.2.2.2 Session Present + * @param return_code + * connect_return_code
+ * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718036
+ * 3.2.2.3 Connect Return code + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_connack(bool session_present, connect_return_code return_code) noexcept = 0; + + /** + * @brief Publish handler + * @param packet_id + * packet identifier
+ * If received publish's QoS is 0, packet_id is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718039
+ * 3.3.2 Variable header + * @param pubopts + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718038
+ * 3.3.1 Fixed header
+ * You can check the fixed header using publish functions. + * @param topic_name + * Topic name + * @param contents + * Published contents + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_publish(optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents) noexcept = 0; + + /** + * @brief Puback handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718045
+ * 3.4.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_puback(packet_id_t packet_id) noexcept = 0; + + /** + * @brief Pubrec handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718050
+ * 3.5.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_pubrec(packet_id_t packet_id) noexcept = 0; + + /** + * @brief Pubrel handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349791
+ * 3.6.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_pubrel(packet_id_t packet_id) noexcept = 0; + + /** + * @brief Pubcomp handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718060
+ * 3.7.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_pubcomp(packet_id_t packet_id) noexcept = 0; + + /** + * @brief Subscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349801
+ * 3.8.2 Variable header + * @param entries + * Collection of Share Name, Topic Filter, and QoS.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349802
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_subscribe(packet_id_t packet_id, + std::vector entries) noexcept = 0; + + /** + * @brief Suback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718070
+ * 3.9.2 Variable header + * @param qoss + * Collection of QoS that is corresponding to subscribed topic order.
+ * If subscription is failure, the value is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718071
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_suback(packet_id_t packet_id, std::vector returns) noexcept = 0; + + /** + * @brief Unsubscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349810
+ * 3.10.2 Variable header + * @param entries + * Collection of Share Name and Topic Filter
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc384800448
+ * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_unsubscribe(packet_id_t packet_id, std::vector entries) noexcept = 0; + + /** + * @brief Unsuback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718045
+ * 3.11.2 Variable header + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_unsuback(packet_id_t) noexcept = 0; + + /** + * @brief Disconnect handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc384800463
+ * 3.14 DISCONNECT – Disconnect notification + */ + virtual void on_disconnect() noexcept = 0; + + // MQTT v5 handlers + + /** + * @brief Connect handler + * @param client_id + * Client Identifier.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier + * @param user_name + * User Name.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.4 User Name + * @param password + * Password.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.5 Password + * @param will + * Will. It contains retain, QoS, propertied, topic, and message.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901040
+ * 3.1.2.5 Will Flag
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901041
+ * 3.1.2.6 Will QoS
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901042
+ * 3.1.2.7 Will Retain
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901060
+ * 3.1.3.2 Will Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901069
+ * 3.1.3.3 Will Topic
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901070
+ * 3.1.3.3 Will Payload
+ * @param clean_start + * Clean Start
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039
+ * 3.1.2.4 Clean Session + * @param keep_alive + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + * + */ + virtual bool on_v5_connect(buffer client_id, + optional user_name, + optional password, + optional will, + bool clean_start, + std::uint16_t keep_alive, + v5::properties props) noexcept = 0; + + /** + * @brief Connack handler + * @param session_present + * Session present flag.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078
+ * 3.2.2.1.1 Session Present + * @param reason_code + * Connect Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901079
+ * 3.2.2.2 Connect Reason code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901080
+ * 3.2.2.3 CONNACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_connack(bool session_present, + v5::connect_reason_code reason_code, + v5::properties props) noexcept = 0; + + /** + * @brief Publish handler + * @param packet_id + * packet identifier
+ * If received publish's QoS is 0, packet_id is nullopt.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901108
+ * 3.3.2.2 Packet Identifier + * @param pubopts + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901101
+ * 3.3.1 Fixed header
+ * You can check the fixed header using publish functions. + * @param topic_name + * Topic name
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107
+ * 3.3.2.1 Topic Name
+ * @param contents + * Publish Payload
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119
+ * 3.3.3 PUBLISH Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_publish(optional packet_id, + publish_options pubopts, + buffer topic_name, + buffer contents, + v5::properties props) noexcept = 0; + + /** + * @brief Puback handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901123
+ * 3.4.2 Variable header + * @param reason_code + * PUBACK Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
+ * 3.4.2.1 PUBACK Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901125
+ * 3.4.2.2 PUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_puback(packet_id_t packet_id, + v5::puback_reason_code reason_code, + v5::properties props) noexcept = 0; + + /** + * @brief Pubrec handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901133
+ * 3.5.2 Variable header + * @param reason_code + * PUBREC Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
+ * 3.5.2.1 PUBREC Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901135
+ * 3.5.2.2 PUBREC Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_pubrec(packet_id_t packet_id, + v5::pubrec_reason_code reason_code, + v5::properties props) noexcept = 0; + + /** + * @brief Pubrel handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901143
+ * 3.6.2 Variable header + * @param reason_code + * PUBREL Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
+ * 3.6.2.1 PUBREL Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901145
+ * 3.6.2.2 PUBREL Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_pubrel(packet_id_t packet_id, + v5::pubrel_reason_code reason_code, + v5::properties props) noexcept = 0; + + /** + * @brief Pubcomp handler + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901153
+ * 3.7.2 Variable header + * @param reason_code + * PUBCOMP Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
+ * 3.7.2.1 PUBCOMP Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901155
+ * 3.7.2.2 PUBCOMP Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_pubcomp(packet_id_t packet_id, + v5::pubcomp_reason_code reason_code, + v5::properties props) noexcept = 0; + + /** + * @brief Subscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901163
+ * 3.8.2 Variable header + * @param entries + * Collection of Share Name, Topic Filter, and Subscribe Options.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901168
+ * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_subscribe(packet_id_t packet_id, + std::vector entries, + v5::properties props) noexcept = 0; + + /** + * @brief Suback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901173
+ * 3.9.2 Variable header + * @param reasons + * Collection of reason_code.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174
+ * 3.9.2.1 SUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_suback(packet_id_t packet_id, + std::vector reasons, + v5::properties props) noexcept = 0; + + /** + * @brief Unsubscribe handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901181
+ * 3.10.2 Variable header + * @param entries + * Collection of Share Name and Topic Filter
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901185
+ * 3.10.3 UNSUBSCRIBE Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_unsubscribe(packet_id_t packet_id, + std::vector entries, + v5::properties props) noexcept = 0; + + /** + * @brief Unsuback handler + * @param packet_id packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901189
+ * 3.11.2 Variable header + * @param reasons + * Collection of reason_code.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901190
+ * 3.11.2.1 UNSUBACK Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_unsuback(packet_id_t, + std::vector reasons, + v5::properties props) noexcept = 0; + + /** + * @brief Disconnect handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * 3.14 DISCONNECT – Disconnect notification + * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + */ + virtual void on_v5_disconnect(v5::disconnect_reason_code reason_code, + v5::properties props) noexcept = 0; + + /** + * @brief Auth handler + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901217
+ * 3.15 AUTH – Authentication exchange + * @param reason_code + * AUTH Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
+ * 3.15.2.1 Authenticate Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901221
+ * 3.15.2.2 AUTH Properties + * @return if the handler returns true, then continue receiving, otherwise quit. + */ + virtual bool on_v5_auth(v5::auth_reason_code reason_code, + v5::properties props) noexcept = 0; + + // Original handlers + +protected: + /** + * @brief Close handler + * + * This handler is called if the client called `disconnect()` and the server closed the socket cleanly. + * If the socket is closed by other reasons, error_handler is called. + */ + virtual void on_close() noexcept = 0; + + /** + * @brief Error handler + * + * This handler is called if the socket is closed without client's `disconnect()` call. + * + * @param ec error code + */ + virtual void on_error(error_code ec) noexcept = 0; + +private: + /** + * @brief Publish response sent handler + * This function is called just after puback sent on QoS1, or pubcomp sent on QoS2. + * @param packet_id + * packet identifier
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901026
+ * 2.2.1 Packet Identifier + */ + virtual void on_pub_res_sent(packet_id_t packet_id) noexcept = 0; + + /** + * @brief Serialize publish handler + * You can serialize the publish message. + * To restore the message, use restore_serialized_message(). + * @param msg publish message + */ + virtual void on_serialize_publish_message(basic_publish_message msg) noexcept = 0; + + /** + * @brief Serialize publish handler + * You can serialize the publish message. + * To restore the message, use restore_serialized_message(). + * @param msg v5::publish message + */ + virtual void on_serialize_v5_publish_message(v5::basic_publish_message msg) noexcept = 0; + + /** + * @brief Serialize pubrel handler + * You can serialize the pubrel message. + * If your storage has already had the publish message that has the same packet_id, + * then you need to replace the publish message to pubrel message. + * To restore the message, use restore_serialized_message(). + * @param msg pubrel message + */ + virtual void on_serialize_pubrel_message(basic_pubrel_message msg) noexcept = 0; + + /** + * @brief Serialize pubrel handler + * You can serialize the pubrel message. + * If your storage has already had the publish message that has the same packet_id, + * then you need to replace the publish message to pubrel message. + * To restore the message, use restore_serialized_message(). + * @param msg pubrel message + */ + virtual void on_serialize_v5_pubrel_message(v5::basic_pubrel_message msg) noexcept = 0; + + /** + * @brief Remove serialized message + * @param packet_id packet identifier of the removing message + */ + virtual void on_serialize_remove(packet_id_t packet_id) noexcept = 0; + +protected: + /** + * @brief Pre-send handler + * This handler is called when any mqtt control packet is decided to send. + */ + virtual void on_pre_send() noexcept = 0; + +private: + /** + * @brief is valid length handler + * This handler is called when remaining length is received. + * @param control_packet_type control_packet_type that has variable length + * @param remaining length + * @return true if check is success, otherwise false + */ + virtual bool check_is_valid_length(control_packet_type packet_type, std::size_t remaining_length) noexcept = 0; + +protected: + /** + * @brief next read handler + * This handler is called when the current mqtt message has been processed. + * @param func A callback function that is called when async operation will finish. + */ + MQTT_ALWAYS_INLINE virtual void on_mqtt_message_processed(any session_life_keeper) { + if (async_read_on_message_processed_) { + async_read_control_packet_type(force_move(session_life_keeper)); + } + } + +public: + endpoint(this_type const&) = delete; + endpoint(this_type&&) = delete; + endpoint& operator=(this_type const&) = delete; + endpoint& operator=(this_type&&) = delete; + + /** + * @brief Get clean session. + * + * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349231
+ * 3.1.2.4 Clean Session
+ * After constructing a endpoint, the clean session is set to false. + * @return clean session + */ + bool clean_session() const { + return clean_start(); + } + + /** + * @brief Get clean start. + * + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039
+ * 3.1.2.4 Clean Start
+ * After constructing a endpoint, the clean start is set to false. + * @return clean start + */ + bool clean_start() const { + return clean_start_; + } + + /** + * @brief Get the client id. + * @return The client id of this client. + */ + std::string const& get_client_id() const { + return client_id_; + } + + /** + * @brief Set client id. + * @param id client id + * + * This function should be called before calling connect().
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier + */ + void set_client_id(std::string id) { + client_id_ = force_move(id); + } + + /** + * @brief get_total_bytes_received + * @return The total bytes received on the socket. + */ + std::size_t get_total_bytes_received() const { + return total_bytes_received_; + } + + /** + * @brief get_total_bytes_sent + * @return The total bytes sent on the socket. + */ + std::size_t get_total_bytes_sent() const { + return total_bytes_sent_; + } + + /** + * @brief Set auto publish response mode. + * @param b set value + * + * When set auto publish response mode to true, puback, pubrec, pubrel,and pub comp automatically send.
+ */ + void set_auto_pub_response(bool b = true) { + auto_pub_response_ = b; + } + + /** + * @brief Set async operation flag + * @param async if true async , otherwise sync + * + * This function overwrite async_operation_ flag that is set by constructor. + * + * This function should be called before sending any packets. + * For server, in the CONNECT packet receiving handler. + * + * This flag effects the following automatic operation. + * - puback/pubrec/pubrel/pubcomp if auto_pub_response_ is true. + * - send store data (publish QoS1,2 and pubrel) on connack receive. + * - disconnect + * MQTT protocol requests sending connack/disconnect packet with error reason code if some error happens.
+ * This function choose sync/async connack/disconnect.
+ */ + void set_async_operation(bool async = true) { + async_operation_ = async; + } + + /** + * @brief Set topic alias send auto mapping enable flag + * @param b set value + * + * If set true then topic alias is automatically used. + * topic alias is allocated and reused by LRU algorithm. + * topic alias that is set manually can be used with this flag. + */ + void set_auto_map_topic_alias_send(bool b = true) { + auto_map_topic_alias_send_ = b; + } + + /** + * @brief Set topic alias send auto replacing enable flag + * @param b set value + * + * If set true when publish without topic alias and topic alias send + * map has corresponding entry, then use the alias. + * topic alias that is set manually can be used with this flag. + */ + void set_auto_replace_topic_alias_send(bool b = true) { + auto_replace_topic_alias_send_ = b; + } + + void set_packet_bulk_read_limit(std::size_t size) { + packet_bulk_read_limit_ = size; + } + + void set_props_bulk_read_limit(std::size_t size) { + props_bulk_read_limit_ = size; + } + + /** + * @brief set topic alias maximum for receiving + * @param max maximum value + * + */ + void set_topic_alias_maximum(topic_alias_t max) { + LockGuard lck (topic_alias_recv_mtx_); + if (max == 0) { + topic_alias_recv_ = nullopt; + } + else { + topic_alias_recv_.emplace(max); + } + } + + /** + * @brief start session with a connected endpoint. + * @param func finish handler that is called when the session is finished + * + */ + void start_session(any session_life_keeper = any()) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "start_session"; + shutdown_requested_ = false; + async_read_control_packet_type(force_move(session_life_keeper)); + } + + // Blocking APIs + + /** + * @brief Publish + * @param topic_name + * A topic name to publish + * @param contents + * The contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props (optional) + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper (optional) + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * @return packet_id. If qos is set to at_most_once, return 0. + * packet_id is automatically generated. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + template + std::enable_if_t< ! std::is_convertible, packet_id_t>::value, packet_id_t > + publish(T&& t, Params&&... params) { + if(detail::should_generate_packet_id(params...)) { + packet_id_t packet_id = acquire_unique_packet_id(); + publish(packet_id, std::forward(t), std::forward(params)...); + return packet_id; + } + else { + publish(0, std::forward(t), std::forward(params)...); + return 0; + } + } + + /** + * @brief Subscribe + * @param topic_name + * A topic name to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @return packet_id. + * packet_id is automatically generated.
+ * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + template + std::enable_if_t< ! std::is_convertible, packet_id_t>::value, packet_id_t > + subscribe(T&& t, Params&&... params) { + packet_id_t packet_id = acquire_unique_packet_id(); + subscribe(packet_id, std::forward(t), std::forward(params)...); + return packet_id; + } + + /** + * @brief Unsubscribe + * @param topic_name + * A topic name to unsubscribe + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @return packet_id. + * packet_id is automatically generated.
+ * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + template + std::enable_if_t< ! std::is_convertible, packet_id_t>::value, packet_id_t > + unsubscribe(T&& t, Params&&... params) { + packet_id_t packet_id = acquire_unique_packet_id(); + unsubscribe(packet_id, std::forward(t), std::forward(params)...); + return packet_id; + } + + /** + * @brief Disconnect + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205
+ * @param reason_code + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + */ + void disconnect( + v5::disconnect_reason_code reason = v5::disconnect_reason_code::normal_disconnection, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "disconnect" + << " reason:" << reason; + + if (connected_ && mqtt_connected_) { + disconnect_requested_ = true; + send_disconnect(reason, force_move(props)); + } + } + + /** + * @brief Disconnect by endpoint + * Force disconnect. It is not a clean disconnect sequence.
+ * When the endpoint disconnects using force_disconnect(), a will will send.
+ */ + void force_disconnect() { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "force_disconnect"; + + sync_shutdown(socket()); + } + + /** + * @brief Publish with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + void publish( + packet_id_t packet_id, + std::string topic_name, + std::string contents, + publish_options pubopts = {}, + v5::properties props = {}, + any life_keeper = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "publish" + << " pid:" << packet_id + << " topic:" << topic_name + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + if (pubopts.get_qos() == qos::at_most_once) { + // In the at_most_once case, we know a priori that send_publish won't track the lifetime. + send_publish(packet_id, + as::buffer(topic_name), + as::buffer(contents), + pubopts, + force_move(props), + any{}); + } + else { + auto sp_topic_name = std::make_shared(force_move(topic_name)); + auto sp_contents = std::make_shared(force_move(contents)); + auto topic_buf = as::buffer(*sp_topic_name); + auto contents_buf = as::buffer(*sp_contents); + + send_publish( + packet_id, + topic_buf, + contents_buf, + pubopts, + force_move(props), + std::make_tuple( + force_move(life_keeper), + force_move(sp_topic_name), + force_move(sp_contents) + ) + ); + } + } + + /** + * @brief Publish with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + template + typename std::enable_if< + as::is_const_buffer_sequence::value + >::type + publish( + packet_id_t packet_id, + as::const_buffer topic_name, + ConstBufferSequence contents, + publish_options pubopts, + v5::properties props, + any life_keeper + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "publish" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name)) + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + send_publish( + packet_id, + topic_name, + force_move(contents), + pubopts, + force_move(props), + force_move(life_keeper) + ); + } + + /** + * @brief Publish with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + template + typename std::enable_if< + as::is_const_buffer_sequence::value + >::type + publish( + packet_id_t packet_id, + as::const_buffer topic_name, + ConstBufferSequence contents, + publish_options pubopts, + any life_keeper + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "publish" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name)) + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + send_publish( + packet_id, + topic_name, + force_move(contents), + pubopts, + v5::properties{}, + force_move(life_keeper) + ); + } + + /** + * @brief Publish with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + * If topic_name and contents don't manage their lifetimes, then life_keeper should be used to keep + * their lifetimes. + */ + template + typename std::enable_if< + is_buffer_sequence::value + >::type + publish( + packet_id_t packet_id, + buffer topic_name, + BufferSequence contents, + publish_options pubopts = {}, + any life_keeper = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "publish" + << " pid:" << packet_id + << " topic:" << topic_name + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + auto topic_name_buf = as::buffer(topic_name); + + std::vector cbs; + { + auto b = MQTT_NS::buffer_sequence_begin(contents); + auto e = MQTT_NS::buffer_sequence_end(contents); + cbs.reserve(static_cast(std::distance(b, e))); + for (; b != e; ++b) { + cbs.emplace_back(as::buffer(*b)); + } + } + + send_publish( + packet_id, + topic_name_buf, + force_move(cbs), + pubopts, + v5::properties{}, + std::make_tuple( + force_move(life_keeper), + force_move(topic_name), + force_move(contents) + ) + ); + } + + /** + * @brief Publish with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + template + typename std::enable_if< + is_buffer_sequence::value + >::type + publish( + packet_id_t packet_id, + buffer topic_name, + BufferSequence contents, + publish_options pubopts, + v5::properties props, + any life_keeper = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "publish" + << " pid:" << packet_id + << " topic:" << topic_name + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + auto topic_name_buf = as::buffer(topic_name); + + std::vector cbs; + { + auto b = MQTT_NS::buffer_sequence_begin(contents); + auto e = MQTT_NS::buffer_sequence_end(contents); + cbs.reserve(static_cast(std::distance(b, e))); + for (; b != e; ++b) { + cbs.emplace_back(as::buffer(*b)); + } + } + + send_publish( + packet_id, + topic_name_buf, + force_move(cbs), + pubopts, + force_move(props), + std::make_tuple( + force_move(life_keeper), + force_move(topic_name), + force_move(contents) + ) + ); + } + + /** + * @brief Subscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161
+ */ + void subscribe( + packet_id_t packet_id, + string_view topic_filter, + subscribe_options option, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "subscribe" + << " pid:" << packet_id + << " topic:" << topic_filter + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + send_subscribe( + std::vector>{ + { as::buffer(topic_filter.data(), topic_filter.size()), option } + }, + packet_id, + force_move(props) + ); + } + + /** + * @brief Subscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161
+ */ + void subscribe( + packet_id_t packet_id, + as::const_buffer topic_filter, + subscribe_options option, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "subscribe" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter)) + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + send_subscribe( + std::vector>{ { topic_filter, option } }, + packet_id, + force_move(props) + ); + } + + /** + * @brief Subscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params a vector of the topic_filter and qos pair. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161
+ */ + void subscribe( + packet_id_t packet_id, + std::vector> params, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "subscribe" + << " pid:" << packet_id; + + std::vector> cb_params; + cb_params.reserve(params.size()); + for (auto const& e : params) { + cb_params.emplace_back(as::buffer(std::get<0>(e).data(), std::get<0>(e).size()), std::get<1>(e)); + } + send_subscribe(force_move(cb_params), packet_id, force_move(props)); + } + + /** + * @brief Subscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params a vector of the subscribe_entry. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161
+ */ + void subscribe( + packet_id_t packet_id, + std::vector> params, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "subscribe" + << " pid:" << packet_id; + + std::vector> buffers; + buffers.reserve(params.size()); + for (auto const& tup : params) { + buffers.emplace_back(as::buffer(std::get<0>(tup)), std::get<1>(tup)); + } + send_subscribe(force_move(buffers), packet_id, force_move(props)); + } + + /** + * @brief Unsubscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to unsubscribe + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void unsubscribe( + packet_id_t packet_id, + string_view topic_filter, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsubscribe" + << " pid:" << packet_id + << " topic:" << topic_filter; + + send_unsubscribe( + std::vector { + as::buffer(topic_filter.data(), topic_filter.size()) + }, + packet_id, + force_move(props) + ); + } + + /** + * @brief Unsubscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to unsubscribe + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void unsubscribe( + packet_id_t packet_id, + as::const_buffer topic_filter, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsubscribe" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter)); + + send_unsubscribe(std::vector{ topic_filter }, packet_id, force_move(props)); + } + + /** + * @brief Unsubscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params a collection of topic_filter + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void unsubscribe( + packet_id_t packet_id, + std::vector params, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsubscribe" + << " pid:" << packet_id; + + std::vector cb_params; + cb_params.reserve(params.size()); + + for (auto&& e : params) { + cb_params.emplace_back(as::buffer(e.data(), e.size())); + } + send_unsubscribe(force_move(cb_params), packet_id, force_move(props)); + } + + /** + * @brief Unsubscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params a collection of topic_filter + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void unsubscribe( + packet_id_t packet_id, + std::vector params, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsubscribe" + << " pid:" << packet_id; + + std::vector cb_params; + cb_params.reserve(params.size()); + + for (auto&& e : params) { + cb_params.emplace_back(buffer(string_view(get_pointer(e), get_size(e)))); + } + send_unsubscribe(params, packet_id, force_move(props)); + } + + /** + * @brief Unsubscribe with already acquired packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params a collection of topic_filter + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void unsubscribe( + packet_id_t packet_id, + std::vector params, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsubscribe" + << " pid:" << packet_id; + + std::vector cb_params; + cb_params.reserve(params.size()); + + for (auto&& e : params) { + cb_params.emplace_back(as::buffer(e)); + } + send_unsubscribe(force_move(cb_params), packet_id, force_move(props)); + } + + /** + * @brief Send pingreq packet. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901195 + */ + void pingreq() { + // pingreq might frequently send, so SEV is set to trace + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "pingreq"; + + if (connected_ && mqtt_connected_) send_pingreq(); + } + + /** + * @brief Send pingresp packet. This function is for broker. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901200 + */ + void pingresp() { + // pingresp might frequently send, so SEV is set to trace + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "pingrsp"; + + send_pingresp(); + } + + /** + * @brief Send auth packet. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718086 + * @param reason_code + * AUTH Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
+ * 3.15.2.1 Authenticate Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901221
+ * 3.15.2.2 AUTH Properties + */ + void auth( + v5::auth_reason_code reason_code = v5::auth_reason_code::success, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "auth" + << " reason:" << reason_code; + + send_auth(reason_code, force_move(props)); + } + + /** + * @brief Send connect packet. + * @param client_id + * The client id to use for this connection
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier (ClientID) + * @param user_name + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.5 User Name + * @param password + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.6 Password + * @param w + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc479576982
+ * 3.1.2.5 Will Flag + * @param clean_session + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039
+ * 3.1.2.4 Clean Start
+ * @param keep_alive_sec + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349238 + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718028 + * @param keep_alive_sec + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + */ + void connect( + std::string const& client_id, + optional const& user_name, + optional const& password, + optional w, + std::uint16_t keep_alive_sec, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "connect" + << " client_id:" << client_id + << " user_name:" << (user_name ? user_name.value() : "none") + << " keep_alive:" << std::dec << keep_alive_sec; + + connect_requested_ = true; + send_connect( + buffer(string_view(client_id)), + [&] { + if (user_name) { + return buffer(string_view(user_name.value())); + } + else { + return buffer(); + } + } (), + [&] { + if (password) { + return buffer(string_view(password.value())); + } + else { + return buffer(); + } + } (), + force_move(w), + keep_alive_sec, + force_move(props) + ); + } + + /** + * @brief Send connect packet. + * @param client_id + * The client id to use for this connection
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier (ClientID) + * @param user_name + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.5 User Name + * @param password + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.6 Password + * @param w + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc479576982
+ * 3.1.2.5 Will Flag + * @param clean_session + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901039
+ * 3.1.2.4 Clean Start
+ * @param keep_alive_sec + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349238 + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718028 + * @param keep_alive_sec + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + */ + void connect( + buffer client_id, + optional user_name, + optional password, + optional w, + std::uint16_t keep_alive_sec, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "connect" + << " client_id:" << client_id + << " user_name:" << (user_name ? string_view(user_name.value()) : string_view("none")) + << " keep_alive:" << std::dec << keep_alive_sec; + + connect_requested_ = true; + send_connect( + force_move(client_id), + force_move(user_name), + force_move(password), + force_move(w), + keep_alive_sec, + force_move(props) + ); + } + + /** + * @brief Send connack packet. This function is for broker. + * @param session_present See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349255 + * @param reason_code See reason_code.hpp and https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349256 + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901080
+ * 3.2.2.3 CONNACK Properties + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718033 + */ + void connack( + bool session_present, + variant reason_code, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "connack" + << " session_present:" << std::boolalpha << session_present + << " reason:" << reason_code; + + send_connack(session_present, reason_code, force_move(props)); + } + + /** + * @brief Send puback packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBACK Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
+ * 3.4.2.1 PUBACK Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901125
+ * 3.4.2.2 PUBACK Properties + */ + void puback( + packet_id_t packet_id, + v5::puback_reason_code reason_code = v5::puback_reason_code::success, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "puback" + << " pid:" << packet_id + << " reason:" << reason_code; + + send_puback(packet_id, reason_code, force_move(props)); + } + + /** + * @brief Send packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
+ * 3.5.2.1 Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901135
+ * 3.5.2.2 Properties + */ + void pubrec( + packet_id_t packet_id, + v5::pubrec_reason_code reason_code = v5::pubrec_reason_code::success, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "pubrec" + << " pid:" << packet_id + << " reason:" << reason_code; + + send_pubrec(packet_id, reason_code, force_move(props)); + } + + /** + * @brief Send pubrel packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBREL Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
+ * 3.6.2.1 PUBREL Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901145
+ * 3.6.2.2 PUBREL Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If your props are not using built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @note The library may store this message while it communicates with the server for several round trips. + * As such, the life_keeper paramter is important. + */ + void pubrel( + packet_id_t packet_id, + v5::pubrel_reason_code reason_code = v5::pubrel_reason_code::success, + v5::properties props = {}, + any life_keeper = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "pubrel" + << " pid:" << packet_id + << " reason:" << reason_code; + + send_pubrel(packet_id, reason_code, force_move(props), force_move(life_keeper)); + } + + /** + * @brief Send pubcomp packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBCOMP Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
+ * 3.7.2.1 PUBCOMP Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901155
+ * 3.7.2.2 PUBCOMP Properties + */ + void pubcomp( + packet_id_t packet_id, + v5::pubcomp_reason_code reason_code = v5::pubcomp_reason_code::success, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "pubcomp" + << " pid:" << packet_id + << " reason:" << reason_code; + + send_pubcomp(packet_id, reason_code, force_move(props)); + } + + /** + * @brief Send suback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174
+ * 3.9.2.1 SUBACK Properties + */ + void suback( + packet_id_t packet_id, + variant reason, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "suback" + << " pid:" << packet_id + << " reason:" < reason; + + if (variant_idx(reason) == 0) { + send_suback(std::vector{ variant_get(reason) }, packet_id, force_move(props)); + } + else { + send_suback(std::vector{ variant_get(reason) }, packet_id, force_move(props)); + } + } + + /** + * @brief Send suback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reasons + * a collection of reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174
+ * 3.9.2.1 SUBACK Properties + */ + void suback( + packet_id_t packet_id, + variant, std::vector> reasons, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "suback" + << " pid:" << packet_id; + + send_suback(force_move(reasons), packet_id, force_move(props)); + } + + /** + * @brief Send unsuback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + */ + void unsuback( + packet_id_t packet_id + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsuback" + << " pid:" << packet_id; + + send_unsuback(packet_id); + } + + /** + * @brief Send unsuback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901190
+ * 3.11.2.1 UNSUBACK Properties + */ + void unsuback( + packet_id_t packet_id, + v5::unsuback_reason_code reason, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsuback" + << " pid:" << packet_id + << " reason:" << reason; + + send_unsuback(std::vector{ reason }, packet_id, force_move(props)); + } + + /** + * @brief Send unsuback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reasons + * a collection of reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901190
+ * 3.11.2.1 UNSUBACK Properties + */ + void unsuback( + packet_id_t packet_id, + std::vector reasons, + v5::properties props = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "unsuback" + << " pid:" << packet_id; + + send_unsuback(force_move(reasons), packet_id, force_move(props)); + } + + /** + * @brief Publish + * @param topic_name + * A topic name to publish + * @param contents + * The contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @return packet_id. If qos is set to at_most_once, return 0. + * packet_id is automatically generated. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + template + std::enable_if_t< ! std::is_convertible, packet_id_t>::value > + async_publish(T&& t, Params&&... params) { + if(detail::should_generate_packet_id(params...)) { + packet_id_t packet_id = acquire_unique_packet_id(); + async_publish(packet_id, std::forward(t), std::forward(params)...); + } + else { + async_publish(0, std::forward(t), std::forward(params)...); + } + } + + /** + * @brief Disconnect + * @param func + * functor object who's operator() will be called when the async operation completes. + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ */ + void async_disconnect( + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_disconnect"; + + if (connected_ && mqtt_connected_) { + disconnect_requested_ = true; + // The reason code and property vector are only used if we're using mqttv5. + async_send_disconnect(v5::disconnect_reason_code::normal_disconnection, + v5::properties{}, + force_move(func)); + } + else { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + } + ); + } + } + + /** + * @brief Disconnect + * @param reason + * DISCONNECT Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208
+ * 3.14.2.1 Disconnect Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209
+ * 3.14.2.2 DISCONNECT Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * Send a disconnect packet to the connected broker. It is a clean disconnecting sequence. + * The broker disconnects the endpoint after receives the disconnect packet.
+ * When the endpoint disconnects using disconnect(), a will won't send.
+ */ + void async_disconnect( + v5::disconnect_reason_code reason, + v5::properties props = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_disconnect" + << " reason:" << reason; + + if (connected_ && mqtt_connected_) { + disconnect_requested_ = true; + async_send_disconnect(reason, force_move(props), force_move(func)); + } + else { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + } + ); + } + } + + /** + * @brief Disconnect by endpoint + * @param func + * functor object who's operator() will be called when the async operation completes. + * Force disconnect. It is not a clean disconnect sequence.
+ * When the endpoint disconnects using force_disconnect(), a will will send.
+ */ + void async_force_disconnect( + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_force_disconnect"; + socket_->post( + [this, self = this->shared_from_this(), func = force_move(func)] () mutable { + async_shutdown(socket(), force_move(func)); + } + ); + } + + // packet_id manual setting version + + /** + * @brief Subscribe + * @param topic_name + * A topic name to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param func + * functor object who's operator() will be called when the async operation completes. + * packet_id is automatically generated.
+ * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + template + std::enable_if_t< ! std::is_convertible, packet_id_t>::value > + async_subscribe(T&& t, Params&&... params) { + packet_id_t packet_id = acquire_unique_packet_id(); + async_subscribe(packet_id, std::forward(t), std::forward(params)...); + } + + /** + * @brief Unsubscribe + * @param topic_name + * A topic name to unsubscribe + * @param func + * functor object who's operator() will be called when the async operation completes. + * packet_id is automatically generated.
+ * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + template + std::enable_if_t< ! std::is_convertible, packet_id_t>::value > + async_unsubscribe(T&& t, Params&&... params) { + packet_id_t packet_id = acquire_unique_packet_id(); + async_unsubscribe(packet_id, std::forward(t), std::forward(params)...); + } + + /** + * @brief Publish with a manual set packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param func + * functor object who's operator() will be called when the async operation completes. + */ + void async_publish( + packet_id_t packet_id, + std::string topic_name, + std::string contents, + publish_options pubopts = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_publish" + << " pid:" << packet_id + << " topic:" << topic_name + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + auto sp_topic_name = std::make_shared(force_move(topic_name)); + auto sp_contents = std::make_shared(force_move(contents)); + auto topic_name_buf = as::buffer(*sp_topic_name); + auto contents_buf = as::buffer(*sp_contents); + + async_send_publish( + packet_id, + topic_name_buf, + contents_buf, + pubopts, + v5::properties{}, + std::make_pair(force_move(sp_topic_name), force_move(sp_contents)), + force_move(func) + ); + } + + /** + * @brief Publish with a manual set packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * @param func + * functor object who's operator() will be called when the async operation completes. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + void async_publish( + packet_id_t packet_id, + std::string topic_name, + std::string contents, + publish_options pubopts, + v5::properties props, + any life_keeper = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_publish" + << " pid:" << packet_id + << " topic:" << topic_name + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + auto sp_topic_name = std::make_shared(force_move(topic_name)); + auto sp_contents = std::make_shared(force_move(contents)); + auto topic_name_buf = as::buffer(*sp_topic_name); + auto contents_buf = as::buffer(*sp_contents); + + async_send_publish( + packet_id, + topic_name_buf, + contents_buf, + pubopts, + force_move(props), + std::make_tuple( + force_move(life_keeper), + force_move(sp_topic_name), + force_move(sp_contents) + ), + force_move(func) + ); + } + + /** + * @brief Publish with a manual set packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * @param func + * functor object who's operator() will be called when the async operation completes. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + template + typename std::enable_if< + as::is_const_buffer_sequence::value + >::type + async_publish( + packet_id_t packet_id, + as::const_buffer topic_name, + ConstBufferSequence contents, + publish_options pubopts = {}, + any life_keeper = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_publish" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name)) + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + async_send_publish( + packet_id, + topic_name, + force_move(contents), + pubopts, + v5::properties{}, + force_move(life_keeper), + force_move(func) + ); + } + + /** + * @brief Publish with a manual set packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * @param func + * functor object who's operator() will be called when the async operation completes. + */ + template + typename std::enable_if< + as::is_const_buffer_sequence::value + >::type + async_publish( + packet_id_t packet_id, + as::const_buffer topic_name, + ConstBufferSequence contents, + publish_options pubopts, + v5::properties props, + any life_keeper = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_publish" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_name), get_size(topic_name)) + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + async_send_publish( + packet_id, + topic_name, + force_move(contents), + pubopts, + force_move(props), + force_move(life_keeper), + force_move(func) + ); + } + + /** + * @brief Publish with a manual set packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * @param func + * functor object who's operator() will be called when the async operation completes. + */ + template + typename std::enable_if< + is_buffer_sequence::value + >::type + async_publish( + packet_id_t packet_id, + buffer topic_name, + BufferSequence contents, + publish_options pubopts = {}, + any life_keeper = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_publish" + << " pid:" << packet_id + << " topic:" << topic_name + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + auto topic_name_buf = as::buffer(topic_name); + + std::vector cbs; + { + auto b = MQTT_NS::buffer_sequence_begin(contents); + auto e = MQTT_NS::buffer_sequence_end(contents); + cbs.reserve(static_cast(std::distance(b, e))); + for (; b != e; ++b) { + cbs.emplace_back(as::buffer(*b)); + } + } + + async_send_publish( + packet_id, + topic_name_buf, + force_move(cbs), + pubopts, + v5::properties{}, + std::make_tuple( + force_move(life_keeper), + force_move(topic_name), + force_move(contents) + ), + force_move(func) + ); + } + + /** + * @brief Publish with a manual set packet identifier + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * If qos == qos::at_most_once, packet_id must be 0. But not checked in release mode due to performance. + * @param topic_name + * A topic name to publish + * @param contents + * The contents or the range of the contents to publish + * @param pubopts + * qos, retain flag, and dup flag. + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901109
+ * 3.3.2.3 PUBLISH Properties + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * @param func + * functor object who's operator() will be called when the async operation completes. + * + * @note If your QOS level is exactly_once or at_least_once, then the library will store this publish + * internally until the broker has confirmed delivery, which may involve resends, and as such the + * life_keeper parameter is important. + */ + template + typename std::enable_if< + is_buffer_sequence::value + >::type + async_publish( + packet_id_t packet_id, + buffer topic_name, + BufferSequence contents, + publish_options pubopts, + v5::properties props, + any life_keeper = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_publish" + << " pid:" << packet_id + << " topic:" << topic_name + << " qos:" << pubopts.get_qos() + << " retain:" << pubopts.get_retain() + << " dup:" << pubopts.get_dup(); + + BOOST_ASSERT((pubopts.get_qos() == qos::at_most_once && packet_id == 0) || (pubopts.get_qos() != qos::at_most_once && packet_id != 0)); + + auto topic_name_buf = as::buffer(topic_name); + + std::vector cbs; + { + auto b = MQTT_NS::buffer_sequence_begin(contents); + auto e = MQTT_NS::buffer_sequence_end(contents); + cbs.reserve(static_cast(std::distance(b, e))); + for (; b != e; ++b) { + cbs.emplace_back(as::buffer(*b)); + } + } + + async_send_publish( + packet_id, + topic_name_buf, + force_move(cbs), + pubopts, + force_move(props), + std::make_tuple( + force_move(life_keeper), + force_move(topic_name), + force_move(contents) + ), + force_move(func) + ); + } + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::string topic_filter, + subscribe_options option, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id + << " topic:" << topic_filter + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + auto sp_topic_filter = std::make_shared(force_move(topic_filter)); + auto topic_filter_buf = as::buffer(*sp_topic_filter); + + async_send_subscribe( + std::vector>{ { topic_filter_buf, option } }, + packet_id, + v5::properties{}, + [life_keeper = force_move(sp_topic_filter), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::string topic_filter, + subscribe_options option, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id + << " topic:" << topic_filter + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + auto sp_topic_filter = std::make_shared(force_move(topic_filter)); + auto topic_filter_buf = as::buffer(*sp_topic_filter); + + async_send_subscribe( + std::vector>{ { topic_filter_buf, option } }, + packet_id, + force_move(props), + [life_keeper = force_move(sp_topic_filter), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param func + * functor object who's operator() will be called when the async operation completes. + * This object should hold the lifetime of the buffers for topic_filter. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + as::const_buffer topic_filter, + subscribe_options option, + async_handler_t func + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter)) + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + async_send_subscribe( + std::vector>{ { topic_filter, option } }, + packet_id, + v5::properties{}, + force_move(func) + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * This object should hold the lifetime of the buffers for topic_filter, and properties. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + as::const_buffer topic_filter, + subscribe_options option, + v5::properties props, + async_handler_t func + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter)) + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + async_send_subscribe( + std::vector>{ { topic_filter, option } }, + packet_id, + force_move(props), + force_move(func) + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + buffer topic_filter, + subscribe_options option, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id + << " topic:" << topic_filter + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + auto topic_filter_buf = as::buffer(topic_filter); + async_send_subscribe( + std::vector>{ { topic_filter_buf, option } }, + packet_id, + v5::properties{}, + [life_keeper = force_move(topic_filter), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter + * A topic filter to subscribe + * @param option + * subscription options
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + buffer topic_filter, + subscribe_options option, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id + << " topic:" << topic_filter + << " qos:" << option.get_qos() + << " rh:" << option.get_retain_handling() + << " nl:" << option.get_nl() + << " rap:" << option.get_rap(); + + auto topic_filter_buf = as::buffer(topic_filter); + async_send_subscribe( + std::vector>{ { topic_filter_buf, option } }, + packet_id, + force_move(props), + [life_keeper = force_move(topic_filter), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the pair of topic_filter and option to subscribe.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::vector> params, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id; + + std::vector> cb_params; + cb_params.reserve(params.size()); + + std::vector> life_keepers; + life_keepers.reserve(params.size()); + + for (auto&& e : params) { + auto sp_topic_filter = std::make_shared(force_move(std::get<0>(e))); + cb_params.emplace_back(as::buffer(*sp_topic_filter), std::get<1>(e)); + life_keepers.emplace_back(force_move(sp_topic_filter)); + } + + async_send_subscribe( + force_move(cb_params), + packet_id, + v5::properties{}, + [life_keeper = force_move(life_keepers), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the pair of topic_filter and option to subscribe.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164
+ * 3.8.2.1 SUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::vector> params, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id; + + std::vector> cb_params; + cb_params.reserve(params.size()); + + std::vector> life_keepers; + life_keepers.reserve(params.size()); + + for (auto&& e : params) { + auto sp_topic_filter = std::make_shared(force_move(std::get<0>(e))); + cb_params.emplace_back(as::buffer(*sp_topic_filter), std::get<1>(e)); + life_keepers.emplace_back(force_move(sp_topic_filter)); + } + async_send_subscribe( + force_move(cb_params), + packet_id, + force_move(props), + [life_keeper = force_move(life_keepers), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params A collection of the pair of topic_filter and qos to subscribe. + * @param func + * functor object who's operator() will be called when the async operation completes. + * This object should hold the lifetime of the buffers for params. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::vector> params, + async_handler_t func + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id; + + async_send_subscribe( + force_move(params), + packet_id, + v5::properties{}, + force_move(func) + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the pair of topic_filter and option to subscribe.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param func + * functor object who's operator() will be called when the async operation completes. + * This object should hold the lifetime of the buffers for params. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::vector> params, + v5::properties props, + async_handler_t func + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id; + + async_send_subscribe( + force_move(params), + packet_id, + force_move(props), + force_move(func) + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params A collection of the pair of topic_filter and qos to subscribe. + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::vector> params, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id; + + std::vector> cb_params; + cb_params.reserve(params.size()); + + for (auto&& e : params) { + cb_params.emplace_back( + as::buffer(std::get<0>(e)), + std::get<1>(e) + ); + } + + async_send_subscribe( + force_move(cb_params), + packet_id, + v5::properties{}, + [life_keeper = force_move(params), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Subscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the pair of topic_filter and option to subscribe.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901169
+ * 3.8.3.1 Subscription Options + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_subscribe( + packet_id_t packet_id, + std::vector> params, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_subscribe" + << " pid:" << packet_id; + + std::vector> cb_params; + cb_params.reserve(params.size()); + + for (auto&& e : params) { + cb_params.emplace_back( + as::buffer(std::get<0>(e)), + std::get<1>(e) + ); + } + + async_send_subscribe( + force_move(cb_params), + packet_id, + force_move(props), + [life_keeper = force_move(params), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter topic_filter + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_unsubscribe( + packet_id_t packet_id, + std::string topic_filter, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id + << " topic:" << topic_filter; + + auto sp_topic_filter = std::make_shared(force_move(topic_filter)); + auto topic_filter_buf = as::buffer(*sp_topic_filter); + async_send_unsubscribe( + std::vector{ topic_filter_buf }, + packet_id, + v5::properties{}, + [life_keeper = force_move(sp_topic_filter), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter topic_filter + * @param func + * functor object who's operator() will be called when the async operation completes. + * This object should hold the lifetime of the buffer for topic_filter. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_unsubscribe( + packet_id_t packet_id, + as::const_buffer topic_filter, + async_handler_t func + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id + << " topic:" << string_view(get_pointer(topic_filter), get_size(topic_filter)); + + async_send_unsubscribe(std::vector{ topic_filter }, packet_id, v5::properties{}, force_move(func)); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter topic_filter + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_unsubscribe( + packet_id_t packet_id, + buffer topic_filter, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id + << " topic:" << topic_filter; + + auto topic_filter_buf = as::buffer(topic_filter); + async_send_unsubscribe(std::vector{ topic_filter_buf }, + packet_id, + v5::properties{}, + [life_keeper = force_move(topic_filter), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + }); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param topic_filter topic_filter + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901161 + */ + void async_unsubscribe( + packet_id_t packet_id, + buffer topic_filter, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id + << " topic:" << topic_filter; + + auto topic_filter_buf = as::buffer(topic_filter); + async_send_unsubscribe(std::vector{ topic_filter_buf }, + packet_id, + force_move(props), + [life_keeper = force_move(topic_filter), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + }); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the topic filter to unsubscribe + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void async_unsubscribe( + packet_id_t packet_id, + std::vector params, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id; + + std::vector cb_params; + cb_params.reserve(params.size()); + + std::vector> life_keepers; + life_keepers.reserve(params.size()); + + for (auto&& e : params) { + life_keepers.emplace_back(std::make_shared(force_move(e))); + cb_params.emplace_back(as::buffer(*life_keepers.back())); + } + + async_send_unsubscribe( + force_move(cb_params), + packet_id, + v5::properties{}, + [life_keeper = force_move(life_keepers), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the topic filter to unsubscribe + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void async_unsubscribe( + packet_id_t packet_id, + std::vector params, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id; + + std::vector cb_params; + cb_params.reserve(params.size()); + + // TOOD: Theoretically, std::vector's storage remains stationary + // as long as it's never copied... + // Perhaps a wrapper that disables copies, and forces move only? + // that would allow us to avoid the std::shared_ptr vector. + // TODO: Does vector do short-buffer-optimization? If so, this is an invalid idea. + std::vector> life_keepers; + life_keepers.reserve(params.size()); + + for (auto&& e : params) { + life_keepers.emplace_back(std::make_shared(force_move(e))); + cb_params.emplace_back(as::buffer(*life_keepers.back())); + } + + async_send_unsubscribe( + force_move(cb_params), + packet_id, + force_move(props), + [life_keeper = force_move(life_keepers), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the topic filter to unsubscribe + * @param func + * functor object who's operator() will be called when the async operation completes. + * This object may hold the lifetime of the buffers for topic_filter and contents. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void async_unsubscribe( + packet_id_t packet_id, + std::vector params, + async_handler_t func + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id; + + async_send_unsubscribe( + force_move(params), + packet_id, + v5::properties{}, + force_move(func) + ); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the topic filter to unsubscribe + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * This object should hold the lifetime of the buffers for params. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void async_unsubscribe( + packet_id_t packet_id, + std::vector params, + v5::properties props, + async_handler_t func + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id; + + async_send_unsubscribe( + force_move(params), + packet_id, + force_move(props), + force_move(func) + ); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the topic filter to unsubscribe + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void async_unsubscribe( + packet_id_t packet_id, + std::vector params, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id; + + std::vector cb_params; + cb_params.reserve(params.size()); + for (auto const& buf : params) { + cb_params.emplace_back(as::buffer(buf)); + } + + async_send_unsubscribe( + force_move(cb_params), + packet_id, + v5::properties{}, + [life_keeper = force_move(params), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Unsubscribe + * @param packet_id + * packet identifier. It should be acquired by acquire_unique_packet_id, or register_packet_id. + * The ownership of the packet_id moves to the library. + * @param params + * A collection of the topic filter to unsubscribe + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182
+ * 3.10.2.1 UNSUBSCRIBE Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * You can subscribe multiple topics all at once.
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901179 + */ + void async_unsubscribe( + packet_id_t packet_id, + std::vector params, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsubscribe" + << " pid:" << packet_id; + + std::vector cb_params; + cb_params.reserve(params.size()); + for (auto const& buf : params) { + cb_params.emplace_back(as::buffer(buf)); + } + + async_send_unsubscribe( + force_move(cb_params), + packet_id, + force_move(props), + [life_keeper = force_move(params), func = force_move(func)] + (error_code ec) { + if(func) func(ec); + } + ); + } + + /** + * @brief Send pingreq packet. + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901195 + */ + void async_pingreq(async_handler_t func = {}) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pingreq"; + + if (connected_ && mqtt_connected_) async_send_pingreq(force_move(func)); + } + + /** + * @brief Send pingresp packet. This function is for broker. + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901200 + */ + void async_pingresp(async_handler_t func = {}) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pingrsp"; + + async_send_pingresp(force_move(func)); + } + + /** + * @brief Send auth packet. + * @param reason_code + * AUTH Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220
+ * 3.15.2.1 Authenticate Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901221
+ * 3.15.2.2 AUTH Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718086 + */ + void async_auth( + v5::auth_reason_code reason_code = v5::auth_reason_code::success, + v5::properties props = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_auth" + << " reason:" << reason_code; + + async_send_auth(reason_code, force_move(props), force_move(func)); + } + + /** + * @brief Send connect packet. + * @param client_id + * The client id to use for this connection
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier (ClientID) + * @param user_name + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.5 User Name + * @param password + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.6 Password + * @param w + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc479576982
+ * 3.1.2.5 Will Flag + * @param keep_alive_sec + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718028 + */ + void async_connect( + buffer client_id, + optional user_name, + optional password, + optional w, + std::uint16_t keep_alive_sec, + async_handler_t func = {} + ) { + async_connect( + force_move(client_id), + force_move(user_name), + force_move(password), + force_move(w), + keep_alive_sec, + v5::properties{}, + force_move(func)); + } + + /** + * @brief Send connect packet. + * @param client_id + * The client id to use for this connection
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901059
+ * 3.1.3.1 Client Identifier (ClientID) + * @param user_name + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901071
+ * 3.1.3.5 User Name + * @param password + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901072
+ * 3.1.3.6 Password + * @param w + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc479576982
+ * 3.1.2.5 Will Flag + * @param keep_alive_sec + * Keep Alive
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046
+ * 3.1.2.11 CONNECT Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718028 + */ + void async_connect( + buffer client_id, + optional user_name, + optional password, + optional w, + std::uint16_t keep_alive_sec, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_connect" + << " client_id:" << client_id + << " user_name:" << (user_name ? string_view(user_name.value()) : string_view("none")) + << " keep_alive:" << std::dec << keep_alive_sec; + + connect_requested_ = true; + async_send_connect( + force_move(client_id), + force_move(user_name), + force_move(password), + force_move(w), + keep_alive_sec, + force_move(props), + force_move(func)); + } + + /** + * @brief Send connack packet. This function is for broker. + * @param session_present See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349255 + * @param return_code See connect_return_code.hpp and https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349256 + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718033 + */ + void async_connack( + bool session_present, + variant reason_code, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_connack" + << " session_present:" << std::boolalpha << session_present + << " reason:" << reason_code; + + async_send_connack(session_present, force_move(reason_code), v5::properties{}, force_move(func)); + } + + /** + * @brief Send connack packet. This function is for broker. + * @param session_present See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349255 + * @param return_code See connect_return_code.hpp and https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc385349256 + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901080
+ * 3.2.2.3 CONNACK Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718033 + */ + void async_connack( + bool session_present, + variant reason_code, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_connack" + << " session_present:" << std::boolalpha << session_present + << " reason:" << reason_code; + + async_send_connack(session_present, force_move(reason_code), force_move(props), force_move(func)); + } + + /** + * @brief Send puback packet. + * @param packet_id packet id corresponding to publish + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + */ + void async_puback( + packet_id_t packet_id, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_puback" + << " pid:" << packet_id; + + async_send_puback(packet_id, v5::puback_reason_code::success, v5::properties{}, force_move(func)); + } + + /** + * @brief Send puback packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBACK Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124
+ * 3.4.2.1 PUBACK Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901125
+ * 3.4.2.2 PUBACK Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + */ + void async_puback( + packet_id_t packet_id, + v5::puback_reason_code reason_code, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_puback" + << " pid:" << packet_id + << " reason:" << reason_code; + + async_send_puback(packet_id, reason_code, force_move(props), force_move(func)); + } + + /** + * @brief Send pubrec packet. + * @param packet_id packet id corresponding to publish + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + */ + void async_pubrec( + packet_id_t packet_id, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pubrec" + << " pid:" << packet_id; + + async_send_pubrec(packet_id, v5::pubrec_reason_code::success, v5::properties{}, force_move(func)); + } + + /** + * @brief Send pubrec packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBREC Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134
+ * 3.5.2.1 PUBREC Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901135
+ * 3.5.2.2 PUBREC Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + */ + void async_pubrec( + packet_id_t packet_id, + v5::pubrec_reason_code reason_code, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pubrec" + << " pid:" << packet_id + << " reason:" << reason_code; + + async_send_pubrec(packet_id, reason_code, force_move(props), force_move(func)); + } + + /** + * @brief Send pubrel packet. + * @param packet_id packet id corresponding to publish + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + */ + void async_pubrel( + packet_id_t packet_id, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pubrel" + << " pid:" << packet_id; + + async_send_pubrel(packet_id, v5::pubrel_reason_code::success, v5::properties{}, any(), force_move(func)); + } + + /** + * @brief Send pubrel packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBREL Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
+ * 3.6.2.1 PUBREL Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901145
+ * 3.6.2.2 PUBREL Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + * + * @note The library may store this message while it communicates with the server for several round trips. + * As such, the life_keeper paramter is important. + */ + template + std::enable_if_t< + std::is_convertible::value + > + async_pubrel( + packet_id_t packet_id, + v5::pubrel_reason_code reason_code, + v5::properties props = {}, + Func&& func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pubrel" + << " pid:" << packet_id + << " reason:" << reason_code; + + async_send_pubrel(packet_id, reason_code, force_move(props), any(), std::forward(func)); + } + + /** + * @brief Send pubrel packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBREL Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144
+ * 3.6.2.1 PUBREL Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901145
+ * 3.6.2.2 PUBREL Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + * + * @param life_keeper + * An object that stays alive as long as the library holds a reference to any other parameters. + * If topic_name, contents, or props do not have built-in lifetime management, (e.g. buffer) + * use this parameter to manage their lifetime. + * + * @note The library may store this message while it communicates with the server for several round trips. + * As such, the life_keeper paramter is important. + */ + void async_pubrel( + packet_id_t packet_id, + v5::pubrel_reason_code reason_code, + v5::properties props = {}, + any life_keeper = {}, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pubrel" + << " pid:" << packet_id + << " reason:" << reason_code; + + async_send_pubrel(packet_id, reason_code, force_move(props), force_move(life_keeper), force_move(func)); + } + + /** + * @brief Send pubcomp packet. + * @param packet_id packet id corresponding to publish + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + */ + void async_pubcomp( + packet_id_t packet_id, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pubcomp" + << " pid:" << packet_id; + + async_send_pubcomp(packet_id, v5::pubcomp_reason_code::success, v5::properties{}, force_move(func)); + } + + /** + * @brief Send pubcomp packet. + * @param packet_id packet id corresponding to publish + * @param reason_code + * PUBCOMP Reason Code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154
+ * 3.7.2.1 PUBCOMP Reason Code + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901155
+ * 3.7.2.2 PUBCOMP Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718043 + */ + void async_pubcomp( + packet_id_t packet_id, + v5::pubcomp_reason_code reason_code, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", trace) + << MQTT_ADD_VALUE(address, this) + << "async_pubcomp" + << " pid:" << packet_id + << " reason:" << reason_code; + + async_send_pubcomp(packet_id, reason_code, force_move(props), force_move(func)); + } + + /** + * @brief Send suback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_suback( + packet_id_t packet_id, + variant reason, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_suback" + << " pid:" << packet_id + << " reason:" < reason; + + if (variant_idx(reason) == 0) { + async_send_suback(std::vector{ variant_get(reason) }, packet_id, v5::properties{}, force_move(func)); + } + else { + async_send_suback(std::vector{ variant_get(reason) }, packet_id, v5::properties{}, force_move(func)); + } + } + + /** + * @brief Send suback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174
+ * 3.9.2.1 SUBACK Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_suback( + packet_id_t packet_id, + variant reason, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_suback" + << " pid:" << packet_id + << " reason:" < reason; + + if (variant_idx(reason) == 0) { + async_send_suback(std::vector{ variant_get(reason) }, packet_id, force_move(props), force_move(func)); + } + else { + async_send_suback(std::vector{ variant_get(reason) }, packet_id, force_move(props), force_move(func)); + } + } + + /** + * @brief Send suback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * a collection of reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_suback( + packet_id_t packet_id, + variant, std::vector> reasons, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_suback" + << " pid:" << packet_id; + + async_send_suback(force_move(reasons), packet_id, v5::properties{}, force_move(func)); + } + + /** + * @brief Send suback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * a collection of reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901178
+ * 3.9.3 SUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174
+ * 3.9.2.1 SUBACK Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_suback( + packet_id_t packet_id, + variant, std::vector> reasons, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_suback" + << " pid:" << packet_id; + + async_send_suback(force_move(reasons), packet_id, force_move(props), force_move(func)); + } + + /** + * @brief Send unsuback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_unsuback( + packet_id_t packet_id, + v5::unsuback_reason_code reason, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsuback" + << " pid:" << packet_id + << " reason:" < reason; + + async_send_unsuback(std::vector{ reason }, packet_id, force_move(func)); + } + + /** + * @brief Send unsuback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reason + * reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901190
+ * 3.11.2.1 UNSUBACK Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_unsuback( + packet_id_t packet_id, + v5::unsuback_reason_code reason, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsuback" + << " pid:" << packet_id + << " reason:" < reason; + + async_send_unsuback(std::vector{ reason }, packet_id, force_move(props), force_move(func)); + } + + /** + * @brief Send unsuback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reasons + * a collection of reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_unsuback( + packet_id_t packet_id, + std::vector reasons, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsuback" + << " pid:" << packet_id; + + async_send_unsuback(force_move(reasons), packet_id, v5::properties{}, force_move(func)); + } + + /** + * @brief Send unsuback packet. This function is for broker. + * @param packet_id packet id corresponding to subscribe + * @param reasons + * a collection of reason_code
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901194
+ * 3.11.3 UNSUBACK Payload + * @param props + * Properties
+ * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901190
+ * 3.11.2.1 UNSUBACK Properties + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718068 + */ + void async_unsuback( + packet_id_t packet_id, + std::vector reasons, + v5::properties props, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsuback" + << " pid:" << packet_id; + + async_send_unsuback(force_move(reasons), packet_id, force_move(props), force_move(func)); + } + + /** + * @brief Send ununsuback packet. This function is for broker. + * @param packet_id + * packet id corresponding to unsubscribe + * @param func + * functor object who's operator() will be called when the async operation completes. + * See https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc398718077 + */ + void async_unsuback( + packet_id_t packet_id, + async_handler_t func = {} + ) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_unsuback" + << " pid:" << packet_id; + + async_send_unsuback(packet_id, force_move(func)); + } + + /** + * @brief Clear stored publish message that has packet_id. + * @param packet_id packet id corresponding to stored publish + */ + void clear_stored_publish(packet_id_t packet_id) { + LockGuard lck (store_mtx_); + auto& idx = store_.template get(); + auto r = idx.equal_range(packet_id); + idx.erase(std::get<0>(r), std::get<1>(r)); + pid_man_.release_id(packet_id); + } + + /** + * @brief Apply f to stored messages. + * @param f applying function. f should be void(char const*, std::size_t) + */ + void for_each_store(std::function const& f) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "for_each_store(ptr, size)"; + LockGuard lck (store_mtx_); + auto const& idx = store_.template get(); + for (auto const & e : idx) { + auto const& m = e.message(); + auto cb = continuous_buffer(m); + f(cb.data(), cb.size()); + } + } + + /** + * @brief Apply f to stored messages. + * @param f applying function. f should be void(store_message_variant) + */ + void for_each_store(std::function)> const& f) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "for_each_store(store_message_variant)"; + LockGuard lck (store_mtx_); + auto const& idx = store_.template get(); + for (auto const & e : idx) { + f(e.message()); + } + } + + /** + * @brief Apply f to stored messages. + * @param f applying function. f should be void(store_message_variant, any) + */ + void for_each_store_with_life_keeper(std::function, any)> const& f) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + + << "for_each_store(store_message_variant, life_keeper)"; + LockGuard lck (store_mtx_); + auto const& idx = store_.template get(); + for (auto const & e : idx) { + f(e.message(), e.life_keeper()); + } + } + + /** + * @brief Get processed but not released QoS2 packet ids + * This function should be called after disconnection + * @return set of packet_ids + */ + std::set get_qos2_publish_handled_pids() const { + return qos2_publish_handled_; + } + + /** + * @brief Restore processed but not released QoS2 packet ids + * This function should be called before receive the first publish + * @param pids packet ids + */ + void restore_qos2_publish_handled_pids(std::set pids) { + qos2_publish_handled_ = force_move(pids); + } + + // manual packet_id management for advanced users + + /** + * @brief Acquire the new unique packet id. + * If all packet ids are already in use, then throw packet_id_exhausted_error exception. + * After acquiring the packet id, you can call acquired_* functions. + * The ownership of packet id is moved to the library. + * Or you can call release_packet_id to release it. + * @return packet id + */ + packet_id_t acquire_unique_packet_id() { + if (auto pid = acquire_unique_packet_id_no_except()) return pid.value(); + throw packet_id_exhausted_error(); + } + + /** + * @brief Acquire the new unique packet id. + * If all packet ids are already in use, then returns nullopt + * After acquiring the packet id, you can call acquired_* functions. + * The ownership of packet id is moved to the library. + * Or you can call release_packet_id to release it. + * @return packet id + */ + optional acquire_unique_packet_id_no_except() { + LockGuard lck (store_mtx_); + return pid_man_.acquire_unique_id(); + } + + /** + * @brief Register packet_id to the library. + * After registering the packet_id, you can call acquired_* functions. + * The ownership of packet id is moved to the library. + * Or you can call release_packet_id to release it. + * @return If packet_id is successfully registerd then return true, otherwise return false. + */ + bool register_packet_id(packet_id_t packet_id) { + LockGuard lck (store_mtx_); + return pid_man_.register_id(packet_id); + } + + /** + * @brief Release packet_id. + * @param packet_id packet id to release. + * only the packet_id gotten by acquire_unique_packet_id, or + * register_packet_id is permitted. + */ + void release_packet_id(packet_id_t packet_id) { + LockGuard lck (store_mtx_); + pid_man_.release_id(packet_id); + } + + /** + * @brief Restore serialized publish and pubrel messages. + * This function should be called before connect. + * @param b iterator begin of the message + * @param e iterator end of the message + */ + template + std::enable_if_t< std::is_convertible::value > + restore_serialized_message(Iterator b, Iterator e) { + BOOST_ASSERT(version_ == protocol_version::v3_1_1); + static_assert( + std::is_same< + typename std::iterator_traits::iterator_category, + std::random_access_iterator_tag + >::value, + "Iterators provided to restore_serialized_message() must be random access iterators." + ); + + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "restore_serialized_message(b, e)"; + + if (b == e) return; + + auto fixed_header = static_cast(*b); + auto cpt_opt = get_control_packet_type_with_check(fixed_header); + if (!cpt_opt) { + MQTT_LOG("mqtt_api", error) + << MQTT_ADD_VALUE(address, this) + << "invalid fixed_header ignored. " + << std::hex << static_cast(fixed_header); + throw malformed_packet_error(); + } + switch (cpt_opt.value()) { + case control_packet_type::publish: { + auto buf = allocate_buffer(b, e); + restore_serialized_message( + basic_publish_message( + buf + ), + buf + ); + } break; + case control_packet_type::pubrel: { + restore_serialized_message( + basic_pubrel_message( + // basic_pubrel_message have no member variable that type is buffer. + // When creating basic_pubrel_message, the constructor just read buffer + // and convert to some values. + // So the argument buffer(...) doesn't need to hold the lifetime. + buffer(string_view(&*b, static_cast(std::distance(b, e)))) + ) + ); + } break; + default: + MQTT_LOG("mqtt_api", error) + << MQTT_ADD_VALUE(address, this) + << "invalid control packet type. " + << std::hex << static_cast(fixed_header); + throw protocol_error(); + break; + } + } + + /** + * @brief Restore serialized publish message. + * This function should be called before connect. + * @param msg publish message. + * @param life_keeper + * An object that stays alive (but is moved with force_move()) until the stored message is sent. + */ + void restore_serialized_message(basic_publish_message msg, any life_keeper = {}) { + BOOST_ASSERT(version_ == protocol_version::v3_1_1); + auto packet_id = msg.packet_id(); + qos qos_value = msg.get_qos(); + LockGuard lck (store_mtx_); + if (pid_man_.register_id(packet_id)) { + auto ret = store_.emplace( + packet_id, + ((qos_value == qos::at_least_once) ? control_packet_type::puback + : control_packet_type::pubrec), + force_move(msg), + force_move(life_keeper) + ); + // When client want to restore serialized messages, + // endpoint might keep the message that has the same packet_id. + // In this case, overwrite store_. + if (!ret.second) { + store_.modify( + ret.first, + [&] (auto& e) { + e = store( + packet_id, + ((qos_value == qos::at_least_once) ? control_packet_type::puback + : control_packet_type::pubrec), + force_move(msg), + force_move(life_keeper) + ); + } + ); + } + } + } + + /** + * @brief Restore serialized pubrel message. + * This function should be called before connect. + * @param msg pubrel message. + */ + void restore_serialized_message(basic_pubrel_message msg, any life_keeper = {}) { + BOOST_ASSERT(version_ == protocol_version::v3_1_1); + auto packet_id = msg.packet_id(); + LockGuard lck (store_mtx_); + if (pid_man_.register_id(packet_id)) { + auto ret = store_.emplace( + packet_id, + control_packet_type::pubcomp, + force_move(msg), + force_move(life_keeper) + ); + // When client want to restore serialized messages, + // endpoint might keep the message that has the same packet_id. + // In this case, overwrite store_. + if (!ret.second) { + store_.modify( + ret.first, + [&] (auto& e) { + e = store( + packet_id, + control_packet_type::pubcomp, + force_move(msg), + force_move(life_keeper) + ); + } + ); + } + } + } + + /** + * @brief Restore serialized publish and pubrel messages. + * This function shouold be called before connect. + * @param b iterator begin of the message + * @param e iterator end of the message + * Empty topic_name on MQTT v5 publish message is prohibited. + */ + template + std::enable_if_t< std::is_convertible::value > + restore_v5_serialized_message(Iterator b, Iterator e) { + BOOST_ASSERT(version_ == protocol_version::v5); + if (b == e) return; + + auto fixed_header = static_cast(*b); + auto cpt_opt = get_control_packet_type_with_check(fixed_header); + if (!cpt_opt) { + MQTT_LOG("mqtt_api", error) + << MQTT_ADD_VALUE(address, this) + << "invalid fixed_header ignored. " + << std::hex << static_cast(fixed_header); + throw malformed_packet_error(); + } + switch (cpt_opt.value()) { + case control_packet_type::publish: { + auto buf = allocate_buffer(b, e); + restore_v5_serialized_message( + v5::basic_publish_message(buf), + buf + ); + } break; + case control_packet_type::pubrel: { + auto buf = allocate_buffer(b, e); + restore_v5_serialized_message( + v5::basic_pubrel_message(buf), + buf + ); + } break; + default: + MQTT_LOG("mqtt_api", error) + << MQTT_ADD_VALUE(address, this) + << "invalid control packet type. " + << std::hex << static_cast(fixed_header); + throw protocol_error(); + break; + } + } + + /** + * @brief Restore serialized publish message. + * This function shouold be called before connect. + * @param msg publish message. Empty topic_name is prohibited. + * @param life_keeper + * An object that stays alive (but is moved with force_move()) until the stored message is sent. + */ + void restore_v5_serialized_message(v5::basic_publish_message msg, any life_keeper = {}) { + BOOST_ASSERT(version_ == protocol_version::v5); + BOOST_ASSERT(!msg.topic().empty()); + auto packet_id = msg.packet_id(); + auto qos = msg.get_qos(); + LockGuard lck (store_mtx_); + if (pid_man_.register_id(packet_id)) { + auto ret = store_.emplace( + packet_id, + qos == qos::at_least_once ? control_packet_type::puback + : control_packet_type::pubrec, + force_move(msg), + force_move(life_keeper) + ); + // When client want to restore serialized messages, + // endpoint might keep the message that has the same packet_id. + // In this case, overwrite store_. + if (!ret.second) { + store_.modify( + ret.first, + [&] (auto& e) { + e = store( + packet_id, + qos == qos::at_least_once ? control_packet_type::puback + : control_packet_type::pubrec, + force_move(msg), + force_move(life_keeper) + ); + } + ); + } + } + } + + /** + * @brief Restore serialized pubrel message. + * This function shouold be called before connect. + * @param msg pubrel message. + * @param life_keeper + * An object that stays alive (but is moved with force_move()) until the stored message is sent. + */ + void restore_v5_serialized_message(v5::basic_pubrel_message msg, any life_keeper = {}) { + BOOST_ASSERT(version_ == protocol_version::v5); + auto packet_id = msg.packet_id(); + LockGuard lck (store_mtx_); + if (pid_man_.register_id(packet_id)) { + auto ret = store_.emplace( + packet_id, + control_packet_type::pubcomp, + force_move(msg), + force_move(life_keeper) + ); + // When client want to restore serialized messages, + // endpoint might keep the message that has the same packet_id. + // In this case, overwrite store_. + if (!ret.second) { + store_.modify( + ret.first, + [&] (auto& e) { + e = store( + packet_id, + control_packet_type::pubcomp, + force_move(msg) + ); + } + ); + } + } + } + +private: + struct restore_basic_message_variant_visitor { + restore_basic_message_variant_visitor(this_type& ep, any life_keeper):ep_(ep), life_keeper_(force_move(life_keeper)) {} + + void operator()(basic_publish_message&& msg) { + ep_.restore_serialized_message(force_move(msg), force_move(life_keeper_)); + } + void operator()(basic_pubrel_message&& msg) { + ep_.restore_serialized_message(force_move(msg), force_move(life_keeper_)); + } + void operator()(v5::basic_publish_message&& msg) { + ep_.restore_v5_serialized_message(force_move(msg), force_move(life_keeper_)); + } + void operator()(v5::basic_pubrel_message&& msg) { + ep_.restore_v5_serialized_message(force_move(msg), force_move(life_keeper_)); + } + template + void operator()(T&&) const { + throw restore_type_error(); + } + private: + this_type& ep_; + any life_keeper_; + }; + +public: + void restore_serialized_message(basic_store_message_variant msg, any life_keeper = {}) { + MQTT_NS::visit(restore_basic_message_variant_visitor(*this, force_move(life_keeper)), force_move(msg)); + } + + + void send_store_message(basic_store_message_variant msg, any life_keeper) { + auto publish_proc = + [&](auto msg, auto&& serialize, auto&& receive_maximum_proc) { + auto msg_lk = apply_topic_alias(msg, life_keeper); + if (maximum_packet_size_send_ < size(std::get<0>(msg_lk))) { + throw packet_size_error(); + } + if (preprocess_publish_message( + msg, + life_keeper, + std::forward(serialize), + std::forward(receive_maximum_proc), + true // register packet_id + ) + ) { + do_sync_write(force_move(std::get<0>(msg_lk))); + } + }; + + auto pubrel_proc = + [&](auto msg, auto const& serialize) { + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + + auto packet_id = msg.packet_id(); + + LockGuard lck (store_mtx_); + pid_man_.register_id(packet_id); + auto ret = store_.emplace( + packet_id, + control_packet_type::pubcomp, + msg, + force_move(life_keeper) + ); + (void)ret; + BOOST_ASSERT(ret.second); + (this->*serialize)(msg); + do_sync_write(force_move(msg)); + }; + + MQTT_NS::visit( + make_lambda_visitor( + [this, &publish_proc](v3_1_1::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "send_store_message publish v3.1.1"; + publish_proc( + force_move(m), + &endpoint::on_serialize_publish_message, + [] (auto&&) { return true; } + ); + }, + [this, &pubrel_proc](v3_1_1::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "send_store_message pubrel v3.1.1"; + pubrel_proc(force_move(m), &endpoint::on_serialize_pubrel_message); + }, + [this, &publish_proc](v5::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "send_store_message publish v5"; + publish_proc( + force_move(m), + &endpoint::on_serialize_v5_publish_message, + [this] (v5::basic_publish_message&& msg) { + if (publish_send_count_.load() == publish_send_max_) { + LockGuard lck (publish_send_queue_mtx_); + publish_send_queue_.emplace_back(force_move(msg), false); + return false; + } + else { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "increment publish_send_count_:" << publish_send_count_.load(); + ++publish_send_count_; + } + return true; + } + ); + }, + [this, &pubrel_proc](v5::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "send_store_message pubrel v5"; + { + LockGuard lck (resend_pubrel_mtx_); + resend_pubrel_.insert(m.packet_id()); + } + pubrel_proc(force_move(m), &endpoint::on_serialize_v5_pubrel_message); + } + ), + msg + ); + } + + void async_send_store_message(basic_store_message_variant msg, any life_keeper, async_handler_t func) { + auto publish_proc = + [&](auto msg, auto&& serialize, auto&& receive_maximum_proc) { + auto msg_lk = apply_topic_alias(msg, life_keeper); + if (maximum_packet_size_send_ < size(std::get<0>(msg_lk))) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + if (preprocess_publish_message( + msg, + life_keeper, + std::forward(serialize), + std::forward(receive_maximum_proc), + true // register packet_id + ) + ) { + do_async_write( + force_move(std::get<0>(msg_lk)), + [func = force_move(func), life_keeper = force_move(std::get<1>(msg_lk))] + (error_code ec) { + if (func) func(ec); + } + ); + } + }; + + auto pubrel_proc = + [&](auto msg, auto const& serialize) { + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + + auto packet_id = msg.packet_id(); + + LockGuard lck (store_mtx_); + pid_man_.register_id(packet_id); + auto ret = store_.emplace( + packet_id, + control_packet_type::pubcomp, + msg, + force_move(life_keeper) + ); + (void)ret; + BOOST_ASSERT(ret.second); + (this->*serialize)(msg); + do_async_write(force_move(msg), force_move(func)); + }; + + MQTT_NS::visit( + make_lambda_visitor( + [this, &publish_proc](v3_1_1::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store_message publish v3.1.1"; + publish_proc( + force_move(m), + &endpoint::on_serialize_publish_message, + [] (auto&&) { return true; } + ); + }, + [this, &pubrel_proc](v3_1_1::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store_message pubrel v3.1.1"; + pubrel_proc(force_move(m), &endpoint::on_serialize_pubrel_message); + }, + [this, &publish_proc, &func](v5::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store_message publish v5"; + publish_proc( + force_move(m), + &endpoint::on_serialize_v5_publish_message, + [this, func] (v5::basic_publish_message&& msg) mutable { + if (publish_send_count_.load() == publish_send_max_) { + { + LockGuard lck (publish_send_queue_mtx_); + publish_send_queue_.emplace_back(force_move(msg), true); + } + socket_->post( + [func = force_move(func)] { + // message has already been stored so func should be called with success here + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + } + ); + return false; + } + else { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "increment publish_send_count_:" << publish_send_count_.load(); + ++publish_send_count_; + } + return true; + } + ); + }, + [this, &pubrel_proc](v5::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store_message pubrel v5"; + { + LockGuard lck (resend_pubrel_mtx_); + resend_pubrel_.insert(m.packet_id()); + } + pubrel_proc(force_move(m), &endpoint::on_serialize_v5_pubrel_message); + } + ), + msg + ); + } + + /** + * @brief Check connection status + * @return current connection status + */ + bool connected() const { + return connected_ && mqtt_connected_; + } + + /** + * @brief Check underlying layer connection status + * @return current connection status + */ + bool underlying_connected() const { + return connected_; + } + + /** + * @brief Trigger next mqtt message manually. + * If you call this function, you need to set manual receive mode + * using set_auto_next_read(false); + */ + void async_read_next_message(any session_life_keeper) { + async_read_control_packet_type(force_move(session_life_keeper)); + } + + /** + * @brief Set maximum number of queued message sending. + * When async message sending function called during asynchronous + * processing, the message is enqueued. When current asynchronous + * message is processed, then concatenate queued messages and + * send it. + * This value limits the maximum number of concatenating messages. + * The default value is 1. + * + * @param count maximum number of queued message sending. 0 means infinity. + * + */ + void set_max_queue_send_count(std::size_t count) { + max_queue_send_count_ = count; + } + + /** + * @brief Set maximum size of queued message sending. + * When async message sending function called during asynchronous + * processing, the message is enqueued. When current asynchronous + * message is processed, then concatenate queued messages and + * send it. + * This value limits the maximum size of concatenating messages. + * The default value is 0. + * + * @param size maximum size of queued message sending. 0 means infinity. + * + */ + void set_max_queue_send_size(std::size_t size) { + max_queue_send_size_ = size; + } + + protocol_version get_protocol_version() const { + return version_; + } + + MQTT_NS::socket const& socket() const { + return *socket_; + } + + MQTT_NS::socket& socket() { + return *socket_; + } + + auto get_executor() { + return socket_->get_executor(); + } + + /** + * @brief Set pingresp timeout + * @param tim timeout value + * + * If tim is not zero, when the client sends PINGREQ, set a timer. + * The timer cancels when PINGRESP is received. If the timer is fired, then force_disconnect + * from the client side.
+ * https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901045
+ * 3.1.2.10 Keep Alive + */ + void set_pingresp_timeout(std::chrono::steady_clock::duration tim) { + pingresp_timeout_ = force_move(tim); + } + + /** + * @brief Set maximum packet size that endpoint can receive + * If the endpoint is client, then it sends as CONNECT packet property. + * If the endpoint is server, then it sends as CONNACK packet property. + * If property is manually set, then maximum_packet_size_recv_ is overwritten by the property. + * + * @param size maximum packet size + */ + void set_maximum_packet_size_recv(std::size_t size) { + BOOST_ASSERT(size > 0 && size <= packet_size_no_limit); + maximum_packet_size_recv_ = size; + } + + /** + * @brief Set receive maximum that endpoint can receive + * If the endpoint is client, then it sends as CONNECT packet property. + * If the endpoint is server, then it sends as CONNACK packet property. + * If property is manually set, then publish_recv_max_ is overwritten by the property. + * + * @param size maximum packet size + */ + void set_receive_maximum(receive_maximum_t val) { + BOOST_ASSERT(val > 0); + publish_recv_max_ = val; + } + +protected: + + /** + * @brief Get shared_ptr of socket + * @return reference of std::shared_ptr + */ + std::shared_ptr& socket_sp_ref() { + return socket_; + } + + void async_read_control_packet_type(any session_life_keeper) { + socket_->async_read( + as::buffer(buf_.data(), 1), + [this, self = this->shared_from_this(), session_life_keeper = force_move(session_life_keeper)]( + error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return; + handle_control_packet_type(force_move(session_life_keeper), force_move(self)); + } + ); + } + + bool handle_close_or_error(error_code ec) { + auto call_handler = + [this, ec] () mutable { + connect_requested_ = false; + clean_sub_unsub_inflight(); + if (disconnect_requested_) { + on_close(); + disconnect_requested_ = false; + } + else { + if (!ec) ec = boost::system::errc::make_error_code(boost::system::errc::not_connected); + on_error(ec); + } + }; + + if (connected_) { + if (!ec) return false; + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "handle_close_or_error call shutdown"; + if (async_operation_) { + async_shutdown( + socket(), + [call_handler](error_code) mutable { + call_handler(); + } + ); + } + else { + sync_shutdown(socket()); + call_handler(); + } + } + else { + call_handler(); + } + return true; + } + + void set_connect() { + connected_ = true; + } + + void set_protocol_version(protocol_version version) { + version_ = version; + } + + void clear_session_data() { + LockGuard lck (store_mtx_); + store_.clear(); + pid_man_.clear(); + } + +private: + enum class connection_type { + client, + server + }; + + void update_values_and_props_on_start_connection(v5::properties& props) { + // Check properties and overwrite the values by properties + std::size_t topic_alias_maximum_count = 0; + std::size_t maximum_packet_size_count = 0; + std::size_t receive_maximum_count = 0; + v5::visit_props( + props, + [&](v5::property::topic_alias_maximum const& p) { + if (++topic_alias_maximum_count == 2) { + throw protocol_error(); + return; + } + LockGuard lck (topic_alias_recv_mtx_); + if (p.val() == 0) { + topic_alias_recv_ = nullopt; + } + else { + topic_alias_recv_.emplace(p.val()); + } + }, + [&](v5::property::maximum_packet_size const& p) { + if (++maximum_packet_size_count == 2) { + throw protocol_error(); + return; + } + if (p.val() == 0) { + throw protocol_error(); + return; + } + maximum_packet_size_recv_ = p.val(); + }, + [&](v5::property::receive_maximum const& p) { + if (++receive_maximum_count == 2) { + throw protocol_error(); + return; + } + if (p.val() == 0) { + throw protocol_error(); + return; + } + publish_recv_max_ = p.val(); + }, + [](auto&&) { + } + ); + + // If property is not set, then set property automatically. + if (topic_alias_maximum_count == 0) { + LockGuard lck (topic_alias_recv_mtx_); + if (topic_alias_recv_ && topic_alias_recv_.value().max() != 0) { + props.emplace_back( + MQTT_NS::v5::property::topic_alias_maximum(topic_alias_recv_.value().max()) + ); + } + } + if (maximum_packet_size_count == 0) { + if (maximum_packet_size_recv_ != packet_size_no_limit) { + props.emplace_back( + MQTT_NS::v5::property::maximum_packet_size(static_cast(maximum_packet_size_recv_)) + ); + } + } + if (receive_maximum_count == 0) { + if (publish_recv_max_ != receive_maximum_max) { + props.emplace_back( + MQTT_NS::v5::property::receive_maximum(static_cast(publish_recv_max_)) + ); + } + } + } + + bool set_values_from_props_on_connection(connection_type type, v5::properties const& props) { + +#define MQTT_SEND_ERROR(rc) \ + switch (type) { \ + case connection_type::client: \ + send_error_disconnect(v5::disconnect_reason_code::rc); \ + break; \ + case connection_type::server: \ + send_error_connack(v5::connect_reason_code::rc); \ + break; \ + default: \ + BOOST_ASSERT(false); \ + break; \ + } + + bool ret = true; + std::size_t topic_alias_maximum_count = 0; + std::size_t maximum_packet_size_count = 0; + std::size_t receive_maximum_count = 0; + std::size_t assigned_client_identifier_count = 0; + v5::visit_props( + props, + [&](v5::property::topic_alias_maximum const& p) { + if (++topic_alias_maximum_count == 2) { + MQTT_SEND_ERROR(protocol_error); + ret = false; + return; + } + if (topic_alias_maximum_count > 2) { + ret = false; + return; + } + if (p.val() > 0) { + LockGuard lck (topic_alias_send_mtx_); + topic_alias_send_.emplace(p.val()); + } + }, + [&](v5::property::maximum_packet_size const& p) { + if (++maximum_packet_size_count == 2) { + MQTT_SEND_ERROR(protocol_error); + ret = false; + return; + } + if (maximum_packet_size_count > 2) { + ret = false; + return; + } + if (p.val() == 0) { + MQTT_SEND_ERROR(protocol_error); + ret = false; + return; + } + maximum_packet_size_send_ = p.val(); + }, + [&](v5::property::receive_maximum const& p) { + if (++receive_maximum_count == 2) { + MQTT_SEND_ERROR(protocol_error); + ret = false; + return; + } + if (receive_maximum_count > 2) { + ret = false; + return; + } + if (p.val() == 0) { + MQTT_SEND_ERROR(protocol_error); + ret = false; + return; + } + publish_send_max_ = p.val(); + }, + [&](v5::property::assigned_client_identifier const& p) { + if (type != connection_type::client) { + MQTT_SEND_ERROR(protocol_error); + ret = false; + return; + } + if (++assigned_client_identifier_count == 2) { + MQTT_SEND_ERROR(protocol_error); + ret = false; + return; + } + if (assigned_client_identifier_count > 2) { + ret = false; + return; + } + set_client_id(std::string(p.val())); + }, + [](auto&&) { + } + ); +#undef MQTT_SEND_ERROR + + return ret; + } + + bool check_transferred_length( + std::size_t bytes_transferred, + std::size_t bytes_expected) { + if (bytes_transferred != bytes_expected) { + call_bad_message_error_handlers(); + return false; + } + return true; + } + + bool check_error_and_transferred_length( + error_code ec, + std::size_t bytes_transferred, + std::size_t bytes_expected) { + if (handle_close_or_error(ec)) return false; + if (!check_transferred_length(bytes_transferred, bytes_expected)) return false; + return true; + } + + void call_bad_message_error_handlers() { + clean_sub_unsub_inflight_on_error(boost::system::errc::make_error_code(boost::system::errc::bad_message)); + } + + void call_protocol_error_handlers() { + clean_sub_unsub_inflight_on_error(boost::system::errc::make_error_code(boost::system::errc::protocol_error)); + } + + void shutdown(MQTT_NS::socket& s) { + if (async_operation_) { + async_shutdown(s, [](auto){}); + } + else { + sync_shutdown(s); + } + } + + void sync_shutdown(MQTT_NS::socket& s) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "sync_shutdown"; + if (shutdown_requested_) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "already shutdowned"; + return; + } + shutdown_requested_ = true; + mqtt_connected_ = false; + + error_code ec; + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "clean_shutdown_and_close"; + s.clean_shutdown_and_close(ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "clean_shutdown_and_close ec:" + << ec.message(); + connected_ = false; + } + + void async_shutdown(MQTT_NS::socket& s, async_handler_t func) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "shutdown"; + if (shutdown_requested_) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "already shutdowned"; + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + return; + } + shutdown_requested_ = true; + mqtt_connected_ = false; + + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "async_clean_shutdown_and_close"; + s.async_clean_shutdown_and_close( + [this, func, sp = this->shared_from_this(), ssp = socket_sp_ref()](error_code ec) { // *1 + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "async_clean_shutdown_and_close ec:" + << ec.message(); + tim_shutdown_.cancel(); + connected_ = false; + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + } + ); + // timeout timer set + tim_shutdown_.expires_after(shutdown_timeout); + std::weak_ptr wp(std::static_pointer_cast(this->shared_from_this())); + tim_shutdown_.async_wait( + [this, func, wp = force_move(wp), ssp = socket_sp_ref()](error_code ec) mutable { + if (auto sp = wp.lock()) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "async_shutdown timer ec:" + << ec.message(); + if (!ec) { + // timeout + // tcp_shutdown indirectly cancel stream.async_shutdown() + // and handler is called with error. + // So captured sp at *1 is released. + + // post is for applying strand + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "post force_shutdown_and_close"; + sp->socket().post( + [this, func = force_move(func), sp] { + if (connected_) { + error_code ec; + socket().force_shutdown_and_close(ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "force_shutdown_and_close ec:" + << ec.message(); + connected_ = false; + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + } + } + ); + } + } + } + ); + } + + void send_error_disconnect(v5::disconnect_reason_code rc) { + if (async_operation_) { + auto sp = this->shared_from_this(); + async_disconnect( + rc, + v5::properties{}, + [sp = force_move(sp)] (error_code) mutable { + sp->socket().post( + [sp = force_move(sp)] { + sp->force_disconnect(); + } + ); + } + ); + } + else { + disconnect(rc); + force_disconnect(); + } + } + + void send_error_connack(v5::connect_reason_code rc) { + if (async_operation_) { + auto sp = this->shared_from_this(); + async_connack( + false, + rc, + [sp = force_move(sp)] (error_code) mutable { + sp->socket().post( + [sp = force_move(sp)] { + sp->force_disconnect(); + } + ); + } + ); + } + else { + connack(false, rc); + force_disconnect(); + } + } + + class send_buffer { + public: + send_buffer():buf_(std::make_shared(static_cast(payload_position_), 0)) {} + + std::shared_ptr const& buf() const { + return buf_; + } + + std::shared_ptr& buf() { + return buf_; + } + + std::pair finalize(std::uint8_t fixed_header) { + auto rb = remaining_bytes(buf_->size() - payload_position_); + std::size_t start_position = payload_position_ - rb.size() - 1; + (*buf_)[start_position] = fixed_header; + buf_->replace(start_position + 1, rb.size(), rb); + return std::make_pair( + &(*buf_)[start_position], + buf_->size() - start_position); + } + private: + static constexpr std::size_t payload_position_ = 5; + std::shared_ptr buf_; + }; + + struct store { + store( + packet_id_t id, + control_packet_type type, + basic_store_message_variant smv, + any life_keeper = any()) + : packet_id_(id) + , expected_control_packet_type_(type) + , smv_(force_move(smv)) + , life_keeper_(force_move(life_keeper)) {} + packet_id_t packet_id() const { return packet_id_; } + control_packet_type expected_control_packet_type() const { return expected_control_packet_type_; } + basic_store_message_variant const& message() const { + return smv_; + } + basic_store_message_variant& message() { + return smv_; + } + any const& life_keeper() const { + return life_keeper_; + } + bool is_publish() const { + return + expected_control_packet_type_ == control_packet_type::puback || + expected_control_packet_type_ == control_packet_type::pubrec; + } + + private: + packet_id_t packet_id_; + control_packet_type expected_control_packet_type_; + basic_store_message_variant smv_; + any life_keeper_; + }; + + struct tag_packet_id {}; + struct tag_packet_id_type {}; + struct tag_seq {}; + using mi_store = mi::multi_index_container< + store, + mi::indexed_by< + mi::ordered_unique< + mi::tag, + mi::composite_key< + store, + mi::const_mem_fun< + store, packet_id_t, + &store::packet_id + >, + mi::const_mem_fun< + store, control_packet_type, + &store::expected_control_packet_type + > + > + >, + mi::ordered_non_unique< + mi::tag, + mi::const_mem_fun< + store, packet_id_t, + &store::packet_id + > + >, + mi::sequenced< + mi::tag + > + > + >; + + void handle_control_packet_type(any session_life_keeper, this_type_sp self) { + fixed_header_ = static_cast(buf_.front()); + remaining_length_ = 0; + remaining_length_multiplier_ = 1; + socket_->async_read( + as::buffer(buf_.data(), 1), + [this, self = force_move(self), session_life_keeper = force_move(session_life_keeper)] ( + error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return; + handle_remaining_length(force_move(session_life_keeper), force_move(self)); + } + ); + } + + bool calc_variable_length(std::size_t& v, std::size_t& multiplier, char buf) { + v += (buf & 0b01111111) * multiplier; + multiplier *= 128; + return multiplier <= 128 * 128 * 128 * 128; + } + + void handle_remaining_length(any session_life_keeper, this_type_sp self) { + if (!calc_variable_length(remaining_length_, remaining_length_multiplier_, buf_.front())) { + call_bad_message_error_handlers(); + return; + } + if (buf_.front() & variable_length_continue_flag) { + socket_->async_read( + as::buffer(buf_.data(), 1), + [this, self = force_move(self), session_life_keeper = force_move(session_life_keeper)]( + error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (handle_close_or_error(ec)) { + return; + } + if (bytes_transferred != 1) { + call_bad_message_error_handlers(); + return; + } + handle_remaining_length(force_move(session_life_keeper), force_move(self)); + } + ); + } + else { + auto cpt_opt = get_control_packet_type_with_check(fixed_header_); + if (!cpt_opt) { + call_bad_message_error_handlers(); + return; + } + auto cpt = cpt_opt.value(); + auto check = + [&]() -> bool { + switch (version_) { + case protocol_version::v3_1_1: + switch (cpt) { + case control_packet_type::connect: + case control_packet_type::publish: + case control_packet_type::subscribe: + case control_packet_type::suback: + case control_packet_type::unsubscribe: + return check_is_valid_length(cpt, remaining_length_); + case control_packet_type::connack: + return remaining_length_ == 2; + case control_packet_type::puback: + case control_packet_type::pubrec: + case control_packet_type::pubrel: + case control_packet_type::pubcomp: + case control_packet_type::unsuback: + return remaining_length_ == sizeof(packet_id_t); + case control_packet_type::pingreq: + case control_packet_type::pingresp: + case control_packet_type::disconnect: + return remaining_length_ == 0; + // Even though there is no auth packet type in v3.1.1 + // it's included in the switch case to provide a warning + // about missing enum values if any are missing. + case control_packet_type::auth: + return false; + } + return false; + case protocol_version::v5: + default: + switch (cpt) { + case control_packet_type::connect: + case control_packet_type::publish: + case control_packet_type::subscribe: + case control_packet_type::suback: + case control_packet_type::unsubscribe: + case control_packet_type::connack: + case control_packet_type::puback: + case control_packet_type::pubrec: + case control_packet_type::pubrel: + case control_packet_type::pubcomp: + case control_packet_type::unsuback: + case control_packet_type::disconnect: + case control_packet_type::auth: + return check_is_valid_length(cpt, remaining_length_); + case control_packet_type::pingreq: + case control_packet_type::pingresp: + return remaining_length_ == 0; + } + return false; + } + }; + if (!check()) { + call_protocol_error_handlers(); + return; + } + + process_payload(force_move(session_life_keeper), force_move(self)); + } + } + + void process_payload(any session_life_keeper, this_type_sp self) { + auto control_packet_type = get_control_packet_type(fixed_header_); + switch (control_packet_type) { + case control_packet_type::connect: + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + break; + case control_packet_type::connack: + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + break; + case control_packet_type::publish: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::puback: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::pubrec: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::pubrel: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::pubcomp: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::subscribe: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::suback: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::unsubscribe: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::unsuback: + if (mqtt_connected_) { + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::pingreq: + if (mqtt_connected_) { + process_pingreq(force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::pingresp: + if (mqtt_connected_) { + process_pingresp(force_move(session_life_keeper)); + } + else { + call_protocol_error_handlers(); + } + break; + case control_packet_type::disconnect: + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + break; + case control_packet_type::auth: + (*std::make_shared(*this, remaining_length_ < packet_bulk_read_limit_)) + (force_move(self), force_move(session_life_keeper)); + break; + default: + break; + } + } + + using parse_handler_variant = + variant< + std::conditional_t, + std::uint32_t, + std::uint16_t, + buffer, + v5::properties + >; + using parse_handler = + std::function< + void( + this_type_sp&& spep, + any&& session_life_keeper, + parse_handler_variant, + buffer + ) + >; + + // primitive read functions + void process_nbytes( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + std::size_t size, + parse_handler&& handler + ) { + if (remaining_length_ < size) { + call_protocol_error_handlers(); + return; + } + remaining_length_ -= size; + + if (buf.empty()) { + auto spa = make_shared_ptr_array(size); + auto ptr = spa.get(); + socket_->async_read( + as::buffer(ptr, size), + [ + this, + self = force_move(self), + session_life_keeper = force_move(session_life_keeper), + handler = force_move(handler), + buf = buffer(string_view(ptr, size), force_move(spa)) + ] + (error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, buf.size())) return; + handler( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + buffer() + ); + } + ); + } + else { + if (buf.size() < size) { + call_protocol_error_handlers(); + return; + } + handler( + force_move(self), + force_move(session_life_keeper), + buf.substr(0, size), + buf.substr(size) + ); + } + } + + template + void process_fixed_length( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + parse_handler&& handler + ) { + if (remaining_length_ < Bytes) { + call_protocol_error_handlers(); + return; + } + + remaining_length_ -= Bytes; + + if (buf.empty()) { + socket_->async_read( + as::buffer(buf_.data(), Bytes), + [ + this, + self = force_move(self), + session_life_keeper = force_move(session_life_keeper), + handler = force_move(handler) + ] + (error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, Bytes)) return; + handler( + force_move(self), + force_move(session_life_keeper), + make_two_or_four_byte::apply( + buf_.data(), + std::next(buf_.data(), boost::numeric_cast(Bytes)) + ), + buffer() + ); + } + ); + } + else { + auto val = + make_two_or_four_byte::apply( + buf.data(), + std::next(buf.data(), boost::numeric_cast(Bytes)) + ); + buf.remove_prefix(Bytes); + handler( + force_move(self), + force_move(session_life_keeper), + val, + force_move(buf) + + ); + } + } + + // This function isn't used for remaining lengh. + void process_variable_length( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + parse_handler&& handler + ) { + process_variable_length_impl( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + force_move(handler), + 0, + 1 + ); + } + + void process_variable_length_impl( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + parse_handler&& handler, + std::size_t size, + std::size_t multiplier + ) { + if (remaining_length_ == 0) { + call_protocol_error_handlers(); + return; + } + --remaining_length_; + + // I use rvalue reference parameter to reduce move constructor calling. + // This is a local lambda expression invoked from this function, so + // I can control all callers. + auto proc = + [this] + ( + this_type_sp&& self, + any&& session_life_keeper, + buffer&& buf, + auto&& handler, + std::size_t size, + std::size_t multiplier + ) mutable { + if (!calc_variable_length(size, multiplier, buf.front())) { + call_protocol_error_handlers(); + return; + } + if (buf.front() & variable_length_continue_flag) { + BOOST_ASSERT(!buf.empty()); + buf.remove_prefix(1); + process_variable_length_impl( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + std::forward(handler), + size, + multiplier + ); + } + else { + buf.remove_prefix(1); + handler( + force_move(self), + force_move(session_life_keeper), + size, + force_move(buf) + ); + } + }; + + if (buf.empty()) { + socket_->async_read( + as::buffer(buf_.data(), 1), + [ + this, + self = force_move(self), + session_life_keeper = force_move(session_life_keeper), + handler = force_move(handler), + size, + multiplier, + proc = force_move(proc) + ] + (error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return; + proc( + force_move(self), + force_move(session_life_keeper), + buffer(string_view(buf_.data(), 1)), // buf_'s lifetime is handled by `self` + force_move(handler), + size, + multiplier + ); + } + ); + } + else { + proc( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + force_move(handler), + size, + multiplier + ); + } + } + + void process_packet_id( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + parse_handler&& handler + ) { + process_fixed_length( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + handler = force_move(handler) + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto packet_id = variant_get(var); + if (packet_id == 0) { + call_protocol_error_handlers(); + return; + } + handler( + force_move(self), + force_move(session_life_keeper), + static_cast(packet_id), + force_move(buf) + ); + } + ); + } + + void process_binary( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + parse_handler&& handler + ) { + if (remaining_length_ < 2) { + call_protocol_error_handlers(); + return; + } + process_fixed_length<2>( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + handler = force_move(handler) + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto size = variant_get::type>(var); + if (remaining_length_ < size) { + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + size, + force_move(handler) + ); + } + ); + } + + void process_string( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + parse_handler&& handler + ) { + process_binary( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [this, handler = force_move(handler)] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& str = variant_get(var); + auto r = utf8string::validate_contents(str); + if (r != utf8string::validation::well_formed) { + call_bad_message_error_handlers(); + return; + } + handler( + force_move(self), + force_move(session_life_keeper), + force_move(str), + force_move(buf) + ); + } + ); + } + + + void process_properties( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + parse_handler&& handler + ) { + process_variable_length( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + handler = force_move(handler) + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto property_length = variant_get(var); + if (property_length > remaining_length_) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + if (property_length == 0) { + handler( + force_move(self), + force_move(session_life_keeper), + v5::properties(), + force_move(buf) + ); + return; + } + + if (buf.empty()) { + struct spa_address_len { + shared_ptr_array spa; + char* address; + std::size_t len; + }; + auto result = + [&] () -> spa_address_len { + if (property_length < props_bulk_read_limit_) { + auto spa = make_shared_ptr_array(property_length); + auto ptr = spa.get(); + return + { + force_move(spa), + ptr, + property_length + }; + } + return + { + nullptr, + buf_.data(), + 1 + }; + } (); + socket_->async_read( + as::buffer(result.address, result.len), + [ + this, + handler = force_move(handler), + self = force_move(self), + session_life_keeper = force_move(session_life_keeper), + property_length, + result + ] + (error_code ec, std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, result.len)) return; + process_property_id( + force_move(self), + force_move(session_life_keeper), + buffer(string_view(result.address, result.len), result.spa), + property_length, + v5::properties(), + force_move(handler) + ); + } + ); + } + else { + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + property_length, + v5::properties(), + force_move(handler) + ); + } + } + ); + } + + void process_property_id( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + std::size_t property_length_rest, + v5::properties props, + parse_handler&& handler + ) { + + if (property_length_rest == 0) { + handler( + force_move(self), + force_move(session_life_keeper), + force_move(props), + force_move(buf) + ); + return; + } + + --remaining_length_; + if (buf.empty()) { + socket_->async_read( + as::buffer(buf_.data(), 1), + [ + this, + self = force_move(self), + session_life_keeper = force_move(session_life_keeper), + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, 1)) return; + process_property_body( + force_move(self), + force_move(session_life_keeper), + buffer(), + static_cast(buf_.front()), + property_length_rest - 1, + force_move(props), + force_move(handler) + ); + } + ); + } + else { + auto id = static_cast(buf.front()); + buf.remove_prefix(1); + process_property_body( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + id, + property_length_rest - 1, + force_move(props), + force_move(handler) + ); + } + } + + void process_property_body( + this_type_sp&& self, + any&& session_life_keeper, + buffer buf, + v5::property::id id, + std::size_t property_length_rest, + v5::properties props, + parse_handler&& handler + ) { + + static constexpr std::size_t length_bytes = 2; + + if (property_length_rest == 0) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + + switch (id) { + case v5::property::id::payload_format_indicator: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::payload_format_indicator(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::message_expiry_interval: { + static constexpr std::size_t len = 4; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::message_expiry_interval(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::content_type: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::content_type(force_move(body), true) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::response_topic: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::response_topic(force_move(body), true) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::correlation_data: { + process_binary( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::correlation_data(force_move(body)) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::subscription_identifier: { + process_variable_length( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest, + remaining_length_before = remaining_length_ + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto size = variant_get(var); + auto consumed = remaining_length_before - remaining_length_; + auto rest = property_length_rest - consumed; + props.emplace_back( + v5::property::subscription_identifier(size) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::session_expiry_interval: { + static constexpr std::size_t len = 4; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::session_expiry_interval(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::assigned_client_identifier: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::assigned_client_identifier(force_move(body), true) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + + } break; + case v5::property::id::server_keep_alive: { + static constexpr std::size_t len = 2; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::server_keep_alive(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::authentication_method: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::authentication_method(force_move(body), true) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::authentication_data: { + process_binary( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::authentication_data(force_move(body)) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::request_problem_information: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::request_problem_information(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::will_delay_interval: { + static constexpr std::size_t len = 4; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::will_delay_interval(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::request_response_information: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::request_response_information(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::response_information: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::response_information(force_move(body), true) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::server_reference: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::server_reference(force_move(body), true) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::reason_string: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + auto rest = property_length_rest - length_bytes - body.size(); + props.emplace_back( + v5::property::reason_string(force_move(body), true) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::receive_maximum: { + static constexpr std::size_t len = 2; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::receive_maximum(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::topic_alias_maximum: { + static constexpr std::size_t len = 2; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::topic_alias_maximum(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::topic_alias: { + static constexpr std::size_t len = 2; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::topic_alias(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::maximum_qos: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::maximum_qos(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::retain_available: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::retain_available(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::user_property: { + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + property_length_rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& key = variant_get(var); + auto rest = property_length_rest - length_bytes - key.size(); + process_string( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + [ + this, + props = force_move(props), + handler = force_move(handler), + key = force_move(key), + property_length_rest = rest + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& val = variant_get(var); + auto rest = property_length_rest - length_bytes - val.size(); + props.emplace_back( + v5::property::user_property( + force_move(key), + force_move(val), + true, + true + ) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } + ); + } break; + case v5::property::id::maximum_packet_size: { + static constexpr std::size_t len = 4; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::maximum_packet_size(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::wildcard_subscription_available: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::wildcard_subscription_available(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::subscription_identifier_available: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::subscription_identifier_available(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + case v5::property::id::shared_subscription_available: { + static constexpr std::size_t len = 1; + if (property_length_rest < len) { + send_error_disconnect(v5::disconnect_reason_code::protocol_error); + call_protocol_error_handlers(); + return; + } + process_nbytes( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + len, + [ + this, + props = force_move(props), + handler = force_move(handler), + rest = property_length_rest - len + ] + (this_type_sp&& self, any&& session_life_keeper, parse_handler_variant var, buffer buf) mutable { + auto& body = variant_get(var); + props.emplace_back( + v5::property::shared_subscription_available(body.begin(), body.end()) + ); + process_property_id( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + rest, + force_move(props), + force_move(handler) + ); + } + ); + } break; + } + } + + // process common + + void process_header( + this_type_sp&& self, + any&& session_life_keeper, + bool all_read, + std::size_t header_len, + parse_handler&& handler + ) { + + if (all_read) { + auto spa = make_shared_ptr_array(remaining_length_); + auto ptr = spa.get(); + socket_->async_read( + as::buffer(ptr, remaining_length_), + [ + this, + self = force_move(self), + session_life_keeper = force_move(session_life_keeper), + buf = buffer(string_view(ptr, remaining_length_), force_move(spa)), + handler = force_move(handler) + ] + (error_code ec, std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, remaining_length_)) return; + handler( + force_move(self), + force_move(session_life_keeper), + force_move(buf), + buffer() + ); + } + ); + return; + } + + if (header_len == 0) { + force_move(handler)( + force_move(self), + force_move(session_life_keeper), + buffer(), + buffer() + ); + return; + } + + socket_->async_read( + as::buffer(buf_.data(), header_len), + [ + this, + self = force_move(self), + session_life_keeper = force_move(session_life_keeper), + header_len, + handler = force_move(handler) + ] + (error_code ec, + std::size_t bytes_transferred) mutable { + this->total_bytes_received_ += bytes_transferred; + if (!check_error_and_transferred_length(ec, bytes_transferred, header_len)) return; + handler( + force_move(self), + force_move(session_life_keeper), + buffer(string_view(buf_.data(), header_len)), + buffer() + ); + } + ); + } + + // process connect + + struct process_connect : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_connect; + using process_type_sp = std::shared_ptr; + + process_connect( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + yield { + auto& buf = variant_get(var); + + static constexpr char protocol_name[] = { 0x00, 0x04, 'M', 'Q', 'T', 'T' }; + if (std::memcmp(buf.data(), protocol_name, sizeof(protocol_name)) != 0) { + ep_.call_protocol_error_handlers(); + return; + } + std::size_t i = sizeof(protocol_name); + auto version = static_cast(buf[i++]); + if (version != protocol_version::v3_1_1 && version != protocol_version::v5) { + ep_.call_protocol_error_handlers(); + return; + } + + if (ep_.version_ == protocol_version::undetermined) { + ep_.version_ = version; + } + else if (ep_.version_ != version) { + ep_.call_protocol_error_handlers(); + return; + } + + connect_flag_ = buf[i++]; + + keep_alive_ = make_uint16_t(buf[i], buf[i + 1]); + ep_.clean_start_ = connect_flags::has_clean_start(connect_flag_); + + buf.remove_prefix(header_len_); // consume buffer + if (ep_.version_ == protocol_version::v5) { + // properties + ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + } + else { + (*this)(force_move(spep), force_move(session_life_keeper), v5::properties(), force_move(buf)); + } + } + props_ = force_move(variant_get(var)); + + // client_id + yield ep_.process_string( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + client_id_ = force_move(variant_get(var)); + ep_.set_client_id(std::string(client_id_)); + if (connect_flags::has_will_flag(connect_flag_)) { + if (ep_.version_ == protocol_version::v5) { + // will properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + will_props_ = force_move(variant_get(var)); + } + // will topic + yield ep_.process_string( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + will_topic_ = force_move(variant_get(var)); + // will payload + yield ep_.process_binary( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + will_payload_ = force_move(variant_get(var)); + } + if (connect_flags::has_user_name_flag(connect_flag_)) { + yield ep_.process_string( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + user_name_ = force_move(variant_get(var)); + } + if (connect_flags::has_password_flag(connect_flag_)) { + yield ep_.process_binary( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + password_ = force_move(variant_get(var)); + } + ep_.mqtt_connected_ = true; + { + ep_.publish_send_count_ = 0; + { + LockGuard lck (ep_.resend_pubrel_mtx_); + ep_.resend_pubrel_.clear(); + } + { + LockGuard lck (ep_.publish_received_mtx_); + ep_.publish_received_.clear(); + } + { + LockGuard lck (ep_.publish_send_queue_mtx_); + ep_.publish_send_queue_.clear(); + } + } + if (!ep_.set_values_from_props_on_connection(connection_type::server, props_)) return; + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_connect( + force_move(client_id_), + force_move(user_name_), + force_move(password_), + connect_flags::has_will_flag(connect_flag_) + ? optional(in_place_init, + force_move(will_topic_), + force_move(will_payload_), + connect_flags::has_will_retain(connect_flag_) | connect_flags::will_qos(connect_flag_)) + : optional(nullopt), + ep_.clean_session(), + keep_alive_ + ) + ) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (ep_.on_v5_connect( + force_move(client_id_), + force_move(user_name_), + force_move(password_), + connect_flags::has_will_flag(connect_flag_) + ? optional(in_place_init, + force_move(will_topic_), + force_move(will_payload_), + connect_flags::has_will_retain(connect_flag_) | connect_flags::will_qos(connect_flag_), + force_move(will_props_)) + : optional(nullopt), + ep_.clean_start(), + keep_alive_, + force_move(props_) + ) + ) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + } + } + + private: + static constexpr std::size_t header_len_ = + 2 + // string length + 4 + // "MQTT" string + 1 + // ProtocolVersion + 1 + // ConnectFlag + 2; // KeepAlive + + ep_t& ep_; + bool all_read_; + + char connect_flag_; + std::uint16_t keep_alive_; + v5::properties props_; + buffer client_id_; + v5::properties will_props_; + buffer will_topic_; + buffer will_payload_; + optional user_name_; + optional password_; + }; + friend struct process_connect; + + // process connack + + struct process_connack : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_connack; + using process_type_sp = std::shared_ptr; + + process_connack( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer /*remain_buf*/ = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + yield { + auto& buf = variant_get(var); + session_present_ = is_session_present(buf[0]); + switch (ep_.version_) { + case protocol_version::v3_1_1: + reason_code_ = static_cast(buf[1]); + break; + case protocol_version::v5: + reason_code_ = static_cast(buf[1]); + break; + default: + BOOST_ASSERT(false); + } + buf.remove_prefix(header_len_); // consume buffer + if (ep_.version_ == protocol_version::v5) { + // properties + ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + } + else { + (*this)(force_move(spep), force_move(session_life_keeper), v5::properties(), force_move(buf)); + } + } + props_ = force_move(variant_get(var)); + ep_.mqtt_connected_ = true; + { + ep_.publish_send_count_ = 0; + { + LockGuard lck (ep_.resend_pubrel_mtx_); + ep_.resend_pubrel_.clear(); + } + { + LockGuard lck (ep_.publish_received_mtx_); + ep_.publish_received_.clear(); + } + { + LockGuard lck (ep_.publish_send_queue_mtx_); + ep_.publish_send_queue_.clear(); + } + } + if (!ep_.set_values_from_props_on_connection(connection_type::client, props_)) return; + { + auto connack_proc = + [this] + (any&& session_life_keeper) mutable { + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_connack( + session_present_, + variant_get(reason_code_) + ) + ) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (ep_.on_v5_connack( + session_present_, + variant_get(reason_code_), + force_move(props_) + ) + ) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + }; + + // Note: boost:variant has no featue to query if the variant currently holds a specific type. + // MQTT_CPP could create a type traits function to match the provided type to the index in + // the boost::variant type list, but for now it does not appear to be needed. + if ( ( (0 == variant_idx(reason_code_)) + && (connect_return_code::accepted == variant_get(reason_code_))) + || ( (1 == variant_idx(reason_code_)) + && (v5::connect_reason_code::success == variant_get(reason_code_)))) { + + // If session_present is false, then call clear_session_data(). + // Here is the reason why it works well. + // --- + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078 + // + // If the Server accepts a connection with Clean Start set to 1, the Server + // MUST set Session Present to 0 in the CONNACK packet in addition to setting + // a 0x00 (Success) Reason Code in the CONNACK packet [MQTT-3.2.2-2]. + // + // + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901048 + // + // The Client can avoid implementing its own Session expiry and instead rely on + // the Session Present flag returned from the Server to determine if the Session + // had expired. If the Client does implement its own Session expiry, it needs to + // store the time at which the Session State will be deleted as part of its + // Session State. + // --- + // + // Also it can avoid the following client side and broker side session state + // mismatch autonatically. + // + // --- + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901078 + // + // If the Client does not have Session State and receives Session Present + // set to 1 it MUST close the Network Connection [MQTT-3.2.2-4]. If it + // wishes to restart with a new Session the Client can reconnect using + // Clean Start set to 1. + // If the Client does have Session State and receives Session Present set + // to 0 it MUST discard its Session State if it continues with the Network + // Connection [MQTT-3.2.2-5]. + // --- + if (session_present_) { + if (ep_.async_operation_) { + // Until all stored messages are written to internal send buffer, + // disable further async reading of incoming packets.. + ep_.async_read_on_message_processed_ = false; + auto async_connack_proc = + [ + this, + spep = force_move(spep), + session_life_keeper = force_move(session_life_keeper), + connack_proc = force_move(connack_proc) + ] + () mutable { + // All stored messages are sent, so re-enable reading of incoming packets. + // and notify the end user code that the connack packet was received. + ep_.async_read_on_message_processed_ = true; + connack_proc(force_move(session_life_keeper)); + }; + ep_.async_send_store(force_move(async_connack_proc)); + return; + } + ep_.send_store(); + } + else { + ep_.clear_session_data(); + } + } + connack_proc(force_move(session_life_keeper)); + } + } + } + + private: + static constexpr std::size_t header_len_ = + 1 + // Connect Acknowledge Flags + 1; // Reason Code + + ep_t& ep_; + bool all_read_; + + bool session_present_; + variant reason_code_; + v5::properties props_; + }; + friend struct process_connack; + + // process publish + + struct process_publish : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_publish; + using process_type_sp = std::shared_ptr; + + process_publish( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < min_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + 0, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // topic_name + yield ep_.process_string( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + topic_name_ = force_move(variant_get(var)); + + qos_value_ = publish::get_qos(ep_.fixed_header_); + if (qos_value_ != qos::at_most_once && + qos_value_ != qos::at_least_once && + qos_value_ != qos::exactly_once) { + ep_.call_bad_message_error_handlers(); + return; + } + + if (qos_value_ == qos::at_least_once || + qos_value_ == qos::exactly_once) { + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + } + if (ep_.version_ == protocol_version::v5) { + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + ep_.remaining_length_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + { + auto handler_call = + [&] { + auto check_full = + [&] { + LockGuard lck (ep_.publish_received_mtx_); + if (ep_.publish_received_.size() == ep_.publish_recv_max_) { + return true; + } + ep_.publish_received_.insert(*packet_id_); + return false; + }; + switch (ep_.version_) { + case protocol_version::v3_1_1: + return ep_.on_publish( + packet_id_, + publish_options(ep_.fixed_header_), + force_move(topic_name_), + force_move(variant_get(var)) + ); + case protocol_version::v5: + switch (qos_value_) { + case qos::at_most_once: + break; + // automatically response error using puback / pubrec + // but the connection continues. + // publish handler is not called + case qos::at_least_once: + if (check_full()) { + if (ep_.async_operation_) { + ep_.async_send_puback( + *packet_id_, + v5::puback_reason_code::quota_exceeded, + v5::properties{}, + [](auto){} + ); + } + else { + ep_.send_puback( + *packet_id_, + v5::puback_reason_code::quota_exceeded, + v5::properties{} + ); + } + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + return false; + } + break; + case qos::exactly_once: + if (check_full()) { + if (ep_.async_operation_) { + ep_.async_send_pubrec( + *packet_id_, + v5::pubrec_reason_code::quota_exceeded, + v5::properties{}, + [](auto){} + ); + } + else { + ep_.send_pubrec( + *packet_id_, + v5::pubrec_reason_code::quota_exceeded, + v5::properties{} + ); + } + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + return false; + } + break; + } + if (topic_name_.empty()) { + if (auto topic_alias = get_topic_alias_from_props(props_)) { + if (topic_alias.value() == 0 || + topic_alias.value() > ep_.topic_alias_recv_.value().max()) { + ep_.send_error_disconnect(v5::disconnect_reason_code::topic_alias_invalid); + ep_.call_protocol_error_handlers(); + return false; + } + auto topic_name = [&] { + LockGuard lck (ep_.topic_alias_recv_mtx_); + if (ep_.topic_alias_recv_) { + return ep_.topic_alias_recv_.value().find(topic_alias.value()); + } + return std::string(); + }(); + if (topic_name.empty()) { + MQTT_LOG("mqtt_cb", error) + << MQTT_ADD_VALUE(address, &ep_) + << "no matching topic alias: " + << topic_alias.value(); + ep_.send_error_disconnect(v5::disconnect_reason_code::protocol_error); + ep_.call_protocol_error_handlers(); + return false; + } + else { + topic_name_ = allocate_buffer(topic_name); + } + } + } + else { + if (auto topic_alias = ep_.get_topic_alias_from_props(props_)) { + LockGuard lck (ep_.topic_alias_recv_mtx_); + if (ep_.topic_alias_recv_) { + ep_.topic_alias_recv_.value().insert_or_update(topic_name_, topic_alias.value()); + } + } + } + { + auto ret = ep_.on_v5_publish( + packet_id_, + publish_options(ep_.fixed_header_), + force_move(topic_name_), + force_move(variant_get(var)), + force_move(props_) + ); + return ret; + } + default: + BOOST_ASSERT(false); + } + return false; + }; + switch (qos_value_) { + case qos::at_most_once: + if (handler_call()) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case qos::at_least_once: + if (handler_call()) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + ep_.auto_pub_response( + [this] { + if (ep_.connected_) { + ep_.send_puback( + *packet_id_, + v5::puback_reason_code::success, + v5::properties{} + ); + } + }, + [this] { + if (ep_.connected_) { + ep_.async_send_puback( + *packet_id_, + v5::puback_reason_code::success, + v5::properties{}, + [](auto){} + ); + } + } + ); + } + break; + case qos::exactly_once: + if (ep_.qos2_publish_handled_.find(*packet_id_) == ep_.qos2_publish_handled_.end()) { + if (handler_call()) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + ep_.qos2_publish_handled_.emplace(*packet_id_); + ep_.auto_pub_response( + [this] { + if (ep_.connected_) { + ep_.send_pubrec( + *packet_id_, + v5::pubrec_reason_code::success, + v5::properties{} + ); + } + }, + [this] { + if (ep_.connected_) { + ep_.async_send_pubrec( + *packet_id_, + v5::pubrec_reason_code::success, + v5::properties{}, + [](auto){} + ); + } + } + ); + } + } + else { + // publish has already been handled + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + if (ep_.async_operation_) { + ep_.async_send_pubrec( + *packet_id_, + v5::pubrec_reason_code::success, + v5::properties{}, + [](auto){} + ); + } + else { + ep_.send_pubrec( + *packet_id_, + v5::pubrec_reason_code::success, + v5::properties{} + ); + } + } + break; + } + } + } + } + + private: + static constexpr std::size_t min_len_ = 2; // topic name length + + ep_t& ep_; + bool all_read_; + + buffer topic_name_; + qos qos_value_; + optional packet_id_; + v5::properties props_; + buffer payload_; + }; + friend struct process_publish; + + // process puback + + struct process_puback : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_puback; + using process_type_sp = std::shared_ptr; + + process_puback( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.remaining_length_ == 0) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126 + // If the Remaining Length is 0, there is no reason code & property length + // the value of success is used for reason code, the value of 0 is used for property length + reason_code_ = v5::puback_reason_code::success; + } + else { + // reason_code + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + 1, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + reason_code_ = static_cast(variant_get(var)[0]); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126 + // If the Remaining Length is 0, there is no property length and the value of 0 is used + + if (ep_.remaining_length_ > 0) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + } + auto erased = + [&] { + LockGuard lck (ep_.store_mtx_); + auto& idx = ep_.store_.template get(); + auto r = idx.equal_range(std::make_tuple(packet_id_, control_packet_type::puback)); + + // puback packet_id is not matched to publish + if (std::get<0>(r) == std::get<1>(r)) return false; + + idx.erase(std::get<0>(r), std::get<1>(r)); + ep_.pid_man_.release_id(packet_id_); + return true; + } (); + if (erased) ep_.on_serialize_remove(packet_id_); + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_puback(packet_id_)) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (erased) ep_.send_publish_queue_one(); + if (ep_.on_v5_puback(packet_id_, reason_code_, force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + + + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::puback_reason_code reason_code_; + v5::properties props_; + }; + friend struct process_puback; + + // process pubrec + + struct process_pubrec : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_pubrec; + using process_type_sp = std::shared_ptr; + + process_pubrec( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.remaining_length_ == 0) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136 + // If the Remaining Length is 0, there is no reason code & property length + // the value of success is used for reason code, the value of 0 is used for property length + reason_code_ = v5::pubrec_reason_code::success; + } + else { + // reason_code + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + 1, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + reason_code_ = static_cast(variant_get(var)[0]); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136 + // If the Remaining Length is 0, there is no property length and the value of 0 is used + + if (ep_.remaining_length_ > 0) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + } + auto erased = + [&] { + LockGuard lck (ep_.store_mtx_); + auto& idx = ep_.store_.template get(); + auto r = idx.equal_range(std::make_tuple(packet_id_, control_packet_type::pubrec)); + + // pubrec packet_id is not matched to publish + if (std::get<0>(r) == std::get<1>(r)) return false; + + idx.erase(std::get<0>(r), std::get<1>(r)); + // packet_id should be erased here only if reason_code is error. + // Otherwise the packet_id is continue to be used for pubrel/pubcomp. + if (is_error(reason_code_)) ep_.pid_man_.release_id(packet_id_); + return true; + } (); + { + auto res = + [&] { + auto rc = + [&] { + if (erased) return v5::pubrel_reason_code::success; + return v5::pubrel_reason_code::packet_identifier_not_found; + } (); + ep_.auto_pub_response( + [&] { + if (ep_.connected_) { + ep_.send_pubrel( + packet_id_, + rc, + v5::properties{}, + any{} + ); + } + else { + ep_.store_pubrel( + packet_id_, + rc, + v5::properties{}, + any{} + ); + } + }, + [&] { + if (ep_.connected_) { + ep_.async_send_pubrel( + packet_id_, + rc, + v5::properties{}, + any{}, + [](auto){} + ); + } + else { + ep_.store_pubrel( + packet_id_, + rc, + v5::properties{}, + any{} + ); + } + } + ); + }; + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_pubrec(packet_id_)) { + res(); + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (erased && is_error(reason_code_)) { + ep_.on_serialize_remove(packet_id_); + ep_.send_publish_queue_one(); + } + if (ep_.on_v5_pubrec(packet_id_, reason_code_, force_move(props_))) { + if (!is_error(reason_code_)) res(); + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + } + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::pubrec_reason_code reason_code_; + v5::properties props_; + }; + friend struct process_pubrec; + + struct process_pubrel : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_pubrel; + using process_type_sp = std::shared_ptr; + + process_pubrel( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.remaining_length_ == 0) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146 + // If the Remaining Length is 0, there is no reason code & property length + // the value of success is used for reason code, the value of 0 is used for property length + reason_code_ = v5::pubrel_reason_code::success; + } + else { + // reason_code + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + 1, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + reason_code_ = static_cast(variant_get(var)[0]); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146 + // If the Remaining Length is 0, there is no property length and the value of 0 is used + + if (ep_.remaining_length_ > 0) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + } + + { + auto res = + [&] { + ep_.auto_pub_response( + [&] { + if (ep_.connected_) { + ep_.send_pubcomp( + packet_id_, + static_cast(reason_code_), + v5::properties{} + ); + } + }, + [&] { + if (ep_.connected_) { + ep_.async_send_pubcomp( + packet_id_, + static_cast(reason_code_), + v5::properties{}, + [](auto){} + ); + } + } + ); + }; + ep_.qos2_publish_handled_.erase(packet_id_); + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_pubrel(packet_id_)) { + res(); + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (ep_.on_v5_pubrel(packet_id_, reason_code_, force_move(props_))) { + res(); + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + } + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::pubrel_reason_code reason_code_; + v5::properties props_; + }; + friend struct process_pubrel; + + // process pubcomp + + struct process_pubcomp : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_pubcomp; + using process_type_sp = std::shared_ptr; + + process_pubcomp( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.remaining_length_ == 0) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156 + // If the Remaining Length is 0, there is no reason code & property length + // the value of success is used for reason code, the value of 0 is used for property length + reason_code_ = v5::pubcomp_reason_code::success; + } + else { + // reason_code + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + 1, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + reason_code_ = static_cast(variant_get(var)[0]); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156 + // If the Remaining Length is 0, there is no property length and the value of 0 is used + + if (ep_.remaining_length_ > 0) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + } + auto erased = + [&] { + LockGuard lck (ep_.store_mtx_); + auto& idx = ep_.store_.template get(); + auto r = idx.equal_range(std::make_tuple(packet_id_, control_packet_type::pubcomp)); + + // pubcomp packet_id is not matched to pubrel + if (std::get<0>(r) == std::get<1>(r)) return false; + + idx.erase(std::get<0>(r), std::get<1>(r)); + ep_.pid_man_.release_id(packet_id_); + return true; + } (); + if (erased) ep_.on_serialize_remove(packet_id_); + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_pubcomp(packet_id_)) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if ( + erased && + [&] { + LockGuard lck (ep_.resend_pubrel_mtx_); + return ep_.resend_pubrel_.find(packet_id_) == ep_.resend_pubrel_.end(); + } () + ) { + ep_.send_publish_queue_one(); + } + if (ep_.on_v5_pubcomp(packet_id_, reason_code_, force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + + + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::pubcomp_reason_code reason_code_; + v5::properties props_; + }; + friend struct process_pubcomp; + + // process subscribe + + struct process_subscribe : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_subscribe; + using process_type_sp = std::shared_ptr; + + process_subscribe( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.version_ == protocol_version::v5) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + + while (true) { + // topic_filter including share_name + yield ep_.process_string( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + sn_tf_opt_ = parse_shared_subscription(variant_get(var)); + if (!sn_tf_opt_) { + MQTT_LOG("mqtt_impl", error) + << MQTT_ADD_VALUE(address, &ep_) + << "topic_filter parse error" + << " whole_topic_filter: " + << variant_get(var); + ep_.send_error_disconnect(v5::disconnect_reason_code::protocol_error); + ep_.call_protocol_error_handlers(); + return; + } + + // subscribe options + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + 1, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + sub_opts_opt_.emplace(static_cast(variant_get(var)[0])); + if (sub_opts_opt_.value().get_qos() != qos::at_most_once && + sub_opts_opt_.value().get_qos() != qos::at_least_once && + sub_opts_opt_.value().get_qos() != qos::exactly_once) { + ep_.call_bad_message_error_handlers(); + return; + } + + entries_.emplace_back( + force_move(sn_tf_opt_.value().share_name), + force_move(sn_tf_opt_.value().topic_filter), + sub_opts_opt_.value() + ); + + if (ep_.remaining_length_ == 0) { + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_subscribe(packet_id_, force_move(entries_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (ep_.on_v5_subscribe(packet_id_, force_move(entries_), force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + return; + } + } + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::properties props_; + optional sn_tf_opt_; + optional sub_opts_opt_; + std::vector entries_; + }; + friend struct process_subscribe; + + // process suback + + struct process_suback : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_suback; + using process_type_sp = std::shared_ptr; + + process_suback( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.version_ == protocol_version::v5) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + + // suback reason codes + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + ep_.remaining_length_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + { + LockGuard lck_store (ep_.store_mtx_); + LockGuard lck_sub_unsub (ep_.sub_unsub_inflight_mtx_); + ep_.pid_man_.release_id(packet_id_); + ep_.sub_unsub_inflight_.erase(packet_id_); + } + switch (ep_.version_) { + case protocol_version::v3_1_1: + { + // TODO: We can avoid an allocation by casting the raw bytes of the + // MQTT_NS::buffer that is being parsed, and instead call the suback + // handler with an std::span and the MQTT_NS::buffer (as lifekeeper) + std::vector results; + auto& body = variant_get(var); + results.resize(body.size()); + std::transform( + body.begin(), + body.end(), + results.begin(), + // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180880 + // The SUBACK Packet sent by the Server to the Client MUST + // contain a return code for each Topic Filter/QoS pair. + // This return code MUST either show the maximum QoS that + // was granted for that Subscription or indicate that the + // subscription failed [MQTT-3.8.4-5]. + [&](auto const& e) -> suback_return_code { + return static_cast(e); + } + ); + if (ep_.on_suback(packet_id_, force_move(results))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + } + case protocol_version::v5: + { + // TODO: We can avoid an allocation by casting the raw bytes of the + // MQTT_NS::buffer that is being parsed, and instead call the suback + // handler with an std::span and the MQTT_NS::buffer (as lifekeeper) + std::vector reasons; + auto& body = variant_get(var); + reasons.resize(body.size()); + std::transform( + body.begin(), + body.end(), + reasons.begin(), + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901170 + // The SUBACK packet sent by the Server to the Client MUST + // contain a Reason Code for each Topic Filter/Subscription + // Option pair [MQTT-3.8.4-6]. + // This Reason Code MUST either show the maximum QoS that + // was granted for that Subscription or indicate that the + // subscription failed [MQTT-3.8.4-7]. + [&](auto const& e) { + return static_cast(e); + } + ); + if (ep_.on_v5_suback(packet_id_, force_move(reasons), force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + } + default: + BOOST_ASSERT(false); + } + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::properties props_; + }; + friend struct process_suback; + + // process unsubscribe + + struct process_unsubscribe : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_unsubscribe; + using process_type_sp = std::shared_ptr; + + process_unsubscribe( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.version_ == protocol_version::v5) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + + while (true) { + // topic_filter including share_name + yield ep_.process_string( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + sn_tf_opt_ = parse_shared_subscription(variant_get(var)); + if (!sn_tf_opt_) { + MQTT_LOG("mqtt_impl", error) + << MQTT_ADD_VALUE(address, &ep_) + << "topic_filter parse error" + << " whole_topic_filter: " + << variant_get(var); + ep_.send_error_disconnect(v5::disconnect_reason_code::protocol_error); + ep_.call_protocol_error_handlers(); + return; + } + + entries_.emplace_back( + force_move(sn_tf_opt_.value().share_name), + force_move(sn_tf_opt_.value().topic_filter) + ); + + if (ep_.remaining_length_ == 0) { + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_unsubscribe(packet_id_, force_move(entries_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (ep_.on_v5_unsubscribe(packet_id_, force_move(entries_), force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + return; + } + } + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::properties props_; + optional sn_tf_opt_; + std::vector entries_; + }; + friend struct process_unsubscribe; + + // process unsuback + + struct process_unsuback : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_unsuback; + using process_type_sp = std::shared_ptr; + + process_unsuback( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ < header_len_) { + ep_.call_protocol_error_handlers(); + return; + } + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // packet_id + yield ep_.process_packet_id( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + packet_id_ = force_move(variant_get(var)); + + if (ep_.version_ == protocol_version::v5) { + // properties + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + + // unsuback reason codes + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + ep_.remaining_length_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + auto body = variant_get(var); + reasons_.resize(body.size()); + std::transform( + body.begin(), + body.end(), + reasons_.begin(), + [&](auto const& e) { + return static_cast(e); + } + ); + } + { + LockGuard lck_store (ep_.store_mtx_); + LockGuard lck_sub_unsub (ep_.sub_unsub_inflight_mtx_); + ep_.pid_man_.release_id(packet_id_); + ep_.sub_unsub_inflight_.erase(packet_id_); + } + switch (ep_.version_) { + case protocol_version::v3_1_1: + if (ep_.on_unsuback(packet_id_)) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + case protocol_version::v5: + if (ep_.on_v5_unsuback(packet_id_, force_move(reasons_), force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + break; + default: + BOOST_ASSERT(false); + } + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + packet_id_t packet_id_; + v5::properties props_; + std::vector reasons_; + }; + friend struct process_unsuback; + + // process pingreq + + void process_pingreq( + any session_life_keeper + ) { + static constexpr std::size_t header_len = 0; + + if (remaining_length_ != header_len) { + call_protocol_error_handlers(); + return; + } + if (on_pingreq()) { + on_mqtt_message_processed(force_move(session_life_keeper)); + } + } + + // process pingresp + + void process_pingresp( + any session_life_keeper + ) { + static constexpr std::size_t header_len = 0; + + if (remaining_length_ != header_len) { + call_protocol_error_handlers(); + return; + } + if (on_pingresp()) { + on_mqtt_message_processed(force_move(session_life_keeper)); + } + if (pingresp_timeout_ != std::chrono::steady_clock::duration::zero()) tim_pingresp_.cancel(); + } + + // process disconnect + + struct process_disconnect : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_disconnect; + using process_type_sp = std::shared_ptr; + + process_disconnect( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.remaining_length_ > 0) { + if (ep_.version_ != protocol_version::v5) { + ep_.call_protocol_error_handlers(); + return; + } + + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // reason_code + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + 1, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + reason_code_ = static_cast(variant_get(var)[0]); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901210 + // If the Remaining Length is 0, there is no property length and the value of 0 is used + if (ep_.remaining_length_ > 0) { + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + } + switch (ep_.version_) { + case protocol_version::v3_1_1: + ep_.on_disconnect(); + break; + case protocol_version::v5: + ep_.on_v5_disconnect(reason_code_, force_move(props_)); + break; + default: + BOOST_ASSERT(false); + } + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "receive DISCONNECT call shutdown"; + ep_.shutdown(*ep_.socket_); + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + return; + } + switch (ep_.version_) { + case protocol_version::v3_1_1: + ep_.on_disconnect(); + break; + case protocol_version::v5: + ep_.on_v5_disconnect(reason_code_, force_move(props_)); + break; + default: + BOOST_ASSERT(false); + } + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "receive DISCONNECT call shutdown"; + ep_.shutdown(*ep_.socket_); + ep_.on_mqtt_message_processed( + force_move( + session_life_keeper + ) + ); + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + ep_t& ep_; + bool all_read_; + + v5::disconnect_reason_code reason_code_; + v5::properties props_; + }; + friend struct process_disconnect; + + // process auth + + struct process_auth : as::coroutine, std::enable_shared_from_this { + using ep_t = this_type; + using ep_t_sp = this_type_sp; + using process_type = process_auth; + using process_type_sp = std::shared_ptr; + + process_auth( + ep_t& ep, + bool all_read + ):ep_{ep}, + all_read_{all_read} { + } + void operator()( + ep_t_sp spep, + any&& session_life_keeper, + parse_handler_variant var = std::size_t(0), + buffer remain_buf = buffer() + ) { + reenter(this) { + if (ep_.version_ != protocol_version::v5) { + ep_.call_protocol_error_handlers(); + return; + } + if (ep_.remaining_length_ > 0) { + // header + yield ep_.process_header( + force_move(spep), + std::make_tuple(force_move(session_life_keeper), this->shared_from_this()), + all_read_, + header_len_, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + + // reason_code + yield ep_.process_nbytes( + force_move(spep), + force_move(session_life_keeper), + force_move(variant_get(var)), + 1, + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + reason_code_ = static_cast(variant_get(var)[0]); + + yield ep_.process_properties( + force_move(spep), + force_move(session_life_keeper), + force_move(remain_buf), + [this] + (auto&&... args ) { + (*this)(std::forward(args)...); + } + ); + props_ = force_move(variant_get(var)); + BOOST_ASSERT(ep_.version_ == protocol_version::v5); + if (ep_.on_v5_auth(reason_code_, force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + std::get<0>( + any_cast< + std::tuple + >(session_life_keeper) + ) + ) + ); + } + return; + } + BOOST_ASSERT(ep_.version_ == protocol_version::v5); + if (ep_.on_v5_auth(reason_code_, force_move(props_))) { + ep_.on_mqtt_message_processed( + force_move( + session_life_keeper + ) + ); + } + } + } + + private: + static constexpr std::size_t header_len_ = sizeof(packet_id_t); // Packet Id + + this_type& ep_; + bool all_read_; + + v5::auth_reason_code reason_code_; + v5::properties props_; + }; + friend struct process_auth; + + template + void auto_pub_response(F const& f, AF const& af) { + if (auto_pub_response_) { + if (async_operation_) af(); + else f(); + } + } + + // Blocking senders. + void send_connect( + buffer client_id, + optional user_name, + optional password, + optional w, + std::uint16_t keep_alive_sec, + v5::properties props + ) { + shutdown_requested_ = false; + switch (version_) { + case protocol_version::v3_1_1: + do_sync_write( + v3_1_1::connect_message( + keep_alive_sec, + force_move(client_id), + clean_session(), + force_move(w), + force_move(user_name), + force_move(password) + ) + ); + break; + case protocol_version::v5: + update_values_and_props_on_start_connection(props); + do_sync_write( + v5::connect_message( + keep_alive_sec, + force_move(client_id), + clean_start(), + force_move(w), + force_move(user_name), + force_move(password), + force_move(props) + ) + ); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_connack( + bool session_present, + variant reason_code, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::connack_message( + session_present, + variant_get(reason_code) + ); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + update_values_and_props_on_start_connection(props); + auto msg = v5::connack_message( + session_present, + variant_get(reason_code), + force_move(props) + ); + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + template + std::enable_if_t< + std::is_same< + PublishMessage, + v5::basic_publish_message + >::value + > + remove_topic_alias( + PublishMessage& msg, + any& life_keeper + ) { + if (msg.topic().empty()) { + // Recover topic alias for store + if (auto ta_opt = get_topic_alias_from_props(msg.props())) { + LockGuard lck (topic_alias_send_mtx_); + std::string t; + if (topic_alias_send_) t = topic_alias_send_.value().find(ta_opt.value()); + if (t.empty()) { + MQTT_LOG("mqtt_impl", error) + << MQTT_ADD_VALUE(address, this) + << "publish topic_name is empty, topic alias " << ta_opt.value() + << " is not registered." ; + throw protocol_error(); + } + else { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "topia alias : " << t << " - " << ta_opt.value() << " is recovered for store." ; + auto topic_name_buf = allocate_buffer(t); + msg.set_topic_name(as::buffer(topic_name_buf)); + life_keeper = std::make_tuple(force_move(life_keeper), force_move(topic_name_buf)); + } + } + else { + MQTT_LOG("mqtt_impl", error) + << MQTT_ADD_VALUE(address, this) + << "publish topic_name is empty, no topic alias set."; + throw protocol_error(); + } + } + msg.remove_prop(v5::property::id::topic_alias); + } + + template + std::enable_if_t< + !std::is_same< + PublishMessage, + v5::basic_publish_message + >::value + > + remove_topic_alias(PublishMessage&, any&) {} + + template + std::enable_if_t< + std::is_same< + PublishMessage, + v5::basic_publish_message + >::value, + std::tuple + > + apply_topic_alias(PublishMessage msg, any life_keeper) { + auto clear_topic_name_and_add_topic_alias = + [&](topic_alias_t ta) { + auto topic_name_buf = buffer(); + msg.set_topic_name(as::buffer(topic_name_buf)); + life_keeper = std::make_tuple(force_move(life_keeper), force_move(topic_name_buf)); + msg.add_prop(v5::property::topic_alias(ta)); + }; + + if (msg.topic().empty()) { + if (auto ta_opt = get_topic_alias_from_props(msg.props())) { + LockGuard lck (topic_alias_send_mtx_); + std::string t; + if (topic_alias_send_) t = topic_alias_send_.value().find(ta_opt.value()); + if (t.empty()) { + MQTT_LOG("mqtt_impl", error) + << MQTT_ADD_VALUE(address, this) + << "publish topic_name is empty, topic alias " << ta_opt.value() + << " is not registered." ; + throw protocol_error(); + } + } + else { + MQTT_LOG("mqtt_impl", error) + << MQTT_ADD_VALUE(address, this) + << "publish topic_name is empty, no topic alias set."; + throw protocol_error(); + } + } + else { + if (auto ta_opt = get_topic_alias_from_props(msg.props())) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "topia alias : " << msg.topic() << " - " << ta_opt.value() << " is registered." ; + LockGuard lck (topic_alias_send_mtx_); + if (topic_alias_send_) { + topic_alias_send_.value().insert_or_update( + msg.topic(), + ta_opt.value() + ); + } + } + else if (auto_map_topic_alias_send_) { + LockGuard lck (topic_alias_send_mtx_); + if (topic_alias_send_) { + auto lru_ta = topic_alias_send_.value().get_lru_alias(); + if (auto ta_opt = topic_alias_send_.value().find(msg.topic())) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "topia alias : " << msg.topic() << " - " << ta_opt.value() << " is found." ; + topic_alias_send_.value().insert_or_update(msg.topic(), ta_opt.value()); // update ts + clear_topic_name_and_add_topic_alias(ta_opt.value()); + } + else { + topic_alias_send_.value().insert_or_update(msg.topic(), lru_ta); // remap topic alias + msg.add_prop(v5::property::topic_alias(lru_ta)); + } + } + } + else if (auto_replace_topic_alias_send_) { + LockGuard lck (topic_alias_send_mtx_); + if (topic_alias_send_) { + if (auto ta_opt = topic_alias_send_.value().find(msg.topic())) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "topia alias : " << msg.topic() << " - " << ta_opt.value() << " is found." ; + topic_alias_send_.value().insert_or_update(msg.topic(), ta_opt.value()); // update ts + clear_topic_name_and_add_topic_alias(ta_opt.value()); + } + } + } + } + return std::make_tuple(force_move(msg), force_move(life_keeper)); + } + + template + std::enable_if_t< + !std::is_same< + PublishMessage, + v5::basic_publish_message + >::value, + std::tuple + > + apply_topic_alias(PublishMessage msg, any life_keeper) { + return std::make_tuple(force_move(msg), force_move(life_keeper)); + } + + template + bool preprocess_publish_message( + PublishMessage const& msg, + any life_keeper, + SerializePublish&& serialize_publish, + ReceiveMaximumProc&& receive_maximum_proc, + bool register_pid = false + ) { + auto qos_value = msg.get_qos(); + if (qos_value == qos::at_least_once || qos_value == qos::exactly_once) { + auto store_msg = msg; + remove_topic_alias(store_msg, life_keeper); + store_msg.set_dup(true); + auto packet_id = store_msg.packet_id(); + + LockGuard lck (store_mtx_); + if (register_pid) { + auto ret = pid_man_.register_id(packet_id); + (void)ret; + BOOST_ASSERT(ret); + } + store_.emplace( + packet_id, + qos_value == qos::at_least_once + ? control_packet_type::puback + : control_packet_type::pubrec, + store_msg, + force_move(life_keeper) + ); + (this->*std::forward(serialize_publish))(store_msg); + return std::forward(receive_maximum_proc)(force_move(store_msg)); + } + return true; + } + + template + typename std::enable_if< + as::is_const_buffer_sequence::value + >::type + send_publish( + packet_id_t packet_id, + as::const_buffer topic_name, + ConstBufferSequence payloads, + publish_options pubopts, + v5::properties props, + any life_keeper) { + + auto do_send_publish = + [&](auto msg, auto&& serialize_publish, auto&& receive_maximum_proc) { + auto msg_lk = apply_topic_alias(msg, life_keeper); + if (maximum_packet_size_send_ < size(std::get<0>(msg_lk))) { + if (packet_id != 0) { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + throw packet_size_error(); + } + if (preprocess_publish_message( + msg, + life_keeper, + std::forward(serialize_publish), + std::forward(receive_maximum_proc) + ) + ) { + do_sync_write(force_move(std::get<0>(msg_lk))); + } + }; + + switch (version_) { + case protocol_version::v3_1_1: + do_send_publish( + v3_1_1::basic_publish_message( + packet_id, + topic_name, + force_move(payloads), + pubopts + ), + &endpoint::on_serialize_publish_message, + [] (auto&&) { return true; } + ); + break; + case protocol_version::v5: + do_send_publish( + v5::basic_publish_message( + packet_id, + topic_name, + force_move(payloads), + pubopts, + force_move(props) + ), + &endpoint::on_serialize_v5_publish_message, + [this] (v5::basic_publish_message&& msg) { + if (publish_send_count_.load() == publish_send_max_) { + LockGuard lck (publish_send_queue_mtx_); + publish_send_queue_.emplace_back(force_move(msg), false); + return false; + } + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "increment publish_send_count_:" << publish_send_count_.load(); + ++publish_send_count_; + return true; + } + ); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_puback( + packet_id_t packet_id, + v5::puback_reason_code reason, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_puback_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::basic_puback_message(packet_id, reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + erase_publish_received(packet_id); + } break; + default: + BOOST_ASSERT(false); + break; + } + + on_pub_res_sent(packet_id); + } + + void send_pubrec( + packet_id_t packet_id, + v5::pubrec_reason_code reason, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_pubrec_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::basic_pubrec_message(packet_id, reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + erase_publish_received(packet_id); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_pubrel( + packet_id_t packet_id, + v5::pubrel_reason_code reason, + v5::properties props, + any life_keeper + ) { + + auto impl = + [&](auto msg, auto const& serialize) { + { + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + + LockGuard lck (store_mtx_); + + // insert if not registerd (start from pubrel sending case) + if (pid_man_.register_id(packet_id)) { + LockGuard lck_resend_pubrel (resend_pubrel_mtx_); + resend_pubrel_.insert(packet_id); + } + + auto ret = store_.emplace( + packet_id, + control_packet_type::pubcomp, + msg, + force_move(life_keeper) + ); + // publish store is erased when pubrec is received. + // pubrel store is erased when pubcomp is received. + // If invalid client send pubrec twice with the same packet id, + // then send corresponding pubrel twice is a possible client/server + // implementation. + // In this case, overwrite store_. + if (!ret.second) { + MQTT_LOG("mqtt_impl", warning) + << MQTT_ADD_VALUE(address, this) + << "overwrite pubrel" + << " packet_id:" << packet_id; + store_.modify( + ret.first, + [&] (auto& e) { + e = store( + packet_id, + control_packet_type::pubcomp, + msg, + life_keeper + ); + } + ); + } + } + + (this->*serialize)(msg); + do_sync_write(force_move(msg)); + }; + + switch (version_) { + case protocol_version::v3_1_1: + impl( + v3_1_1::basic_pubrel_message(packet_id), + &endpoint::on_serialize_pubrel_message + ); + break; + case protocol_version::v5: + impl( + v5::basic_pubrel_message(packet_id, reason, force_move(props)), + &endpoint::on_serialize_v5_pubrel_message + ); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void store_pubrel( + packet_id_t packet_id, + v5::pubrel_reason_code reason, + v5::properties props, + any life_keeper + ) { + + auto impl = + [&](auto msg, auto const& serialize) { + { + LockGuard lck (store_mtx_); + + // insert if not registerd (start from pubrel sending case) + pid_man_.register_id(packet_id); + + auto ret = store_.emplace( + packet_id, + control_packet_type::pubcomp, + msg, + force_move(life_keeper) + ); + (void)ret; + BOOST_ASSERT(ret.second); + } + + (this->*serialize)(msg); + }; + + switch (version_) { + case protocol_version::v3_1_1: + impl( + v3_1_1::basic_pubrel_message(packet_id), + &endpoint::on_serialize_pubrel_message + ); + break; + case protocol_version::v5: + impl( + v5::basic_pubrel_message(packet_id, reason, force_move(props)), + &endpoint::on_serialize_v5_pubrel_message + ); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_pubcomp( + packet_id_t packet_id, + v5::pubcomp_reason_code reason, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_pubcomp_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::basic_pubcomp_message(packet_id, reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + + on_pub_res_sent(packet_id); + } + + void send_subscribe( + std::vector> params, + packet_id_t packet_id, + v5::properties props + ) { + for(auto const& p : params) + { + (void)p; + BOOST_ASSERT( + std::get<1>(p).get_qos() == qos::at_most_once || + std::get<1>(p).get_qos() == qos::at_least_once || + std::get<1>(p).get_qos() == qos::exactly_once + ); + } + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_subscribe_message(force_move(params), packet_id); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + throw packet_size_error(); + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::basic_subscribe_message(force_move(params), packet_id, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + throw packet_size_error(); + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_suback( + variant, std::vector> params, + packet_id_t packet_id, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_suback_message( + force_move(variant_get>(params)), + packet_id + ); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::basic_suback_message( + force_move(variant_get>(params)), + packet_id, + force_move(props) + ); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_unsubscribe( + std::vector params, + packet_id_t packet_id, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_unsubscribe_message(force_move(params), packet_id); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + throw packet_size_error(); + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::basic_unsubscribe_message(force_move(params), packet_id, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + throw packet_size_error(); + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_unsuback( + packet_id_t packet_id + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_unsuback_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: + BOOST_ASSERT(false); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_unsuback( + std::vector params, + packet_id_t packet_id, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: + BOOST_ASSERT(false); + break; + case protocol_version::v5: { + auto msg = v5::basic_unsuback_message(force_move(params), packet_id, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_pingreq() { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::pingreq_message(); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + set_pingresp_timer(); + } break; + case protocol_version::v5: { + auto msg = v5::pingreq_message(); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + set_pingresp_timer(); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_pingresp() { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::pingresp_message(); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::pingresp_message(); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_auth( + v5::auth_reason_code reason, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: + BOOST_ASSERT(false); + break; + case protocol_version::v5: { + auto msg = v5::auth_message(reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_disconnect( + v5::disconnect_reason_code reason, + v5::properties props + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::disconnect_message(); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + case protocol_version::v5: { + auto msg = v5::disconnect_message(reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + throw packet_size_error(); + } + do_sync_write(force_move(msg)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void send_store() { + // packet_id has already been registered + LockGuard lck (store_mtx_); + auto& idx = store_.template get(); + for (auto it = idx.begin(), end = idx.end(); it != end;) { + auto msg = it->message(); + MQTT_NS::visit( + make_lambda_visitor( + [&](v3_1_1::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store publish v3.1.1"; + if (maximum_packet_size_send_ < size(m)) { + pid_man_.release_id(m.packet_id()); + MQTT_LOG("mqtt_impl", warning) + << MQTT_ADD_VALUE(address, this) + << "over maximum packet size message removed. packet_id:" << m.packet_id(); + it = idx.erase(it); + return; + } + do_sync_write(m); + ++it; + }, + [&](v3_1_1::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store pubrel v3.1.1"; + do_sync_write(m); + ++it; + }, + [&](v5::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store publish v5"; + any life_keeper; + auto msg_lk = apply_topic_alias(m, force_move(life_keeper)); + if (maximum_packet_size_send_ < size(std::get<0>(msg_lk))) { + pid_man_.release_id(m.packet_id()); + MQTT_LOG("mqtt_impl", warning) + << MQTT_ADD_VALUE(address, this) + << "over maximum packet size message removed. packet_id:" << m.packet_id(); + it = idx.erase(it); + return; + } + if (publish_send_count_.load() == publish_send_max_) { + LockGuard lck (publish_send_queue_mtx_); + publish_send_queue_.emplace_back( + force_move(std::get<0>(msg_lk)), + false, + force_move(std::get<1>(msg_lk)) + ); + } + else { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "increment publish_send_count_:" << publish_send_count_.load(); + ++publish_send_count_; + do_sync_write(force_move(std::get<0>(msg_lk))); + } + ++it; + }, + [&](v5::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store pubrel v5"; + { + LockGuard lck_resend_pubrel (resend_pubrel_mtx_); + resend_pubrel_.insert(m.packet_id()); + } + do_sync_write(m); + ++it; + } + ), + msg + ); + } + } + + // Blocking write + template + void do_sync_write(MessageVariant&& mv) { + boost::system::error_code ec; + if (can_send()) { + on_pre_send(); + total_bytes_sent_ += socket_->write(const_buffer_sequence(mv), ec); + // If ec is set as error, the error will be handled by async_read. + // If `handle_error(ec);` is called here, error_handler would be called twice. + } + } + + // Non blocking (async) senders + void async_send_connect( + buffer client_id, + optional user_name, + optional password, + optional const& w, + std::uint16_t keep_alive_sec, + v5::properties props, + async_handler_t func + ) { + shutdown_requested_ = false; + switch (version_) { + case protocol_version::v3_1_1: + do_async_write( + v3_1_1::connect_message( + keep_alive_sec, + force_move(client_id), + clean_session(), + w, + force_move(user_name), + force_move(password) + ), + force_move(func) + ); + break; + case protocol_version::v5: + update_values_and_props_on_start_connection(props); + do_async_write( + v5::connect_message( + keep_alive_sec, + force_move(client_id), + clean_start(), + w, + force_move(user_name), + force_move(password), + force_move(props) + ), + force_move(func) + ); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_connack( + bool session_present, + variant reason_code, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::connack_message( + session_present, + variant_get(reason_code) + ); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + case protocol_version::v5: { + update_values_and_props_on_start_connection(props); + auto msg = v5::connack_message( + session_present, + variant_get(reason_code), + force_move(props) + ); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + template + typename std::enable_if< + as::is_const_buffer_sequence::value + >::type + async_send_publish( + packet_id_t packet_id, + as::const_buffer topic_name, + ConstBufferSequence payloads, + publish_options pubopts, + v5::properties props, + any life_keeper, + async_handler_t func + ) { + auto do_async_send_publish = + [&](auto msg, auto&& serialize_publish, auto&& receive_maximum_proc) { + auto msg_lk = apply_topic_alias(msg, life_keeper); + if (maximum_packet_size_send_ < size(std::get<0>(msg_lk))) { + if (packet_id != 0) { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + if (preprocess_publish_message( + msg, + life_keeper, + std::forward(serialize_publish), + std::forward(receive_maximum_proc) + ) + ) { + do_async_write( + force_move(std::get<0>(msg_lk)), + [life_keeper = force_move(std::get<1>(msg_lk)), func](error_code ec) { + if (func) func(ec); + } + ); + } + }; + + switch (version_) { + case protocol_version::v3_1_1: + do_async_send_publish( + v3_1_1::basic_publish_message( + packet_id, + topic_name, + force_move(payloads), + pubopts + ), + &endpoint::on_serialize_publish_message, + [] (auto&&) { return true; } + ); + break; + case protocol_version::v5: + do_async_send_publish( + v5::basic_publish_message( + packet_id, + topic_name, + force_move(payloads), + pubopts, + force_move(props) + ), + &endpoint::on_serialize_v5_publish_message, + [this, func] (v5::basic_publish_message&& msg) mutable { + if (publish_send_count_.load() == publish_send_max_) { + { + LockGuard lck (publish_send_queue_mtx_); + publish_send_queue_.emplace_back(force_move(msg), true); + } + socket_->post( + [func = force_move(func)] { + // message has already been stored so func should be called with success here + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + } + ); + return false; + } + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "increment publish_send_count_:" << publish_send_count_.load(); + ++publish_send_count_; + return true; + } + ); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_puback( + packet_id_t packet_id, + v5::puback_reason_code reason, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_puback_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + [this, self = this->shared_from_this(), packet_id, func = force_move(func)] + (error_code ec) { + if (func) func(ec); + on_pub_res_sent(packet_id); + } + ); + } break; + case protocol_version::v5: { + auto msg = v5::basic_puback_message(packet_id, reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + [this, self = this->shared_from_this(), packet_id, func = force_move(func)] + (error_code ec) { + erase_publish_received(packet_id); + if (func) func(ec); + on_pub_res_sent(packet_id); + } + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_pubrec( + packet_id_t packet_id, + v5::pubrec_reason_code reason, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_pubrec_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + case protocol_version::v5: { + auto msg = v5::basic_pubrec_message(packet_id, reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + [this, self = this->shared_from_this(), packet_id, func = force_move(func)] + (error_code ec) { + erase_publish_received(packet_id); + if (func) func(ec); + } + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_pubrel( + packet_id_t packet_id, + v5::pubrel_reason_code reason, + v5::properties props, + any life_keeper, + async_handler_t func + ) { + + auto msg = basic_pubrel_message(packet_id); + + auto impl = + [&](auto msg, auto const& serialize) { + { + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + + LockGuard lck (store_mtx_); + + // insert if not registerd (start from pubrel sending case) + if (pid_man_.register_id(packet_id)) { + LockGuard lck_resend_pubrel (resend_pubrel_mtx_); + resend_pubrel_.insert(packet_id); + } + + auto ret = store_.emplace( + packet_id, + control_packet_type::pubcomp, + msg, + life_keeper + ); + // publish store is erased when pubrec is received. + // pubrel store is erased when pubcomp is received. + // If invalid client send pubrec twice with the same packet id, + // then send corresponding pubrel twice is a possible client/server + // implementation. + // In this case, overwrite store_. + if (!ret.second) { + MQTT_LOG("mqtt_impl", warning) + << MQTT_ADD_VALUE(address, this) + << "overwrite pubrel" + << " packet_id:" << packet_id; + store_.modify( + ret.first, + [&] (auto& e) { + e = store( + packet_id, + control_packet_type::pubcomp, + msg, + life_keeper + ); + } + ); + } + } + + (this->*serialize)(msg); + + do_async_write( + force_move(msg), + [life_keeper = force_move(life_keeper), func = force_move(func)](error_code ec) { + if(func) func(ec); + } + ); + }; + + switch (version_) { + case protocol_version::v3_1_1: + impl( + v3_1_1::basic_pubrel_message(packet_id), + &endpoint::on_serialize_pubrel_message + ); + break; + case protocol_version::v5: + impl( + v5::basic_pubrel_message(packet_id, reason, force_move(props)), + &endpoint::on_serialize_v5_pubrel_message + ); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_pubcomp( + packet_id_t packet_id, + v5::pubcomp_reason_code reason, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_pubcomp_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + [this, self = this->shared_from_this(), packet_id, func = force_move(func)] + (error_code ec) { + if (func) func(ec); + on_pub_res_sent(packet_id); + } + ); + } break; + case protocol_version::v5: { + auto msg = v5::basic_pubcomp_message(packet_id, reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + [this, self = this->shared_from_this(), packet_id, func = force_move(func)] + (error_code ec) { + if (func) func(ec); + on_pub_res_sent(packet_id); + } + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_subscribe( + std::vector> params, + packet_id_t packet_id, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_subscribe_message(force_move(params), packet_id); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + case protocol_version::v5: { + auto msg = v5::basic_subscribe_message(force_move(params), packet_id, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_suback( + variant, std::vector> params, + packet_id_t packet_id, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_suback_message( + force_move(variant_get>(params)), + packet_id + ); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + case protocol_version::v5: { + auto msg = v5::basic_suback_message( + force_move(variant_get>(params)), + packet_id, + force_move(props) + ); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_unsubscribe( + std::vector params, + packet_id_t packet_id, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_unsubscribe_message(force_move(params), packet_id); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + case protocol_version::v5: { + auto msg = v5::basic_unsubscribe_message(force_move(params), packet_id, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + { + LockGuard lck_store (store_mtx_); + pid_man_.release_id(packet_id); + } + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + { + LockGuard lck (sub_unsub_inflight_mtx_); + sub_unsub_inflight_.insert(packet_id); + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_unsuback( + packet_id_t packet_id, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::basic_unsuback_message(packet_id); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + case protocol_version::v5: + BOOST_ASSERT(false); + break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_unsuback( + std::vector params, + packet_id_t packet_id, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: + BOOST_ASSERT(false); + break; + case protocol_version::v5: { + auto msg = v5::basic_unsuback_message(force_move(params), packet_id, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write( + force_move(msg), + force_move(func) + ); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_pingreq(async_handler_t func) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::pingreq_message(); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write(force_move(msg), force_move(func)); + set_pingresp_timer(); + } break; + case protocol_version::v5: { + auto msg = v5::pingreq_message(); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write(force_move(msg), force_move(func)); + set_pingresp_timer(); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_pingresp(async_handler_t func) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::pingresp_message(); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write(force_move(msg), force_move(func)); + } break; + case protocol_version::v5: { + auto msg = v5::pingresp_message(); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write(force_move(msg), force_move(func)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_auth( + v5::auth_reason_code reason, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: + BOOST_ASSERT(false); + break; + case protocol_version::v5: { + auto msg = v5::auth_message(reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write(force_move(msg), force_move(func)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_disconnect( + v5::disconnect_reason_code reason, + v5::properties props, + async_handler_t func + ) { + switch (version_) { + case protocol_version::v3_1_1: { + auto msg = v3_1_1::disconnect_message(); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write(force_move(msg), force_move(func)); + } break; + case protocol_version::v5: { + auto msg = v5::disconnect_message(reason, force_move(props)); + if (maximum_packet_size_send_ < size(msg)) { + socket_->post( + [func = force_move(func)] { + if (func) func(boost::system::errc::make_error_code(boost::system::errc::message_size)); + } + ); + return; + } + do_async_write(force_move(msg), force_move(func)); + } break; + default: + BOOST_ASSERT(false); + break; + } + } + + void async_send_store(std::function func) { + // packet_id has already been registered + auto g = shared_scope_guard( + [func = force_move(func)] { + func(); + } + ); + LockGuard lck (store_mtx_); + if (store_.empty()) { + socket().post( + [g]{} + ); + return; + } + auto& idx = store_.template get(); + for (auto it = idx.begin(), end = idx.end(); it != end;) { + auto msg = it->message(); + MQTT_NS::visit( + make_lambda_visitor( + [&](v3_1_1::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store publish v3.1.1"; + if (maximum_packet_size_send_ < size(m)) { + pid_man_.release_id(m.packet_id()); + MQTT_LOG("mqtt_impl", warning) + << MQTT_ADD_VALUE(address, this) + << "over maximum packet size message removed. packet_id:" << m.packet_id(); + it = idx.erase(it); + return; + } + do_async_write( + m, + [g] + (error_code /*ec*/) { + } + ); + ++it; + }, + [&](v3_1_1::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store pubrel v3.1.1"; + do_async_write( + m, + [g] + (error_code /*ec*/) { + } + ); + ++it; + }, + [&](v5::basic_publish_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store publish v5"; + any life_keeper; + auto msg_lk = apply_topic_alias(m, force_move(life_keeper)); + if (maximum_packet_size_send_ < size(std::get<0>(msg_lk))) { + pid_man_.release_id(m.packet_id()); + MQTT_LOG("mqtt_impl", warning) + << MQTT_ADD_VALUE(address, this) + << "over maximum packet size message removed. packet_id:" << m.packet_id(); + it = idx.erase(it); + return; + } + if (publish_send_count_.load() == publish_send_max_) { + LockGuard lck (publish_send_queue_mtx_); + publish_send_queue_.emplace_back( + force_move(std::get<0>(msg_lk)), + true, + force_move(std::get<1>(msg_lk)) + ); + } + else { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "increment publish_send_count_:" << publish_send_count_.load(); + ++publish_send_count_; + do_async_write( + get_basic_message_variant(force_move(std::get<0>(msg_lk))), + [g, life_keeper = force_move(std::get<1>(msg_lk))] + (error_code /*ec*/) { + } + ); + } + ++it; + }, + [&](v5::basic_pubrel_message& m) { + MQTT_LOG("mqtt_api", info) + << MQTT_ADD_VALUE(address, this) + << "async_send_store pubrel v5"; + { + LockGuard lck_resend_pubrel (resend_pubrel_mtx_); + resend_pubrel_.insert(m.packet_id()); + } + do_async_write( + m, + [g] + (error_code /*ec*/) { + } + ); + ++it; + } + ), + msg + ); + } + } + + // Non blocking (async) write + + class async_packet { + public: + async_packet( + basic_message_variant mv, + async_handler_t h = {}) + : mv_(force_move(mv)) + , handler_(force_move(h)) {} + basic_message_variant const& message() const { + return mv_; + } + basic_message_variant& message() { + return mv_; + } + async_handler_t const& handler() const { return handler_; } + async_handler_t& handler() { return handler_; } + private: + basic_message_variant mv_; + async_handler_t handler_; + }; + + struct write_completion_handler { + write_completion_handler( + std::shared_ptr self, + async_handler_t func, + std::size_t num_of_messages, + std::size_t expected) + :self_(force_move(self)), + func_(force_move(func)), + num_of_messages_(num_of_messages), + bytes_to_transfer_(expected) + { + // write_completion_handler is only constructed in one place + // and a handler is provided in that location. + // Since we don't check that the handler is valid before calling it + // it's a bug if the handler is invalid when constructed. + BOOST_ASSERT(func_); + } + void operator()(error_code ec) const { + func_(ec); + for (std::size_t i = 0; i != num_of_messages_; ++i) { + self_->queue_.pop_front(); + } + if (ec || // Error is handled by async_read. + !self_->connected_) { + while (!self_->queue_.empty()) { + // Handlers for outgoing packets need not be valid. + if (auto&& h = self_->queue_.front().handler()) h(ec); + self_->queue_.pop_front(); + } + return; + } + if (!self_->queue_.empty()) { + self_->do_async_write(); + } + } + void operator()( + error_code ec, + std::size_t bytes_transferred) const { + func_(ec); + self_->total_bytes_sent_ += bytes_transferred; + for (std::size_t i = 0; i != num_of_messages_; ++i) { + self_->queue_.pop_front(); + } + if (ec || // Error is handled by async_read. + !self_->connected_) { + while (!self_->queue_.empty()) { + // Handlers for outgoing packets need not be valid. + if(auto&& h = self_->queue_.front().handler()) h(ec); + self_->queue_.pop_front(); + } + return; + } + if (bytes_to_transfer_ != bytes_transferred) { + while (!self_->queue_.empty()) { + // Handlers for outgoing packets need not be valid. + if(auto&& h = self_->queue_.front().handler()) h(ec); + self_->queue_.pop_front(); + } + throw write_bytes_transferred_error(bytes_to_transfer_, bytes_transferred); + } + if (!self_->queue_.empty()) { + self_->do_async_write(); + } + } + std::shared_ptr self_; + async_handler_t func_; + std::size_t num_of_messages_; + std::size_t bytes_to_transfer_; + }; + + void do_async_write() { + // Only attempt to send up to the user specified maximum items + using difference_t = typename decltype(queue_)::difference_type; + std::size_t iterator_count = (max_queue_send_count_ == 0) + ? queue_.size() + : std::min(max_queue_send_count_, queue_.size()); + auto const& start = queue_.cbegin(); + auto end = std::next(start, boost::numeric_cast(iterator_count)); + + // And further, only up to the specified maximum bytes + std::size_t total_bytes = 0; + std::size_t total_const_buffer_sequence = 0; + for (auto it = start; it != end; ++it) { + auto const& elem = *it; + auto const& mv = elem.message(); + std::size_t const size = MQTT_NS::size(mv); + + // If we hit the byte limit, we don't include this buffer for this send. + if (max_queue_send_size_ != 0 && max_queue_send_size_ < total_bytes + size) { + end = it; + iterator_count = boost::numeric_cast(std::distance(start, end)); + break; + } + total_bytes += size; + total_const_buffer_sequence += num_of_const_buffer_sequence(mv); + } + + std::vector buf; + std::vector handlers; + + buf.reserve(total_const_buffer_sequence); + handlers.reserve(iterator_count); + + for (auto it = start; it != end; ++it) { + auto const& elem = *it; + auto const& mv = elem.message(); + auto const& cbs = const_buffer_sequence(mv); + std::copy(cbs.begin(), cbs.end(), std::back_inserter(buf)); + handlers.emplace_back(elem.handler()); + } + + on_pre_send(); + + socket_->async_write( + force_move(buf), + write_completion_handler( + this->shared_from_this(), + [handlers = force_move(handlers)] + (error_code ec) { + for (auto const& h : handlers) { + if (h) h(ec); + } + }, + iterator_count, + total_bytes + ) + ); + } + + void do_async_write(basic_message_variant mv, async_handler_t func) { + // Move this job to the socket's strand so that it can be queued without mutexes. + socket_->post( + [this, self = this->shared_from_this(), mv = force_move(mv), func = force_move(func)] + () mutable { + if (can_send()) { + queue_.emplace_back(force_move(mv), force_move(func)); + // Only need to start async writes if there was nothing in the queue before the above item. + if (queue_.size() > 1) return; + do_async_write(); + } + else { + // offline async publish is successfully finished, because there's nothing to do. + if (func) func(boost::system::errc::make_error_code(boost::system::errc::success)); + return; + } + } + ); + } + + static constexpr std::uint16_t make_uint16_t(char b1, char b2) { + return + static_cast( + ((static_cast(b1) & 0xff)) << 8 | + (static_cast(b2) & 0xff) + ); + } + + void clean_sub_unsub_inflight() { + LockGuard lck_store (store_mtx_); + LockGuard lck_sub_unsub (sub_unsub_inflight_mtx_); + auto it = sub_unsub_inflight_.begin(); + auto end = sub_unsub_inflight_.end(); + while (it != end) { + pid_man_.release_id(*it); + it = sub_unsub_inflight_.erase(it); + } + } + + void clean_sub_unsub_inflight_on_error(error_code ec) { + clean_sub_unsub_inflight(); + on_error(ec); + } + + void set_pingresp_timer() { + if (pingresp_timeout_ == std::chrono::steady_clock::duration::zero()) return; + if (tim_pingresp_set_) return; + tim_pingresp_set_ = true; + tim_pingresp_.expires_after(pingresp_timeout_); + std::weak_ptr wp(std::static_pointer_cast(this->shared_from_this())); + tim_pingresp_.async_wait( + [wp = force_move(wp)](error_code ec) { + if (auto sp = wp.lock()) { + sp->tim_pingresp_set_ = false; + if (!ec) { + sp->socket().post( + [sp] { + sp->force_disconnect(); + } + ); + } + } + } + ); + } + + void send_publish_queue_one() { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "derement publish_send_count_:" << publish_send_count_.load(); + BOOST_ASSERT(publish_send_count_.load() > 0); + --publish_send_count_; + auto entry = + [&] () -> optional { + LockGuard lck (publish_send_queue_mtx_); + if (publish_send_queue_.empty()) return nullopt; + auto entry = force_move(publish_send_queue_.front()); + publish_send_queue_.pop_front(); + return entry; + } (); + if (!entry) return; + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "increment publish_send_count_:" << publish_send_count_.load(); + ++publish_send_count_; + if (entry.value().async) { + do_async_write( + force_move(entry.value().message), + [life_keeper = force_move(entry.value().life_keeper)] + (error_code) { + } + ); + } + else { + do_sync_write(force_move(entry.value().message)); + } + } + + void erase_publish_received(packet_id_t packet_id) { + LockGuard lck (publish_received_mtx_); + publish_received_.erase(packet_id); + } + + bool can_send() const { + return connected_ && ! shutdown_requested_; + } + + static optional get_topic_alias_from_prop(v5::property_variant const& prop) { + optional val; + v5::visit_prop( + prop, + [&val](v5::property::topic_alias const& p) { + val = p.val(); + }, + [](auto&&) { + } + ); + return val; + } + + static optional get_topic_alias_from_props(v5::properties const& props) { + optional val; + v5::visit_props( + props, + [&val](v5::property::topic_alias const& p) { + val = p.val(); + }, + [](auto&&) { + } + ); + return val; + } + +public: + void set_preauthed_user_name(optional const& user_name) { + preauthed_user_name_ = user_name; + } + optional get_preauthed_user_name() const { + return preauthed_user_name_; + } +private: + optional preauthed_user_name_; + +protected: + // Ensure that only code that knows the *exact* type of an object + // inheriting from this abstract base class can destruct it. + // This avoids issues of the destructor not triggering destruction + // of derived classes, and any member variables contained in them. + // Note: Not virtual to avoid need for a vtable when possible. + ~endpoint() { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "endpoint destroy"; + } + +protected: + bool clean_start_{false}; + +private: + std::shared_ptr socket_; + std::atomic connected_{false}; + std::atomic mqtt_connected_{false}; + std::atomic shutdown_requested_{false}; + + std::string client_id_; + + std::array buf_; + std::uint8_t fixed_header_; + std::size_t remaining_length_multiplier_; + std::size_t remaining_length_; + std::vector payload_; + + Mutex store_mtx_; + mi_store store_; + std::set qos2_publish_handled_; + std::deque queue_; + + packet_id_manager pid_man_; + + Mutex sub_unsub_inflight_mtx_; + std::set sub_unsub_inflight_; + bool auto_pub_response_{true}; + bool async_operation_{ false }; + bool async_read_on_message_processed_ { true }; + bool disconnect_requested_{false}; + bool connect_requested_{false}; + std::size_t max_queue_send_count_{1}; + std::size_t max_queue_send_size_{0}; + protocol_version version_{protocol_version::undetermined}; + std::size_t packet_bulk_read_limit_ = 256; + std::size_t props_bulk_read_limit_ = packet_bulk_read_limit_; + std::size_t total_bytes_sent_ = 0; + std::size_t total_bytes_received_ = 0; + static constexpr std::uint8_t variable_length_continue_flag = 0b10000000; + + std::chrono::steady_clock::duration pingresp_timeout_ = std::chrono::steady_clock::duration::zero(); + as::steady_timer tim_pingresp_; + bool tim_pingresp_set_ = false; + + as::steady_timer tim_shutdown_; + + bool auto_map_topic_alias_send_ = false; + bool auto_replace_topic_alias_send_ = false; + mutable Mutex topic_alias_send_mtx_; + optional topic_alias_send_; + + mutable Mutex topic_alias_recv_mtx_; + optional topic_alias_recv_; + + std::size_t maximum_packet_size_send_ = packet_size_no_limit; + std::size_t maximum_packet_size_recv_ = packet_size_no_limit; + + std::atomic publish_send_count_{0}; + receive_maximum_t publish_send_max_ = receive_maximum_max; + receive_maximum_t publish_recv_max_ = receive_maximum_max; + Mutex publish_received_mtx_; + std::set publish_received_; + struct publish_send_queue_elem { + publish_send_queue_elem( + basic_message_variant message, + bool async, + any life_keeper = any() + ): message{force_move(message)}, + life_keeper{force_move(life_keeper)}, + async{async} + {} + basic_message_variant message; + any life_keeper; + bool async; + }; + Mutex publish_send_queue_mtx_; + std::deque publish_send_queue_; + + mutable Mutex resend_pubrel_mtx_; + std::set resend_pubrel_; +}; + +} // namespace MQTT_NS + +#include + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif // defined(__GNUC__) + +#endif // MQTT_ENDPOINT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/error_code.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/error_code.hpp new file mode 100644 index 000000000..993d70491 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/error_code.hpp @@ -0,0 +1,20 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_ERROR_CODE_HPP) +#define MQTT_ERROR_CODE_HPP + +#include + +#include + +namespace MQTT_NS { + +using error_code = boost::system::error_code; + +} // namespace MQTT_NS + +#endif // MQTT_ERROR_CODE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/exception.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/exception.hpp new file mode 100644 index 000000000..a39843393 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/exception.hpp @@ -0,0 +1,135 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_EXCEPTION_HPP) +#define MQTT_EXCEPTION_HPP + +#include +#include + +#include +#include + +#include +#include + +namespace MQTT_NS { + +struct protocol_error : std::exception { + char const* what() const noexcept override final { + return "protocol error"; + } +}; + +struct malformed_packet_error : std::exception { + char const* what() const noexcept override final { + return "malformed packet error"; + } +}; + +struct remaining_length_error : std::exception { + char const* what() const noexcept override final { + return "remaining length error"; + } +}; + +struct variable_length_error : std::exception { + char const* what() const noexcept override final { + return "variable length error"; + } +}; + +struct utf8string_length_error : std::exception { + char const* what() const noexcept override final { + return "utf8string length error"; + } +}; + +struct utf8string_contents_error : std::exception { + utf8string_contents_error(utf8string::validation r):r(r) {} + char const* what() const noexcept override final { + if (r == utf8string::validation::ill_formed) { + return "utf8string ill_formed"; + } + else { + BOOST_ASSERT(r == utf8string::validation::well_formed_with_non_charactor); + return "utf8string well_formed_with_non_charactor"; + } + } + utf8string::validation r; +}; + +struct will_message_length_error : std::exception { + char const* what() const noexcept override final { + return "will message length error"; + } +}; + +struct password_length_error : std::exception { + char const* what() const noexcept override final { + return "password length error"; + } +}; + +struct bytes_transferred_error : std::exception { + bytes_transferred_error(std::size_t expected, std::size_t actual) { + std::stringstream ss; + ss << "bytes transferred error. expected: " << expected << " actual: " << actual; + msg = ss.str(); + } + char const* what() const noexcept override final { + return msg.data(); + } + std::string msg; +}; + +struct read_bytes_transferred_error : bytes_transferred_error { + read_bytes_transferred_error(std::size_t expected, std::size_t actual) + :bytes_transferred_error(expected, actual) { + msg = "[read] " + msg; + } +}; + +struct write_bytes_transferred_error : bytes_transferred_error { + write_bytes_transferred_error(std::size_t expected, std::size_t actual) + :bytes_transferred_error(expected, actual) { + msg = "[write] " + msg; + } +}; + +struct packet_id_exhausted_error : std::exception { + char const* what() const noexcept override final { + return "packet_id exhausted error"; + } +}; + +struct property_parse_error : std::exception { + char const* what() const noexcept override final { + return "property parse error"; + } +}; + +struct property_length_error : std::exception { + char const* what() const noexcept override final { + return "property length error"; + } +}; + +struct restore_type_error : std::exception { + char const* what() const noexcept override final { + return "restore type error"; + } +}; + +struct packet_size_error : std::exception { + char const* what() const noexcept override final { + return "packet size error"; + } +}; + +} // namespace MQTT_NS + +#endif // MQTT_EXCEPTION_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/fixed_header.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/fixed_header.hpp new file mode 100644 index 000000000..f69f62290 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/fixed_header.hpp @@ -0,0 +1,21 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_FIXED_HEADER_HPP) +#define MQTT_FIXED_HEADER_HPP + +#include +#include + +namespace MQTT_NS { + +constexpr std::uint8_t make_fixed_header(control_packet_type type, std::uint8_t flags) { + return static_cast(type) | (flags & 0x0f); +} + +} // namespace MQTT_NS + +#endif // MQTT_FIXED_HEADER_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/four_byte_util.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/four_byte_util.hpp new file mode 100644 index 000000000..535e93622 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/four_byte_util.hpp @@ -0,0 +1,57 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_FOUR_BYTE_UTIL_HPP) +#define MQTT_FOUR_BYTE_UTIL_HPP + +#include +#include +#include + +#include +#include + +#include + +namespace MQTT_NS { + +inline boost::container::static_vector num_to_4bytes(std::uint32_t val) { + return { + static_cast(val >> 24), + static_cast(val >> 16), + static_cast(val >> 8), + static_cast(val & 0xff) + }; +} + +template +inline void add_uint32_t_to_buf(T& buf, std::uint32_t num) { + buf.push_back(static_cast(num >> 24)); + buf.push_back(static_cast(num >> 16)); + buf.push_back(static_cast(num >> 8)); + buf.push_back(static_cast(num & 0xff)); +} + +template +constexpr std::uint32_t make_uint32_t(It b, It e) { + (void)e; // Avoid warning in release builds about unused variable + BOOST_ASSERT(std::distance(b, e) == 4); + auto b1 = b++; + auto b2 = b++; + auto b3 = b++; + auto b4 = b++; + return + static_cast( + (static_cast(*b1) & 0xff) << 24 | + (static_cast(*b2) & 0xff) << 16 | + (static_cast(*b3) & 0xff) << 8 | + (static_cast(*b4) & 0xff) + ); +} + +} // namespace MQTT_NS + +#endif // MQTT_FOUR_BYTE_UTIL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/hexdump.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/hexdump.hpp new file mode 100644 index 000000000..be839c546 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/hexdump.hpp @@ -0,0 +1,27 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_HEXDUMP_HPP) +#define MQTT_HEXDUMP_HPP + +#include +#include + +#include + +namespace MQTT_NS { + +template +inline void hexdump(std::ostream& os, T const& v) { + for (auto c : v) { + os << std::hex << std::setw(2) << std::setfill('0'); + os << (static_cast(c) & 0xff) << ' '; + } +} + +} // namespace MQTT_NS + +#endif // MQTT_HEXDUMP_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/log.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/log.hpp new file mode 100644 index 000000000..fd460d59d --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/log.hpp @@ -0,0 +1,146 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_LOG_HPP) +#define MQTT_LOG_HPP + +#include +#include +#include + +#if defined(MQTT_USE_LOG) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // defined(MQTT_USE_LOG) + +#include + +namespace MQTT_NS { + +struct channel : std::string { + using std::string::string; +}; + +enum class severity_level { + trace, + debug, + info, + warning, + error, + fatal +}; + +inline std::ostream& operator<<(std::ostream& o, severity_level sev) { + constexpr char const* const str[] { + "trace", + "debug", + "info", + "warning", + "error", + "fatal" + }; + o << str[static_cast(sev)]; + return o; +} + +namespace detail { + +struct null_log { + template + constexpr null_log(Params&&...) {} +}; + +template +inline constexpr null_log const& operator<<(null_log const& o, T const&) { return o; } + +} // namespace detail + +#if defined(MQTT_USE_LOG) + +// template arguments are defined in MQTT_NS +// filter and formatter can distinguish mqtt_cpp's channel and severity by their types +using global_logger_t = boost::log::sources::severity_channel_logger; +inline global_logger_t& logger() { + thread_local global_logger_t l; + return l; +} + +// Normal attributes +BOOST_LOG_ATTRIBUTE_KEYWORD(file, "MqttFile", std::string) +BOOST_LOG_ATTRIBUTE_KEYWORD(line, "MqttLine", unsigned int) +BOOST_LOG_ATTRIBUTE_KEYWORD(function, "MqttFunction", std::string) +BOOST_LOG_ATTRIBUTE_KEYWORD(address, "MqttAddress", void const*) + + +// Take any filterable parameters (FP) +#define MQTT_LOG_FP(chan, sev) \ + BOOST_LOG_STREAM_CHANNEL_SEV(MQTT_NS::logger(), MQTT_NS::channel(chan), sev) \ + << boost::log::add_value(MQTT_NS::file, __FILE__) \ + << boost::log::add_value(MQTT_NS::line, __LINE__) \ + << boost::log::add_value(MQTT_NS::function, BOOST_CURRENT_FUNCTION) + +#define MQTT_GET_LOG_SEV_NUM(lv) BOOST_PP_CAT(MQTT_, lv) + +// Use can set preprocessor macro MQTT_LOG_SEV. +// For example, -DMQTT_LOG_SEV=info, greater or equal to info log is generated at +// compiling time. + +#if !defined(MQTT_LOG_SEV) +#define MQTT_LOG_SEV trace +#endif // !defined(MQTT_LOG_SEV) + +#define MQTT_trace 0 +#define MQTT_debug 1 +#define MQTT_info 2 +#define MQTT_warning 3 +#define MQTT_error 4 +#define MQTT_fatal 5 + +// User can define custom MQTT_LOG implementation +// By default MQTT_LOG_FP is used + + +#if !defined(MQTT_LOG) + +#define MQTT_LOG(chan, sev) \ + BOOST_PP_IF( \ + BOOST_PP_GREATER_EQUAL(MQTT_GET_LOG_SEV_NUM(sev), MQTT_GET_LOG_SEV_NUM(MQTT_LOG_SEV)), \ + MQTT_LOG_FP(chan, MQTT_NS::severity_level::sev), \ + MQTT_NS::detail::null_log(chan, MQTT_NS::severity_level::sev) \ + ) + +#endif // !defined(MQTT_LOG) + +#if !defined(MQTT_ADD_VALUE) + +#define MQTT_ADD_VALUE(name, val) boost::log::add_value((MQTT_NS::name), (val)) + +#endif // !defined(MQTT_ADD_VALUE) + +#else // defined(MQTT_USE_LOG) + +#define MQTT_LOG(chan, sev) MQTT_NS::detail::null_log(chan, MQTT_NS::severity_level::sev) +#define MQTT_ADD_VALUE(name, val) val + +#endif // defined(MQTT_USE_LOG) + +} // namespace MQTT_NS + +#endif // MQTT_LOG_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/message.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/message.hpp new file mode 100644 index 000000000..512da913b --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/message.hpp @@ -0,0 +1,1123 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_MESSAGE_HPP) +#define MQTT_MESSAGE_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +inline namespace v3_1_1 { + +namespace detail_v3_1_1 { + +class header_only_message { +public: + /** + * @brief Create empty header_packet_id_message. + */ + header_only_message(control_packet_type type, std::uint8_t flags) + : message_ { static_cast(make_fixed_header(type, flags)), 0 } + {} + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + return { as::buffer(message_.data(), message_.size()) }; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return message_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 1; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + return std::string(message_.data(), size()); + } +private: + boost::container::static_vector message_; +}; + + +template +class basic_header_packet_id_message; + + + +template +class basic_header_packet_id_message { +public: + /** + * @brief Create empty header_packet_id_message. + */ + basic_header_packet_id_message(control_packet_type type, std::uint8_t flags, typename packet_id_type::type packet_id) + : message_ { static_cast(make_fixed_header(type, flags)), PacketIdBytes } + { + add_packet_id_to_buf::apply(message_, packet_id); + } + + template + basic_header_packet_id_message(Iterator b, Iterator e) { + if (std::distance(b, e) != 2 + PacketIdBytes) throw remaining_length_error(); + if (b[1] != PacketIdBytes) throw remaining_length_error(); + + std::copy(b, e, std::back_inserter(message_)); + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + return { as::buffer(message_.data(), size()) }; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return message_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 1; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + return std::string(message_.data(), size()); + } +protected: + boost::container::static_vector const& message() const { + return message_; + } + +private: + boost::container::static_vector message_; +}; + +} // namespace detail_v3_1_1 + +template +struct basic_puback_message : detail_v3_1_1::basic_header_packet_id_message { + using base = detail_v3_1_1::basic_header_packet_id_message; + basic_puback_message(typename packet_id_type::type packet_id) + : base(control_packet_type::puback, 0b0000, packet_id) + {} +}; + +using puback_message = basic_puback_message<2>; + +template +struct basic_pubrec_message : detail_v3_1_1::basic_header_packet_id_message { + using base = detail_v3_1_1::basic_header_packet_id_message; + basic_pubrec_message(typename packet_id_type::type packet_id) + : base(control_packet_type::pubrec, 0b0000, packet_id) + {} +}; + +using pubrec_message = basic_pubrec_message<2>; + +template +struct basic_pubrel_message : detail_v3_1_1::basic_header_packet_id_message { + using base = detail_v3_1_1::basic_header_packet_id_message; + basic_pubrel_message(typename packet_id_type::type packet_id) + : base(control_packet_type::pubrel, 0b0010, packet_id) + { + } + + basic_pubrel_message(string_view buf) + : base(buf.begin(), buf.end()) + { + } + + /** + * @brief Get packet id + * @return packet_id + */ + typename packet_id_type::type packet_id() const { + return make_packet_id::apply(std::next(base::message().begin(), 2), base::message().end()); + } +}; + +using pubrel_message = basic_pubrel_message<2>; +using pubrel_32_message = basic_pubrel_message<4>; + +template +struct basic_pubcomp_message : detail_v3_1_1::basic_header_packet_id_message { + basic_pubcomp_message(typename packet_id_type::type packet_id) + : detail_v3_1_1::basic_header_packet_id_message(control_packet_type::pubcomp, 0b0000, packet_id) + {} +}; + +using pubcomp_message = basic_pubcomp_message<2>; + +template +struct basic_unsuback_message : detail_v3_1_1::basic_header_packet_id_message { + basic_unsuback_message(typename packet_id_type::type packet_id) + : detail_v3_1_1::basic_header_packet_id_message(control_packet_type::unsuback, 0b0000, packet_id) + {} +}; + +using unsuback_message = basic_unsuback_message<2>; + +struct pingreq_message : detail_v3_1_1::header_only_message { + pingreq_message() + : detail_v3_1_1::header_only_message(control_packet_type::pingreq, 0b0000) + {} +}; + +struct pingresp_message : detail_v3_1_1::header_only_message { + pingresp_message() + : detail_v3_1_1::header_only_message(control_packet_type::pingresp, 0b0000) + {} +}; + +struct disconnect_message : detail_v3_1_1::header_only_message { + disconnect_message() + : detail_v3_1_1::header_only_message(control_packet_type::disconnect, 0b0000) + {} +}; + +class connack_message { +public: + connack_message(bool session_present, connect_return_code return_code) + : message_ { + static_cast(make_fixed_header(control_packet_type::connack, 0b0000)), + 0b0010, + static_cast(session_present ? 1 : 0), + static_cast(return_code) + } + {} + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + return { as::buffer(message_.data(), size()) }; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return message_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 1; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + return std::string(message_.data(), size()); + } + +private: + boost::container::static_vector message_; +}; + +// variable length messages + +class connect_message { +public: + connect_message( + std::uint16_t keep_alive_sec, + buffer client_id, + bool clean_session, + optional w, + optional user_name, + optional password + ) + : fixed_header_(static_cast(make_fixed_header(control_packet_type::connect, 0b0000))), + connect_flags_(0), + // protocol name length, protocol name, protocol level, connect flag, client id length, client id, keep alive + remaining_length_( + 2 + // protocol name length + 4 + // protocol name + 1 + // protocol level + 1 + // connect flag + 2 + // keep alive + 2 + // client id length + client_id.size() // client id + ), + protocol_name_and_level_ { 0x00, 0x04, 'M', 'Q', 'T', 'T', 0x04 }, + client_id_(force_move(client_id)), + client_id_length_buf_{ num_to_2bytes(boost::numeric_cast(client_id_.size())) }, + keep_alive_buf_ { num_to_2bytes(keep_alive_sec) } + { + utf8string_check(client_id_); + if (clean_session) connect_flags_ |= connect_flags::clean_session; + if (user_name) { + utf8string_check(user_name.value()); + connect_flags_ |= connect_flags::user_name_flag; + user_name_ = force_move(user_name.value()); + add_uint16_t_to_buf(user_name_length_buf_, boost::numeric_cast(user_name_.size())); + + remaining_length_ += 2 + user_name_.size(); + } + if (password) { + connect_flags_ |= connect_flags::password_flag; + password_ = force_move(password.value()); + add_uint16_t_to_buf(password_length_buf_, boost::numeric_cast(password_.size())); + + remaining_length_ += 2 + password_.size(); + } + if (w) { + connect_flags_ |= connect_flags::will_flag; + if (w.value().get_retain() == retain::yes) connect_flags_ |= connect_flags::will_retain; + connect_flags::set_will_qos(connect_flags_, w.value().get_qos()); + + utf8string_check(w.value().topic()); + will_topic_name_ = force_move(w.value().topic()); + add_uint16_t_to_buf( + will_topic_name_length_buf_, + boost::numeric_cast(will_topic_name_.size()) + ); + if (w.value().message().size() > 0xffffL) throw will_message_length_error(); + will_message_ = force_move(w.value().message()); + add_uint16_t_to_buf( + will_message_length_buf_, + boost::numeric_cast(will_message_.size())); + + remaining_length_ += 2 + will_topic_name_.size() + 2 + will_message_.size(); + } + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(protocol_name_and_level_.data(), protocol_name_and_level_.size())); + ret.emplace_back(as::buffer(&connect_flags_, 1)); + ret.emplace_back(as::buffer(keep_alive_buf_.data(), keep_alive_buf_.size())); + + ret.emplace_back(as::buffer(client_id_length_buf_.data(), client_id_length_buf_.size())); + ret.emplace_back(as::buffer(client_id_)); + + if (connect_flags::has_will_flag(connect_flags_)) { + ret.emplace_back(as::buffer(will_topic_name_length_buf_.data(), will_topic_name_length_buf_.size())); + ret.emplace_back(as::buffer(will_topic_name_)); + ret.emplace_back(as::buffer(will_message_length_buf_.data(), will_message_length_buf_.size())); + ret.emplace_back(as::buffer(will_message_)); + } + + if (connect_flags::has_user_name_flag(connect_flags_)) { + ret.emplace_back(as::buffer(user_name_length_buf_.data(), user_name_length_buf_.size())); + ret.emplace_back(as::buffer(user_name_)); + } + + if (connect_flags::has_password_flag(connect_flags_)) { + ret.emplace_back(as::buffer(password_length_buf_.data(), password_length_buf_.size())); + ret.emplace_back(as::buffer(password_)); + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return + 1 + // fixed header + 1 + // remaining length + 1 + // protocol name and level + 1 + // connect flags + 1 + // keep alive + + 2 + // client id length, client id + + 2 + // will topic name length, will topic name + 2 + // will message length, will message + 2 + // user name length, user name + 2; // password length, password + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + ret.append(protocol_name_and_level_.data(), protocol_name_and_level_.size()); + ret.push_back(connect_flags_); + ret.append(keep_alive_buf_.data(), keep_alive_buf_.size()); + + ret.append(client_id_length_buf_.data(), client_id_length_buf_.size()); + ret.append(client_id_.data(), client_id_.size()); + + if (connect_flags::has_will_flag(connect_flags_)) { + ret.append(will_topic_name_length_buf_.data(), will_topic_name_length_buf_.size()); + ret.append(will_topic_name_.data(), will_topic_name_.size()); + ret.append(will_message_length_buf_.data(), will_message_length_buf_.size()); + ret.append(will_message_.data(), will_message_.size()); + } + + if (connect_flags::has_user_name_flag(connect_flags_)) { + ret.append(user_name_length_buf_.data(), user_name_length_buf_.size()); + ret.append(user_name_.data(), user_name_.size()); + } + + if (connect_flags::has_password_flag(connect_flags_)) { + ret.append(password_length_buf_.data(), password_length_buf_.size()); + ret.append(password_.data(), password_.size()); + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + char connect_flags_; + + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + + boost::container::static_vector protocol_name_and_level_; + buffer client_id_; + boost::container::static_vector client_id_length_buf_; + + buffer will_topic_name_; + boost::container::static_vector will_topic_name_length_buf_; + buffer will_message_; + boost::container::static_vector will_message_length_buf_; + + buffer user_name_; + boost::container::static_vector user_name_length_buf_; + buffer password_; + boost::container::static_vector password_length_buf_; + + boost::container::static_vector keep_alive_buf_; +}; + +template +class basic_publish_message { +public: + template < + typename ConstBufferSequence, + typename std::enable_if< + as::is_const_buffer_sequence::value, + std::nullptr_t + >::type = nullptr + > + basic_publish_message( + typename packet_id_type::type packet_id, + as::const_buffer topic_name, + ConstBufferSequence payloads, + publish_options pubopts + ) + : fixed_header_(make_fixed_header(control_packet_type::publish, 0b0000) | pubopts.operator std::uint8_t()), + topic_name_(topic_name), + topic_name_length_buf_ { num_to_2bytes(boost::numeric_cast(topic_name.size())) }, + remaining_length_( + 2 // topic name length + + topic_name_.size() // topic name + + ( (pubopts.get_qos() == qos::at_least_once || pubopts.get_qos() == qos::exactly_once) + ? PacketIdBytes // packet_id + : 0) + ) + { + auto b = as::buffer_sequence_begin(payloads); + auto e = as::buffer_sequence_end(payloads); + auto num_of_payloads = static_cast(std::distance(b, e)); + payloads_.reserve(num_of_payloads); + for (; b != e; ++b) { + auto const& payload = *b; + remaining_length_ += payload.size(); + payloads_.push_back(payload); + } + + utf8string_check(topic_name_); + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + if (pubopts.get_qos() == qos::at_least_once || + pubopts.get_qos() == qos::exactly_once) { + packet_id_.reserve(PacketIdBytes); + add_packet_id_to_buf::apply(packet_id_, packet_id); + } + } + + // Used in test code, and to deserialize stored messages. + basic_publish_message(buffer buf) { + if (buf.empty()) throw remaining_length_error(); + fixed_header_ = static_cast(buf.front()); + qos qos_value = get_qos(); + buf.remove_prefix(1); + + if (buf.empty()) throw remaining_length_error(); + auto len_consumed = remaining_length(buf.begin(), buf.end()); + remaining_length_ = std::get<0>(len_consumed); + auto consumed = std::get<1>(len_consumed); + + std::copy( + buf.begin(), + std::next(buf.begin(), static_cast(consumed)), + std::back_inserter(remaining_length_buf_)); + buf.remove_prefix(consumed); + + if (buf.size() < 2) throw remaining_length_error(); + std::copy(buf.begin(), std::next(buf.begin(), 2), std::back_inserter(topic_name_length_buf_)); + auto topic_name_length = make_uint16_t(topic_name_length_buf_.begin(), topic_name_length_buf_.end()); + buf.remove_prefix(2); + + if (buf.size() < topic_name_length) throw remaining_length_error(); + + topic_name_ = as::buffer(buf.substr(0, topic_name_length)); + utf8string_check(topic_name_); + buf.remove_prefix(topic_name_length); + + switch (qos_value) { + case qos::at_most_once: + break; + case qos::at_least_once: + case qos::exactly_once: + if (buf.size() < PacketIdBytes) throw remaining_length_error(); + std::copy(buf.begin(), std::next(buf.begin(), PacketIdBytes), std::back_inserter(packet_id_)); + buf.remove_prefix(PacketIdBytes); + break; + default: + throw protocol_error(); + break; + }; + + if (!buf.empty()) { + payloads_.emplace_back(as::buffer(buf)); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(topic_name_length_buf_.data(), topic_name_length_buf_.size())); + ret.emplace_back(as::buffer(topic_name_)); + if (!packet_id_.empty()) { + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + } + std::copy(payloads_.begin(), payloads_.end(), std::back_inserter(ret)); + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + std::size_t num_of_const_buffer_sequence() const { + return + 1 + // fixed header + 1 + // remaining length + 2 + // topic name length, topic name + (packet_id_.empty() ? 0 : 1) + // packet_id + payloads_.size(); + } + + /** + * @brief Create one continuous buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(topic_name_length_buf_.data(), topic_name_length_buf_.size()); + ret.append(get_pointer(topic_name_), get_size(topic_name_)); + + ret.append(packet_id_.data(), packet_id_.size()); + for (auto const& payload : payloads_) { + ret.append(get_pointer(payload), get_size(payload)); + } + + return ret; + } + + /** + * @brief Get packet id + * @return packet_id + */ + typename packet_id_type::type packet_id() const { + return make_packet_id::apply(packet_id_.begin(), packet_id_.end()); + } + + /** + * @brief Get publish_options + * @return publish_options. + */ + constexpr publish_options get_options() const { + return publish_options(fixed_header_); + } + + /** + * @brief Get qos + * @return qos + */ + constexpr qos get_qos() const { + return publish::get_qos(fixed_header_); + } + + /** + * @brief Check retain flag + * @return true if retain, otherwise return false. + */ + constexpr bool is_retain() const { + return publish::is_retain(fixed_header_); + } + + /** + * @brief Check dup flag + * @return true if dup, otherwise return false. + */ + constexpr bool is_dup() const { + return publish::is_dup(fixed_header_); + } + + /** + * @brief Get topic name + * @return topic name + */ + constexpr string_view topic() const { + return string_view(get_pointer(topic_name_), get_size(topic_name_)); + } + + /** + * @brief Get payload + * @return payload + */ + std::vector payload() const { + std::vector ret; + ret.reserve(payloads_.size()); + for (auto const& payload : payloads_) { + ret.emplace_back(get_pointer(payload), get_size(payload)); + } + return ret; + } + + /** + * @brief Get payload as single buffer + * @return payload + */ + buffer payload_as_buffer() const { + auto size = std::accumulate( + payloads_.begin(), + payloads_.end(), + std::size_t(0), + [](std::size_t s, as::const_buffer const& payload) { + return s += payload.size(); + } + ); + + if (size == 0) return buffer(); + + auto spa = make_shared_ptr_array(size); + auto ptr = spa.get(); + auto it = ptr; + for (auto const& payload : payloads_) { + auto b = get_pointer(payload); + auto s = get_size(payload); + auto e = b + s; + std::copy(b, e, it); + it += s; + } + return buffer(string_view(ptr, size), force_move(spa)); + } + + /** + * @brief Set dup flag + * @param dup flag value to set + */ + constexpr void set_dup(bool dup) { + publish::set_dup(fixed_header_, dup); + } + +private: + std::uint8_t fixed_header_; + as::const_buffer topic_name_; + boost::container::static_vector topic_name_length_buf_; + boost::container::static_vector packet_id_; + std::vector payloads_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; +}; + +using publish_message = basic_publish_message<2>; +using publish_32_message = basic_publish_message<4>; + +template +class basic_subscribe_message { +private: + struct entry { + entry(as::const_buffer topic_name, subscribe_options qos_value) + : topic_name_(topic_name), + topic_name_length_buf_ { num_to_2bytes(boost::numeric_cast(topic_name_.size())) }, + qos_(qos_value.get_qos()) + {} + + as::const_buffer topic_name_; + boost::container::static_vector topic_name_length_buf_; + qos qos_; + }; + +public: + basic_subscribe_message( + std::vector> params, + typename packet_id_type::type packet_id + ) + : fixed_header_(make_fixed_header(control_packet_type::subscribe, 0b0010)), + remaining_length_(PacketIdBytes) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + + // Check for errors before allocating. + for (auto&& e : params) { + as::const_buffer topic_name = std::get<0>(e); + utf8string_check(topic_name); + } + + entries_.reserve(params.size()); + for (auto&& e : params) { + as::const_buffer topic_name = std::get<0>(e); + size_t size = topic_name.size(); + + entries_.emplace_back(topic_name, std::get<1>(e)); + remaining_length_ += + 2 + // topic name length + size + // topic name + 1; // means QoS + } + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + for (auto const& e : entries_) { + ret.emplace_back(as::buffer(e.topic_name_length_buf_.data(), e.topic_name_length_buf_.size())); + ret.emplace_back(as::buffer(e.topic_name_)); + ret.emplace_back(as::buffer(&e.qos_, 1)); + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + std::size_t num_of_const_buffer_sequence() const { + return + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + entries_.size() * 3; // topic name length, topic name, qos + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(packet_id_.data(), packet_id_.size()); + + for (auto const& e : entries_) { + ret.append(e.topic_name_length_buf_.data(), e.topic_name_length_buf_.size()); + ret.append(get_pointer(e.topic_name_), get_size(e.topic_name_)); + ret.push_back(static_cast(e.qos_)); + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + std::vector entries_; + boost::container::static_vector packet_id_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; +}; + +using subscribe_message = basic_subscribe_message<2>; + +template +class basic_suback_message { +public: + basic_suback_message( + std::vector params, + typename packet_id_type::type packet_id + ) + : fixed_header_(make_fixed_header(control_packet_type::suback, 0b0000)), + remaining_length_(params.size() + PacketIdBytes) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + // TODO: We should be able to simply static-cast params.data() into a char*. + entries_.reserve(params.size()); + for (auto e : params) { + entries_.push_back(static_cast(e)); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + ret.emplace_back(as::buffer(entries_)); + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 4; // fixed header, remaining length, packet_id, entries + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(packet_id_.data(), packet_id_.size()); + ret.append(entries_); + + return ret; + } + +private: + std::uint8_t fixed_header_; + std::string entries_; + boost::container::static_vector packet_id_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; +}; + +using suback_message = basic_suback_message<2>; + +template +class basic_unsubscribe_message { +private: + struct entry { + entry(as::const_buffer topic_name) + : topic_name_(force_move(topic_name)), + topic_name_length_buf_ { num_to_2bytes(boost::numeric_cast(topic_name_.size())) } + {} + + as::const_buffer topic_name_; + boost::container::static_vector topic_name_length_buf_; + }; + +public: + basic_unsubscribe_message( + std::vector params, + typename packet_id_type::type packet_id + ) + : fixed_header_(make_fixed_header(control_packet_type::unsubscribe, 0b0010)), + remaining_length_(PacketIdBytes) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + + // Check for errors before allocating. + for (auto&& e : params) { + utf8string_check(e); + } + + entries_.reserve(params.size()); + for (auto&& e : params) { + entries_.emplace_back(e); + remaining_length_ += + 2 + // topic name length + e.size(); // topic name + } + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + for (auto const& e : entries_) { + ret.emplace_back(as::buffer(e.topic_name_length_buf_.data(), e.topic_name_length_buf_.size())); + ret.emplace_back(as::buffer(e.topic_name_)); + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + std::size_t num_of_const_buffer_sequence() const { + return + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + entries_.size() * 2; // topic name length, topic name + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(packet_id_.data(), packet_id_.size()); + + for (auto const& e : entries_) { + ret.append(e.topic_name_length_buf_.data(), e.topic_name_length_buf_.size()); + ret.append(get_pointer(e.topic_name_), get_size(e.topic_name_)); + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + std::vector entries_; + boost::container::static_vector packet_id_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; +}; + +using unsubscribe_message = basic_unsubscribe_message<2>; + +} // inline namespace v3_1_1 + +} // namespace MQTT_NS + +#endif // MQTT_MESSAGE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/message_variant.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/message_variant.hpp new file mode 100644 index 000000000..d78df6ea5 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/message_variant.hpp @@ -0,0 +1,147 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_MESSAGE_VARIANT_HPP) +#define MQTT_MESSAGE_VARIANT_HPP + +#include +#include +#include +#include + +namespace MQTT_NS { + +// message_variant + +template +using basic_message_variant = variant< + v3_1_1::connect_message, + v3_1_1::connack_message, + v3_1_1::basic_publish_message, + v3_1_1::basic_puback_message, + v3_1_1::basic_pubrec_message, + v3_1_1::basic_pubrel_message, + v3_1_1::basic_pubcomp_message, + v3_1_1::basic_subscribe_message, + v3_1_1::basic_suback_message, + v3_1_1::basic_unsubscribe_message, + v3_1_1::basic_unsuback_message, + v3_1_1::pingreq_message, + v3_1_1::pingresp_message, + v3_1_1::disconnect_message, + v5::connect_message, + v5::connack_message, + v5::basic_publish_message, + v5::basic_puback_message, + v5::basic_pubrec_message, + v5::basic_pubrel_message, + v5::basic_pubcomp_message, + v5::basic_subscribe_message, + v5::basic_suback_message, + v5::basic_unsubscribe_message, + v5::basic_unsuback_message, + v5::pingreq_message, + v5::pingresp_message, + v5::disconnect_message, + v5::auth_message +>; + +using message_variant = basic_message_variant<2>; + +namespace detail { + +struct const_buffer_sequence_visitor { + template + std::vector operator()(T&& t) const { + return t.const_buffer_sequence(); + } +}; + +struct size_visitor { + template + std::size_t operator()(T&& t) const { + return t.size(); + } +}; + +struct num_of_const_buffer_sequence_visitor { + template + std::size_t operator()(T&& t) const { + return t.num_of_const_buffer_sequence(); + } +}; + +struct continuous_buffer_visitor { + template + std::string operator()(T&& t) const { + return std::forward(t).continuous_buffer(); + } +}; + +} // namespace detail + +template +inline std::vector const_buffer_sequence( + basic_message_variant const& mv) { + return MQTT_NS::visit(detail::const_buffer_sequence_visitor(), mv); +} + +template +inline std::size_t size(basic_message_variant const& mv) { + return MQTT_NS::visit(detail::size_visitor(), mv); +} + +template +inline std::size_t num_of_const_buffer_sequence( + basic_message_variant const& mv) { + return MQTT_NS::visit(detail::num_of_const_buffer_sequence_visitor(), mv); +} + +template +inline std::string continuous_buffer(basic_message_variant const& mv) { + return MQTT_NS::visit(detail::continuous_buffer_visitor(), mv); +} + + +// store_message_variant + +template +using basic_store_message_variant = variant< + v3_1_1::basic_publish_message, + v3_1_1::basic_pubrel_message, + v5::basic_publish_message, + v5::basic_pubrel_message +>; + +using store_message_variant = basic_store_message_variant<2>; + +namespace detail { + +template +struct basic_message_variant_visitor { + template + basic_message_variant operator()(T const& t) const { + return t; + } +}; + +} // detail + +template +inline +basic_message_variant get_basic_message_variant( + basic_store_message_variant smv) { + return MQTT_NS::visit(detail::basic_message_variant_visitor(), smv); +} + +template +inline std::string continuous_buffer(basic_store_message_variant const& mv) { + return MQTT_NS::visit(detail::continuous_buffer_visitor(), mv); +} + +} // namespace MQTT_NS + +#endif // MQTT_MESSAGE_VARIANT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/move.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/move.hpp new file mode 100644 index 000000000..c7b5ab9dc --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/move.hpp @@ -0,0 +1,27 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_MOVE_HPP) +#define MQTT_MOVE_HPP + +#include +#include + +#include + +namespace MQTT_NS { + +template +constexpr +typename std::remove_reference_t&& +force_move(T&& t) { + static_assert(!std::is_const>::value, "T is const. Fallback to copy."); + return std::move(t); +} + +} // namespace MQTT_NS + +#endif // MQTT_MOVE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/namespace.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/namespace.hpp new file mode 100644 index 000000000..da2cb31a5 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/namespace.hpp @@ -0,0 +1,14 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_NAMESPACE_HPP) +#define MQTT_NAMESPACE_HPP + +#if !defined(MQTT_NS) +#define MQTT_NS mqtt +#endif // !defined(MQTT_NS) + +#endif // MQTT_NAMESPACE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/null_strand.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/null_strand.hpp new file mode 100644 index 000000000..6ca44c12c --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/null_strand.hpp @@ -0,0 +1,100 @@ +// Copyright Takatoshi Kondo 2016 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_NULL_STRAND_HPP) +#define MQTT_NULL_STRAND_HPP + +#include + +#include + +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +// Determines which strand to use +#if defined(MQTT_NO_TS_EXECUTORS) + +// Using standard executor style null_strand / simple executor +using null_strand = as::io_context::executor_type; + +#else // defined(MQTT_NO_TS_EXECUTORS) + +namespace detail { + +struct null_strand { + explicit null_strand(as::io_context& ioc) noexcept : ioc_(ioc) {} + template + void post(Func&& f, Allocator) const { + as::post( + ioc_, + [f = std::forward(f)] () mutable { + std::move(f)(); + } + ); + } + template + void defer(Func&& f, Allocator) const { + as::defer( + ioc_, + [f = std::forward(f)] () mutable { + std::move(f)(); + } + ); + } + template + void dispatch(Func&& f, Allocator) const { + as::dispatch( + ioc_, + [f = std::forward(f)] () mutable { + std::move(f)(); + } + ); + } + bool running_in_this_thread() const noexcept { return false; } + void on_work_started() const noexcept {} + void on_work_finished() const noexcept {} + as::io_context& context() noexcept{ return ioc_; } + as::io_context const& context() const noexcept { return ioc_; } +private: + as::io_context& ioc_; +}; + +} // namespace detail + +// Use networking TS style null_strand +using null_strand = detail::null_strand; + +inline bool operator==(null_strand const& lhs, null_strand const& rhs) { + return std::addressof(lhs) == std::addressof(rhs); +} + +inline bool operator!=(null_strand const& lhs, null_strand const& rhs) { + return !(lhs == rhs); +} + +#endif // defined(MQTT_NO_TS_EXECUTORS) + +} // namespace MQTT_NS + + +#if !defined(MQTT_NO_TS_EXECUTORS) + +namespace boost { +namespace asio { + +template<> +struct is_executor : std::true_type { +}; + +} // namespace asio +} // namespace boost + +#endif // !defined(MQTT_NO_TS_EXECUTORS) + +#endif // MQTT_NULL_STRAND_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/optional.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/optional.hpp new file mode 100644 index 000000000..143f74424 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/optional.hpp @@ -0,0 +1,43 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_OPTIONAL_HPP) +#define MQTT_OPTIONAL_HPP + +#if defined(MQTT_STD_OPTIONAL) + +#include + +#else // defined(MQTT_STD_OPTIONAL) + +#include + +#endif // defined(MQTT_STD_VARIANT) + +#include + +namespace MQTT_NS { + +#if defined(MQTT_STD_OPTIONAL) + +using std::optional; +using std::nullopt_t; +using in_place_t = std::in_place_t; +static constexpr auto in_place_init = in_place_t{}; +static constexpr auto nullopt = std::nullopt; + +#else // defined(MQTT_STD_OPTIONAL) + +using boost::optional; +using nullopt_t = boost::none_t; +using boost::in_place_init; +static const auto nullopt = boost::none; + +#endif // defined(MQTT_STD_OPTIONAL) + +} // namespace MQTT_NS + +#endif // MQTT_OPTIONAL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/packet_id_manager.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/packet_id_manager.hpp new file mode 100644 index 000000000..36d40b656 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/packet_id_manager.hpp @@ -0,0 +1,69 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PACKET_ID_MANAGER_HPP) +#define MQTT_PACKET_ID_MANAGER_HPP + +#include // should be top to configure variant limit + +#include +#include + +namespace MQTT_NS { + +template +class packet_id_manager { + using packet_id_t = PacketId; + +public: + + /** + * @brief Acquire the new unique packet id. + * If all packet ids are already in use, then returns nullopt + * After acquiring the packet id, you can call acquired_* functions. + * The ownership of packet id is moved to the library. + * Or you can call release_packet_id to release it. + * @return packet id + */ + optional acquire_unique_id() { + return va_.allocate(); + } + + /** + * @brief Register packet_id to the library. + * After registering the packet_id, you can call acquired_* functions. + * The ownership of packet id is moved to the library. + * Or you can call release_packet_id to release it. + * @return If packet_id is successfully registerd then return true, otherwise return false. + */ + bool register_id(packet_id_t packet_id) { + return va_.use(packet_id); + } + + /** + * @brief Release packet_id. + * @param packet_id packet id to release. + * only the packet_id gotten by acquire_unique_packet_id, or + * register_packet_id is permitted. + */ + void release_id(packet_id_t packet_id) { + va_.deallocate(packet_id); + } + + /** + * @brief Clear all packet ids. + */ + void clear() { + va_.clear(); + } + +private: + value_allocator va_ {1, std::numeric_limits::max()}; +}; + +} // namespace MQTT_NS + +#endif // MQTT_PACKET_ID_MANAGER_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/packet_id_type.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/packet_id_type.hpp new file mode 100644 index 000000000..7c595ccf3 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/packet_id_type.hpp @@ -0,0 +1,25 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PACKET_ID_TYPE_HPP) +#define MQTT_PACKET_ID_TYPE_HPP + +#include + +namespace MQTT_NS { + +template +using packet_id_type = two_or_four_byte_type; + +template +using make_packet_id = make_two_or_four_byte; + +template +using add_packet_id_to_buf = add_two_or_four_byte_to_buf; + +} // namespace MQTT_NS + +#endif // MQTT_PACKET_ID_TYPE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/property.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/property.hpp new file mode 100644 index 000000000..cb3582e87 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/property.hpp @@ -0,0 +1,828 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PROPERTY_HPP) +#define MQTT_PROPERTY_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +namespace v5 { + +namespace property { + +namespace detail { + +enum class ostream_format { + direct, + int_cast, + key_val, + binary_string, + json_like +}; + +template +struct n_bytes_property : private boost::totally_ordered> { + explicit n_bytes_property(property::id id) + :id_(id) {} + + template + n_bytes_property(property::id id, It b, It e) + :id_(id), buf_(force_move(b), force_move(e)) {} + + n_bytes_property(property::id id, boost::container::static_vector buf) + :id_(id), buf_(force_move(buf)) {} + + /** + * @brief Add const buffer sequence into the given buffer. + * @param v buffer to add + */ + void add_const_buffer_sequence(std::vector& v) const { + v.emplace_back(as::buffer(&id_, 1)); + v.emplace_back(as::buffer(buf_.data(), buf_.size())); + } + + /** + * @brief Copy the internal information to the range between b and e + * it is for boost asio APIs + * @param b begin of the range to fill + * @param e end of the range to fill + */ + template + void fill(It b, It e) const { + (void)e; // Avoid warning in release builds about unused variable + BOOST_ASSERT(static_cast(std::distance(b, e)) >= size()); + *b++ = static_cast::value_type>(id_); + std::copy(buf_.begin(), buf_.end(), b); + } + + /** + * @brief Get property::id + * @return id + */ + property::id id() const { + return id_; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return 1 + buf_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 2; + } + + friend bool operator<(n_bytes_property const& lhs, n_bytes_property const& rhs) { + return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_); + } + + friend bool operator==(n_bytes_property const& lhs, n_bytes_property const& rhs) { + return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_); + } + + static constexpr ostream_format const of_ = ostream_format::direct; + property::id id_; + boost::container::static_vector buf_; +}; + +struct binary_property : private boost::totally_ordered { + binary_property(property::id id, buffer buf) + :id_(id), + buf_(force_move(buf)), + length_{ num_to_2bytes(boost::numeric_cast(buf_.size())) } { + if (buf_.size() > 0xffff) throw property_length_error(); + } + + /** + * @brief Add const buffer sequence into the given buffer. + * @param v buffer to add + */ + void add_const_buffer_sequence(std::vector& v) const { + v.emplace_back(as::buffer(&id_, 1)); + v.emplace_back(as::buffer(length_.data(), length_.size())); + v.emplace_back(as::buffer(buf_.data(), buf_.size())); + } + + /** + * @brief Copy the internal information to the range between b and e + * it is for boost asio APIs + * @param b begin of the range to fill + * @param e end of the range to fill + */ + template + void fill(It b, It e) const { + (void)e; // Avoid warning in release builds about unused variable + using dt = typename It::difference_type; + + BOOST_ASSERT(static_cast(std::distance(b, e)) >= size()); + *b++ = static_cast::value_type>(id_); + std::copy(length_.begin(), length_.end(), b); + std::advance(b, static_cast
(length_.size())); + std::copy(buf_.begin(), buf_.end(), b); + } + + /** + * @brief Get property::id + * @return id + */ + property::id id() const { + return id_; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return 1 + length_.size() + buf_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 2; + } + + constexpr buffer const& val() const { + return buf_; + } + + friend bool operator<(binary_property const& lhs, binary_property const& rhs) { + return std::tie(lhs.id_, lhs.buf_) < std::tie(rhs.id_, rhs.buf_); + } + + friend bool operator==(binary_property const& lhs, binary_property const& rhs) { + return std::tie(lhs.id_, lhs.buf_) == std::tie(rhs.id_, rhs.buf_); + } + + static constexpr ostream_format const of_ = ostream_format::json_like; + property::id id_; + buffer buf_; + boost::container::static_vector length_; +}; + +struct string_property : binary_property { + string_property(property::id id, buffer buf, bool already_checked) + :binary_property(id, force_move(buf)) { + if (!already_checked) { + auto r = utf8string::validate_contents(this->val()); + if (r != utf8string::validation::well_formed) throw utf8string_contents_error(r); + } + } +}; + +struct variable_property : private boost::totally_ordered { + variable_property(property::id id, std::size_t value) + :id_(id) { + variable_push(value_, value); + } + + /** + * @brief Add const buffer sequence into the given buffer. + * @param v buffer to add + */ + void add_const_buffer_sequence(std::vector& v) const { + v.emplace_back(as::buffer(&id_, 1)); + v.emplace_back(as::buffer(value_.data(), value_.size())); + } + + /** + * @brief Copy the internal information to the range between b and e + * it is for boost asio APIs + * @param b begin of the range to fill + * @param e end of the range to fill + */ + template + void fill(It b, It e) const { + (void)e; // Avoid warning in release builds about unused variable + BOOST_ASSERT(static_cast(std::distance(b, e)) >= size()); + *b++ = static_cast::value_type>(id_); + std::copy(value_.begin(), value_.end(), b); + } + + /** + * @brief Get property::id + * @return id + */ + property::id id() const { + return id_; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return 1 + value_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 2; + } + + constexpr std::size_t val() const { + return std::get<0>(variable_length(value_)); + } + + friend bool operator<(variable_property const& lhs, variable_property const& rhs) { + auto const& lval = lhs.val(); + auto const& rval = rhs.val(); + return std::tie(lhs.id_, lval) < std::tie(rhs.id_, rval); + } + + friend bool operator==(variable_property const& lhs, variable_property const& rhs) { + auto const& lval = lhs.val(); + auto const& rval = rhs.val(); + return std::tie(lhs.id_, lval) == std::tie(rhs.id_, rval); + } + + static constexpr ostream_format const of_ = ostream_format::direct; + property::id id_; + boost::container::static_vector value_; +}; + +} // namespace detail + +class payload_format_indicator : public detail::n_bytes_property<1> { +public: + using recv = payload_format_indicator; + using store = payload_format_indicator; + enum payload_format { + binary, + string + }; + + payload_format_indicator(payload_format fmt = binary) + : detail::n_bytes_property<1>(id::payload_format_indicator, { fmt == binary ? char(0) : char(1) } ) {} + + template + payload_format_indicator(It b, It e) + : detail::n_bytes_property<1>(id::payload_format_indicator, b, e) {} + + payload_format val() const { + return ( (buf_.front() == 0) + ? binary + : string); + } + + static constexpr detail::ostream_format const of_ = detail::ostream_format::binary_string; +}; + + +class message_expiry_interval : public detail::n_bytes_property<4> { +public: + using recv = message_expiry_interval; + using store = message_expiry_interval; + message_expiry_interval(std::uint32_t val) + : detail::n_bytes_property<4>(id::message_expiry_interval, num_to_4bytes(val) ) {} + + template + message_expiry_interval(It b, It e) + : detail::n_bytes_property<4>(id::message_expiry_interval, b, e) {} + + std::uint32_t val() const { + return make_uint32_t(buf_.begin(), buf_.end()); + } +}; + +class content_type : public detail::string_property { +public: + explicit content_type(buffer val, bool already_checked = false) + : detail::string_property(id::content_type, force_move(val), already_checked) {} +}; + +class response_topic : public detail::string_property { +public: + explicit response_topic(buffer val, bool already_checked = false) + : detail::string_property(id::response_topic, force_move(val), already_checked) {} +}; + +class correlation_data : public detail::binary_property { +public: + explicit correlation_data(buffer val) + : detail::binary_property(id::correlation_data, force_move(val)) {} +}; + +class subscription_identifier : public detail::variable_property { +public: + using recv = subscription_identifier; + using store = subscription_identifier; + subscription_identifier(std::size_t subscription_id) + : detail::variable_property(id::subscription_identifier, subscription_id) {} +}; + +class session_expiry_interval : public detail::n_bytes_property<4> { +public: + using recv = session_expiry_interval; + using store = session_expiry_interval; + session_expiry_interval(session_expiry_interval_t val) + : detail::n_bytes_property<4>(id::session_expiry_interval, { num_to_4bytes(val) } ) { + static_assert(sizeof(session_expiry_interval_t) == 4, "sizeof(sesion_expiry_interval) should be 4"); + } + + template + session_expiry_interval(It b, It e) + : detail::n_bytes_property<4>(id::session_expiry_interval, b, e) {} + + session_expiry_interval_t val() const { + return make_uint32_t(buf_.begin(), buf_.end()); + } +}; + +class assigned_client_identifier : public detail::string_property { +public: + explicit assigned_client_identifier(buffer val, bool already_checked = false) + : detail::string_property(id::assigned_client_identifier, force_move(val), already_checked) {} +}; + +class server_keep_alive : public detail::n_bytes_property<2> { +public: + using recv = server_keep_alive; + using store = server_keep_alive; + server_keep_alive(std::uint16_t val) + : detail::n_bytes_property<2>(id::server_keep_alive, { num_to_2bytes(val) } ) {} + + template + server_keep_alive(It b, It e) + : detail::n_bytes_property<2>(id::server_keep_alive, b, e) {} + + std::uint16_t val() const { + return make_uint16_t(buf_.begin(), buf_.end()); + } +}; + +class authentication_method : public detail::string_property { +public: + explicit authentication_method(buffer val, bool already_checked = false) + : detail::string_property(id::authentication_method, force_move(val), already_checked) {} +}; + +class authentication_data : public detail::binary_property { +public: + explicit authentication_data(buffer val) + : detail::binary_property(id::authentication_data, force_move(val)) {} +}; + +class request_problem_information : public detail::n_bytes_property<1> { +public: + using recv = request_problem_information; + using store = request_problem_information; + request_problem_information(bool value) + : detail::n_bytes_property<1>(id::request_problem_information, { value ? char(1) : char(0) } ) {} + + template + request_problem_information(It b, It e) + : detail::n_bytes_property<1>(id::request_problem_information, b, e) {} + + bool val() const { + return buf_.front() == 1; + } +}; + +class will_delay_interval : public detail::n_bytes_property<4> { +public: + using recv = will_delay_interval; + using store = will_delay_interval; + will_delay_interval(std::uint32_t val) + : detail::n_bytes_property<4>(id::will_delay_interval, { num_to_4bytes(val) } ) {} + + template + will_delay_interval(It b, It e) + : detail::n_bytes_property<4>(id::will_delay_interval, b, e) {} + + std::uint32_t val() const { + return make_uint32_t(buf_.begin(), buf_.end()); + } +}; + +class request_response_information : public detail::n_bytes_property<1> { +public: + using recv = request_response_information; + using store = request_response_information; + request_response_information(bool value) + : detail::n_bytes_property<1>(id::request_response_information, { value ? char(1) : char(0) } ) {} + + template + request_response_information(It b, It e) + : detail::n_bytes_property<1>(id::request_response_information, b, e) {} + + bool val() const { + return buf_.front() == 1; + } +}; + +class response_information : public detail::string_property { +public: + explicit response_information(buffer val, bool already_checked = false) + : detail::string_property(id::response_information, force_move(val), already_checked) {} +}; + +class server_reference : public detail::string_property { +public: + explicit server_reference(buffer val, bool already_checked = false) + : detail::string_property(id::server_reference, force_move(val), already_checked) {} +}; + +class reason_string : public detail::string_property { +public: + explicit reason_string(buffer val, bool already_checked = false) + : detail::string_property(id::reason_string, force_move(val), already_checked) {} +}; + +class receive_maximum : public detail::n_bytes_property<2> { +public: + using recv = receive_maximum; + using store = receive_maximum; + receive_maximum(receive_maximum_t val) + : detail::n_bytes_property<2>(id::receive_maximum, { num_to_2bytes(val) } ) {} + + template + receive_maximum(It b, It e) + : detail::n_bytes_property<2>(id::receive_maximum, b, e) {} + + receive_maximum_t val() const { + return make_uint16_t(buf_.begin(), buf_.end()); + } +}; + + +class topic_alias_maximum : public detail::n_bytes_property<2> { +public: + using recv = topic_alias_maximum; + using store = topic_alias_maximum; + topic_alias_maximum(topic_alias_t val) + : detail::n_bytes_property<2>(id::topic_alias_maximum, { num_to_2bytes(val) } ) {} + + template + topic_alias_maximum(It b, It e) + : detail::n_bytes_property<2>(id::topic_alias_maximum, b, e) {} + + topic_alias_t val() const { + return make_uint16_t(buf_.begin(), buf_.end()); + } +}; + + +class topic_alias : public detail::n_bytes_property<2> { +public: + using recv = topic_alias; + using store = topic_alias; + topic_alias(topic_alias_t val) + : detail::n_bytes_property<2>(id::topic_alias, { num_to_2bytes(val) } ) {} + + template + topic_alias(It b, It e) + : detail::n_bytes_property<2>(id::topic_alias, b, e) {} + + topic_alias_t val() const { + return make_uint16_t(buf_.begin(), buf_.end()); + } +}; + +class maximum_qos : public detail::n_bytes_property<1> { +public: + using recv = maximum_qos; + using store = maximum_qos; + maximum_qos(qos value) + : detail::n_bytes_property<1>(id::maximum_qos, { static_cast(value) } ) { + if (value != qos::at_most_once && + value != qos::at_least_once && + value != qos::exactly_once) throw property_parse_error(); + } + + template + maximum_qos(It b, It e) + : detail::n_bytes_property<1>(id::maximum_qos, b, e) {} + + std::uint8_t val() const { + return static_cast(buf_.front()); + } + + static constexpr const detail::ostream_format of_ = detail::ostream_format::int_cast; +}; + +class retain_available : public detail::n_bytes_property<1> { +public: + using recv = retain_available; + using store = retain_available; + retain_available(bool value) + : detail::n_bytes_property<1>(id::retain_available, { value ? char(1) : char(0) } ) {} + + template + retain_available(It b, It e) + : detail::n_bytes_property<1>(id::retain_available, b, e) {} + + bool val() const { + return buf_.front() == 1; + } +}; + + +class user_property : private boost::totally_ordered { +public: + user_property(buffer key, buffer val, bool key_already_checked = false, bool val_already_checked = false) + : key_(force_move(key), key_already_checked), val_(force_move(val), val_already_checked) {} + + /** + * @brief Add const buffer sequence into the given buffer. + * @param v buffer to add + */ + void add_const_buffer_sequence(std::vector& v) const { + v.emplace_back(as::buffer(&id_, 1)); + v.emplace_back(as::buffer(key_.len.data(), key_.len.size())); + v.emplace_back(as::buffer(key_.buf)); + v.emplace_back(as::buffer(val_.len.data(), val_.len.size())); + v.emplace_back(as::buffer(val_.buf)); + } + + template + void fill(It b, It e) const { + (void)e; // Avoid warning in release builds about unused variable + using dt = typename It::difference_type; + BOOST_ASSERT(static_cast(std::distance(b, e)) >= size()); + + *b++ = static_cast::value_type>(id_); + { + std::copy(key_.len.begin(), key_.len.end(), b); + std::advance(b, static_cast
(key_.len.size())); + auto ptr = key_.buf.data(); + auto size = key_.buf.size(); + std::copy(ptr, std::next(ptr, static_cast
(size)), b); + std::advance(b, static_cast
(size)); + } + { + std::copy(val_.len.begin(), val_.len.end(), b); + std::advance(b, static_cast
(val_.len.size())); + auto ptr = val_.buf.data(); + auto size = val_.buf.size(); + std::copy(ptr, std::next(ptr, static_cast
(size)), b); + std::advance(b, static_cast
(size)); + } + } + + /** + * @brief Get property::id + * @return id + */ + property::id id() const { + return id_; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // id_ + key_.size() + + val_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return + 1 + // header + 2 + // key (len, buf) + 2; // val (len, buf) + } + + constexpr buffer const& key() const { + return key_.buf; + } + + constexpr buffer const& val() const { + return val_.buf; + } + + friend bool operator<(user_property const& lhs, user_property const& rhs) { + return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) < std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf); + } + + friend bool operator==(user_property const& lhs, user_property const& rhs) { + return std::tie(lhs.id_, lhs.key_.buf, lhs.val_.buf) == std::tie(rhs.id_, rhs.key_.buf, rhs.val_.buf); + } + + static constexpr detail::ostream_format const of_ = detail::ostream_format::key_val; + +private: + struct len_str { + explicit len_str(buffer b, bool already_checked = false) + : buf(force_move(b)), + len{ num_to_2bytes(boost::numeric_cast(buf.size())) } + { + if (!already_checked) { + auto r = utf8string::validate_contents(buf); + if (r != utf8string::validation::well_formed) throw utf8string_contents_error(r); + } + } + + std::size_t size() const { + return len.size() + buf.size(); + } + buffer buf; + boost::container::static_vector len; + }; + +private: + property::id id_ = id::user_property; + len_str key_; + len_str val_; +}; + +class maximum_packet_size : public detail::n_bytes_property<4> { +public: + using recv = maximum_packet_size; + using store = maximum_packet_size; + maximum_packet_size(std::uint32_t val) + : detail::n_bytes_property<4>(id::maximum_packet_size, { num_to_4bytes(val) } ) {} + + template + maximum_packet_size(It b, It e) + : detail::n_bytes_property<4>(id::maximum_packet_size, b, e) {} + + std::uint32_t val() const { + return make_uint32_t(buf_.begin(), buf_.end()); + } +}; + + +class wildcard_subscription_available : public detail::n_bytes_property<1> { +public: + using recv = wildcard_subscription_available; + using store = wildcard_subscription_available; + wildcard_subscription_available(bool value) + : detail::n_bytes_property<1>(id::wildcard_subscription_available, { value ? char(1) : char(0) } ) {} + + template + wildcard_subscription_available(It b, It e) + : detail::n_bytes_property<1>(id::wildcard_subscription_available, b, e) {} + + bool val() const { + return buf_.front() == 1; + } +}; + + +class subscription_identifier_available : public detail::n_bytes_property<1> { +public: + using recv = subscription_identifier_available; + using store = subscription_identifier_available; + subscription_identifier_available(bool value) + : detail::n_bytes_property<1>(id::subscription_identifier_available, { value ? char(1) : char(0) } ) {} + + template + subscription_identifier_available(It b, It e) + : detail::n_bytes_property<1>(id::subscription_identifier_available, b, e) {} + + bool val() const { + return buf_.front() == 1; + } +}; + + +class shared_subscription_available : public detail::n_bytes_property<1> { +public: + using recv = shared_subscription_available; + using store = shared_subscription_available; + shared_subscription_available(bool value) + : detail::n_bytes_property<1>(id::shared_subscription_available, { value ? char(1) : char(0) } ) {} + + template + shared_subscription_available(It b, It e) + : detail::n_bytes_property<1>(id::shared_subscription_available, b, e) {} + + bool val() const { + return buf_.front() == 1; + } +}; + +template +std::enable_if_t< Property::of_ == detail::ostream_format::direct, std::ostream& > +operator<<(std::ostream& o, Property const& p) { + o << p.val(); + return o; +} + +template +std::enable_if_t< Property::of_ == detail::ostream_format::int_cast, std::ostream& > +operator<<(std::ostream& o, Property const& p) { + o << static_cast(p.val()); + return o; +} + +template +std::enable_if_t< Property::of_ == detail::ostream_format::key_val, std::ostream& > +operator<<(std::ostream& o, Property const& p) { + o << p.key() << ':' << p.val(); + return o; +} + +template +std::enable_if_t< Property::of_ == detail::ostream_format::binary_string, std::ostream& > +operator<<(std::ostream& o, Property const& p) { + // Note this only compiles because both strings below are the same length. + o << ((p.val() == payload_format_indicator::binary) ? "binary" : "string"); + return o; +} + +template +std::enable_if_t< Property::of_ == detail::ostream_format::json_like, std::ostream& > +operator<<(std::ostream& o, Property const& p) { + auto const& v = p.val(); + for (auto const c : v) { + switch (c) { + case '\\': + o << "\\\\"; + break; + case '"': + o << "\\\""; + break; + case '/': + o << "\\/"; + break; + case '\b': + o << "\\b"; + break; + case '\f': + o << "\\f"; + break; + case '\n': + o << "\\n"; + break; + case '\r': + o << "\\r"; + break; + case '\t': + o << "\\t"; + break; + default: { + unsigned int code = static_cast(c); + if (code < 0x20 || code >= 0x7f) { + std::ios::fmtflags flags(o.flags()); + o << "\\u" << std::hex << std::setw(4) << std::setfill('0') << (code & 0xff); + o.flags(flags); + } + else { + o << c; + } + } break; + } + } + return o; +} + + +} // namespace property +} // namespace v5 +} // namespace MQTT_NS + +#endif // MQTT_PROPERTY_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/property_id.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/property_id.hpp new file mode 100644 index 000000000..0d92974d9 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/property_id.hpp @@ -0,0 +1,55 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PROPERTY_ID_HPP) +#define MQTT_PROPERTY_ID_HPP + +#include +#include + +namespace MQTT_NS { + +namespace v5 { + +namespace property { + +enum class id { + payload_format_indicator = 1, + message_expiry_interval = 2, + content_type = 3, + response_topic = 8, + correlation_data = 9, + subscription_identifier = 11, + session_expiry_interval = 17, + assigned_client_identifier = 18, + server_keep_alive = 19, + authentication_method = 21, + authentication_data = 22, + request_problem_information = 23, + will_delay_interval = 24, + request_response_information = 25, + response_information = 26, + server_reference = 28, + reason_string = 31, + receive_maximum = 33, + topic_alias_maximum = 34, + topic_alias = 35, + maximum_qos = 36, + retain_available = 37, + user_property = 38, + maximum_packet_size = 39, + wildcard_subscription_available = 40, + subscription_identifier_available = 41, + shared_subscription_available = 42, +}; + +} // namespace property + +} // namespace v5 + +} // namespace MQTT_NS + +#endif // MQTT_PROPERTY_ID_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/property_parse.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/property_parse.hpp new file mode 100644 index 000000000..e0cc25bea --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/property_parse.hpp @@ -0,0 +1,249 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PROPERTY_PARSE_HPP) +#define MQTT_PROPERTY_PARSE_HPP + +#include + +#include +#include +#include +#include +#include + +namespace MQTT_NS { +namespace v5 { +namespace property { + +inline +optional parse_one(buffer& buf) { + if (buf.empty()) return nullopt; + try { + auto id = static_cast(buf.front()); + buf.remove_prefix(1); + switch (id) { + case id::payload_format_indicator: { + if (buf.size() < 1) return nullopt; + auto p = payload_format_indicator(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + case id::message_expiry_interval: { + if (buf.size() < 4) return nullopt; + auto p = message_expiry_interval(buf.begin(), std::next(buf.begin(), 4)); + buf.remove_prefix(4); + return property_variant(p); + } break; + case id::content_type: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = content_type(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::response_topic: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = response_topic(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::correlation_data: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = correlation_data(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::subscription_identifier: { + auto val_consumed = variable_length(buf.begin(), buf.end()); + auto val = std::get<0>(val_consumed); + auto consumed = std::get<1>(val_consumed); + if (consumed == 0) return nullopt; + auto p = subscription_identifier(val); + buf.remove_prefix(consumed); + return property_variant(p); + } break; + case id::session_expiry_interval: { + if (buf.size() < 4) return nullopt; + auto p = session_expiry_interval(buf.begin(), std::next(buf.begin(), 4)); + buf.remove_prefix(4); + return property_variant(p); + } break; + case id::assigned_client_identifier: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = assigned_client_identifier(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::server_keep_alive: { + if (buf.size() < 2) return nullopt; + auto p = server_keep_alive(buf.begin(), std::next(buf.begin(), 2)); + buf.remove_prefix(2); + return property_variant(p); + } break; + case id::authentication_method: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = authentication_method(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::authentication_data: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = authentication_data(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::request_problem_information: { + if (buf.size() < 1) return nullopt; + auto p = request_problem_information(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + case id::will_delay_interval: { + if (buf.size() < 4) return nullopt; + auto p = will_delay_interval(buf.begin(), std::next(buf.begin(), 4)); + buf.remove_prefix(4); + return property_variant(p); + } break; + case id::request_response_information: { + if (buf.size() < 1) return nullopt; + auto p = request_response_information(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + case id::response_information: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = response_information(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::server_reference: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = server_reference(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::reason_string: { + if (buf.size() < 2) return nullopt; + auto len = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + len) return nullopt; + auto p = reason_string(buf.substr(2, len)); + buf.remove_prefix(2 + len); + return property_variant(p); + } break; + case id::receive_maximum: { + if (buf.size() < 2) return nullopt; + auto p = receive_maximum(buf.begin(), std::next(buf.begin(), 2)); + buf.remove_prefix(2); + return property_variant(p); + } break; + case id::topic_alias_maximum: { + if (buf.size() < 2) return nullopt; + auto p = topic_alias_maximum(buf.begin(), std::next(buf.begin(), 2)); + buf.remove_prefix(2); + return property_variant(p); + } break; + case id::topic_alias: { + if (buf.size() < 2) return nullopt; + auto p = topic_alias(buf.begin(), std::next(buf.begin(), 2)); + buf.remove_prefix(2); + return property_variant(p); + } break; + case id::maximum_qos: { + if (buf.size() < 1) return nullopt; + auto p = maximum_qos(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + case id::retain_available: { + if (buf.size() < 1) return nullopt; + auto p = retain_available(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + case id::user_property: { + if (buf.size() < 2) return nullopt; + auto keylen = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + keylen) return nullopt; + auto key = buf.substr(2, keylen); + buf.remove_prefix(2 + keylen); + + if (buf.size() < 2) return nullopt; + auto vallen = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + if (buf.size() < 2U + vallen) return nullopt; + auto val = buf.substr(2, vallen); + + auto p = user_property(force_move(key), force_move(val)); + buf.remove_prefix(2 + vallen); + + return property_variant(p); + } break; + case id::maximum_packet_size: { + if (buf.size() < 4) return nullopt; + auto p = maximum_packet_size(buf.begin(), std::next(buf.begin(), 4)); + buf.remove_prefix(4); + return property_variant(p); + } break; + case id::wildcard_subscription_available: { + if (buf.size() < 1) return nullopt; + auto p = wildcard_subscription_available(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + case id::subscription_identifier_available: { + if (buf.size() < 1) return nullopt; + auto p = subscription_identifier_available(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + case id::shared_subscription_available: { + if (buf.size() < 1) return nullopt; + auto p = shared_subscription_available(buf.begin(), std::next(buf.begin(), 1)); + buf.remove_prefix(1); + return property_variant(p); + } break; + } + } + catch (property_parse_error const&) { + return nullopt; + } + return nullopt; +} + +inline +std::vector parse(buffer buf) { + std::vector props; + while (true) { + if (auto ret = parse_one(buf)) { + props.push_back(force_move(ret.value())); + } + else { + break; + } + } + return props; +} + +} // namespace property +} // namespace v5 +} // namespace MQTT_NS + +#endif // MQTT_PROPERTY_PARSE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/property_variant.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/property_variant.hpp new file mode 100644 index 000000000..ecebbf4da --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/property_variant.hpp @@ -0,0 +1,229 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PROPERTY_VARIANT_HPP) +#define MQTT_PROPERTY_VARIANT_HPP + +#include + +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace v5 { +// property_variant + +using property_variant = variant< + property::payload_format_indicator, + property::message_expiry_interval, + property::content_type, + property::response_topic, + property::correlation_data, + property::subscription_identifier, + property::session_expiry_interval, + property::assigned_client_identifier, + property::server_keep_alive, + property::authentication_method, + property::authentication_data, + property::request_problem_information, + property::will_delay_interval, + property::request_response_information, + property::response_information, + property::server_reference, + property::reason_string, + property::receive_maximum, + property::topic_alias_maximum, + property::topic_alias, + property::maximum_qos, + property::retain_available, + property::user_property, + property::maximum_packet_size, + property::wildcard_subscription_available, + property::subscription_identifier_available, + property::shared_subscription_available +>; + +using properties = std::vector; + +namespace property { + +namespace detail { + +struct add_const_buffer_sequence_visitor { + add_const_buffer_sequence_visitor(std::vector& v):v(v) {} + template + void operator()(T&& t) const { + t.add_const_buffer_sequence(v); + } + std::vector& v; +}; + +struct id_visitor { + template + id operator()(T const& t) const { + return t.id(); + } +}; + +struct size_visitor { + template + std::size_t operator()(T&& t) const { + return t.size(); + } +}; + +struct num_of_const_buffer_sequence_visitor { + template + std::size_t operator()(T&& t) const { + return t.num_of_const_buffer_sequence(); + } +}; + +template +struct fill_visitor { + fill_visitor(Iterator b, Iterator e):b(b), e(e) {} + + template + void operator()(T&& t) const { + t.fill(b, e); + } + + Iterator b; + Iterator e; +}; + +template +inline fill_visitor make_fill_visitor(Iterator b, Iterator e) { + return fill_visitor(b, e); +} + +} // namespace detail + +} // namespace property + +inline void add_const_buffer_sequence(std::vector& v, property_variant const& pv) { + MQTT_NS::visit(property::detail::add_const_buffer_sequence_visitor(v), pv); +} + +inline property::id id(property_variant const& pv) { + return MQTT_NS::visit(property::detail::id_visitor(), pv); +} + +inline std::size_t size(property_variant const& pv) { + return MQTT_NS::visit(property::detail::size_visitor(), pv); +} + +inline std::size_t num_of_const_buffer_sequence(property_variant const& pv) { + return MQTT_NS::visit(property::detail::num_of_const_buffer_sequence_visitor(), pv); +} + + +template +inline void fill(property_variant const& pv, Iterator b, Iterator e) { + auto vis = property::detail::make_fill_visitor(b, e); + MQTT_NS::visit(vis, pv); +} + +struct less_than_visitor { + template + bool operator()(T const& lhs, T const& rhs) const { + return lhs < rhs; + } + template + bool operator()(T const& lhs, U const& rhs) const { + return lhs.id() < rhs.id(); + } +}; + +inline +bool operator<(property_variant const& lhs, property_variant const& rhs) { + return MQTT_NS::visit( + less_than_visitor(), + lhs, + rhs + ); +} + +struct equal_visitor { + template + bool operator()(T const& lhs, T const& rhs) const { + return lhs == rhs; + } + template + bool operator()(T const&, U const&) const { + return false; + } +}; + +inline +bool operator==(property_variant const& lhs, property_variant const& rhs) { + return MQTT_NS::visit( + equal_visitor(), + lhs, + rhs + ); +} + +inline +bool operator!=(property_variant const& lhs, property_variant const& rhs) { + return !MQTT_NS::visit( + equal_visitor(), + lhs, + rhs + ); +} + +template +inline +void +visit_prop(property_variant const& prop, Visitors&&... visitors) { + MQTT_NS::visit( + make_lambda_visitor(std::forward(visitors)...), prop + ); +} + +template +inline +void +visit_props(properties const& props, Visitors&&... visitors) { + for (auto const& prop : props) { + visit_prop( + prop, + std::forward(visitors)... + ); + } +} + +template +inline +void +visit_prop(property_variant&& prop, Visitors&&... visitors) { + MQTT_NS::visit( + make_lambda_visitor(std::forward(visitors)...), force_move(prop) + ); +} + +template +inline +void +visit_props(properties&& props, Visitors&&... visitors) { + for (auto&& prop : force_move(props)) { + visit_prop( + force_move(prop), + std::forward(visitors)... + ); + } +} + + +} // namespace v5 + +} // namespace MQTT_NS + +#endif // MQTT_PROPERTY_VARIANT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/protocol_version.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/protocol_version.hpp new file mode 100644 index 000000000..23e573f95 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/protocol_version.hpp @@ -0,0 +1,41 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PROTOCOL_VERSION_HPP) +#define MQTT_PROTOCOL_VERSION_HPP + +#include +#include + +#include + +namespace MQTT_NS { + +enum class protocol_version { + undetermined = 0, + v3_1_1 = 4, + v5 = 5, +}; + +constexpr char const* protocol_version_to_str(protocol_version v) { + switch(v) { + case protocol_version::undetermined: return "undetermined"; + case protocol_version::v3_1_1: return "v3_1_1"; + case protocol_version::v5: return "v5"; + default: return "unknown_protocol_version"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, protocol_version val) +{ + os << protocol_version_to_str(val); + return os; +} + +} // namespace MQTT_NS + +#endif // MQTT_PROTOCOL_VERSION_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/publish.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/publish.hpp new file mode 100644 index 000000000..efec0bbfd --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/publish.hpp @@ -0,0 +1,137 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_PUBLISH_HPP) +#define MQTT_PUBLISH_HPP + +#include +#include + +#include + +#include +#include + +namespace MQTT_NS { + +namespace publish { + +constexpr bool is_dup(std::uint8_t v) { + return (v & 0b00001000) != 0; +} + +constexpr qos get_qos(std::uint8_t v) { + return static_cast((v & 0b00000110) >> 1); +} + +constexpr bool is_retain(std::uint8_t v) { + return (v & 0b00000001) != 0; +} + +constexpr void set_dup(std::uint8_t& fixed_header, bool dup) { + if (dup) fixed_header |= 0b00001000; + else fixed_header &= static_cast(~0b00001000); +} + +} // namespace publish + +enum class retain : std::uint8_t +{ + yes = 0b00000001, + no = 0b00000000, +}; + +enum class dup : std::uint8_t +{ + yes = 0b00001000, + no = 0b00000000, +}; + +struct publish_options final { + constexpr publish_options() = default; + ~publish_options() = default; + constexpr publish_options(publish_options &&) = default; + constexpr publish_options(publish_options const&) = default; + constexpr publish_options& operator=(publish_options &&) = default; + constexpr publish_options& operator=(publish_options const&) = default; + + explicit constexpr publish_options(std::uint8_t value) : data_(value) { } + + constexpr publish_options(retain value) : data_(static_cast(value)) { } + constexpr publish_options(dup value) : data_(static_cast(value)) { } + constexpr publish_options(qos value) : data_(static_cast(static_cast(value) << 1)) + { + BOOST_ASSERT(value == qos::at_most_once || value == qos::at_least_once || value == qos::exactly_once); + } + + constexpr publish_options operator|(publish_options rhs) const { return publish_options(data_ | rhs.data_); } + constexpr publish_options operator|(retain rhs) const { return *this | publish_options(rhs); } + constexpr publish_options operator|(dup rhs) const { return *this | publish_options(rhs); } + constexpr publish_options operator|(qos rhs) const { return *this | publish_options(rhs); } + + constexpr publish_options& operator|=(publish_options rhs) { return (*this = (*this | rhs)); } + constexpr publish_options& operator|=(retain rhs) { return (*this = (*this | rhs)); } + constexpr publish_options& operator|=(dup rhs) { return (*this = (*this | rhs)); } + constexpr publish_options& operator|=(qos rhs) { return (*this = (*this | rhs)); } + + constexpr retain get_retain() const + { return static_cast(data_ & 0b00000001); } + constexpr dup get_dup() const + { return static_cast(data_ & 0b00001000); } + constexpr qos get_qos() const + { return static_cast((data_ & 0b00000110) >> 1); } + + explicit constexpr operator std::uint8_t() const { return data_; } + +private: + std::uint8_t data_ = 0; // defaults to retain::no, dup::no, qos::at_most_once +}; + +constexpr publish_options operator|(retain lhs, dup rhs) { return publish_options(lhs) | rhs; } +constexpr publish_options operator|(retain lhs, qos rhs) { return publish_options(lhs) | rhs; } + +constexpr publish_options operator|(dup lhs, retain rhs) { return publish_options(lhs) | rhs; } +constexpr publish_options operator|(dup lhs, qos rhs) { return publish_options(lhs) | rhs; } + +constexpr publish_options operator|(qos lhs, retain rhs) { return publish_options(lhs) | rhs; } +constexpr publish_options operator|(qos lhs, dup rhs) { return publish_options(lhs) | rhs; } + + +constexpr char const* retain_to_str(retain v) { + switch(v) { + case retain::yes: return "yes"; + case retain::no: return "no"; + default: return "invalid_retain"; + } +} + + +inline +std::ostream& operator<<(std::ostream& os, retain val) +{ + os << retain_to_str(val); + return os; +} + +constexpr char const* dup_to_str(dup v) { + switch(v) { + case dup::yes: return "yes"; + case dup::no: return "no"; + default: return "invalid_dup"; + } +} + + +inline +std::ostream& operator<<(std::ostream& os, dup val) +{ + os << dup_to_str(val); + return os; +} + +} // namespace MQTT_NS + +#endif // MQTT_PUBLISH_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/reason_code.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/reason_code.hpp new file mode 100644 index 000000000..3bf8b6071 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/reason_code.hpp @@ -0,0 +1,422 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_REASON_CODE_HPP) +#define MQTT_REASON_CODE_HPP + +#include +#include + +#include +#include + +namespace MQTT_NS { + +enum class suback_return_code : std::uint8_t { + success_maximum_qos_0 = 0x00, + success_maximum_qos_1 = 0x01, + success_maximum_qos_2 = 0x02, + failure = 0x80, +}; + +constexpr +char const* suback_return_code_to_str(suback_return_code v) { + switch(v) + { + case suback_return_code::success_maximum_qos_0: return "success_maximum_qos_0"; + case suback_return_code::success_maximum_qos_1: return "success_maximum_qos_1"; + case suback_return_code::success_maximum_qos_2: return "success_maximum_qos_2"; + case suback_return_code::failure: return "failure"; + default: return "unknown_suback_return_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, suback_return_code val) +{ + os << suback_return_code_to_str(val); + return os; +} + +constexpr suback_return_code qos_to_suback_return_code(qos q) { + return static_cast(q); +} + +namespace v5 { + +enum class connect_reason_code : std::uint8_t { + success = 0x00, + unspecified_error = 0x80, + malformed_packet = 0x81, + protocol_error = 0x82, + implementation_specific_error = 0x83, + unsupported_protocol_version = 0x84, + client_identifier_not_valid = 0x85, + bad_user_name_or_password = 0x86, + not_authorized = 0x87, + server_unavailable = 0x88, + server_busy = 0x89, + banned = 0x8a, + server_shutting_down = 0x8b, + bad_authentication_method = 0x8c, + topic_name_invalid = 0x90, + packet_too_large = 0x95, + quota_exceeded = 0x97, + payload_format_invalid = 0x99, + retain_not_supported = 0x9a, + qos_not_supported = 0x9b, + use_another_server = 0x9c, + server_moved = 0x9d, + connection_rate_exceeded = 0x9f, +}; + +constexpr +char const* connect_reason_code_to_str(connect_reason_code v) { + switch(v) + { + case connect_reason_code::success: return "success"; + case connect_reason_code::unspecified_error: return "unspecified_error"; + case connect_reason_code::malformed_packet: return "malformed_packet"; + case connect_reason_code::protocol_error: return "protocol_error"; + case connect_reason_code::implementation_specific_error: return "implementation_specific_error"; + case connect_reason_code::unsupported_protocol_version: return "unsupported_protocol_version"; + case connect_reason_code::client_identifier_not_valid: return "client_identifier_not_valid"; + case connect_reason_code::bad_user_name_or_password: return "bad_user_name_or_password"; + case connect_reason_code::not_authorized: return "not_authorized"; + case connect_reason_code::server_unavailable: return "server_unavailable"; + case connect_reason_code::server_busy: return "server_busy"; + case connect_reason_code::banned: return "banned"; + case connect_reason_code::server_shutting_down: return "server_shutting_down"; + case connect_reason_code::bad_authentication_method: return "bad_authentication_method"; + case connect_reason_code::topic_name_invalid: return "topic_name_invalid"; + case connect_reason_code::packet_too_large: return "packet_too_large"; + case connect_reason_code::quota_exceeded: return "quota_exceeded"; + case connect_reason_code::payload_format_invalid: return "payload_format_invalid"; + case connect_reason_code::retain_not_supported: return "retain_not_supported"; + case connect_reason_code::qos_not_supported: return "qos_not_supported"; + case connect_reason_code::use_another_server: return "use_another_server"; + case connect_reason_code::server_moved: return "server_moved"; + case connect_reason_code::connection_rate_exceeded: return "connection_rate_exceeded"; + default: return "unknown_connect_reason_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, connect_reason_code val) +{ + os << connect_reason_code_to_str(val); + return os; +} + +enum class disconnect_reason_code : std::uint8_t { + normal_disconnection = 0x00, + disconnect_with_will_message = 0x04, + unspecified_error = 0x80, + malformed_packet = 0x81, + protocol_error = 0x82, + implementation_specific_error = 0x83, + not_authorized = 0x87, + server_busy = 0x89, + server_shutting_down = 0x8b, + keep_alive_timeout = 0x8d, + session_taken_over = 0x8e, + topic_filter_invalid = 0x8f, + topic_name_invalid = 0x90, + receive_maximum_exceeded = 0x93, + topic_alias_invalid = 0x94, + packet_too_large = 0x95, + message_rate_too_high = 0x96, + quota_exceeded = 0x97, + administrative_action = 0x98, + payload_format_invalid = 0x99, + retain_not_supported = 0x9a, + qos_not_supported = 0x9b, + use_another_server = 0x9c, + server_moved = 0x9d, + shared_subscriptions_not_supported = 0x9e, + connection_rate_exceeded = 0x9f, + maximum_connect_time = 0xa0, + subscription_identifiers_not_supported = 0xa1, + wildcard_subscriptions_not_supported = 0xa2, +}; + +constexpr +char const* disconnect_reason_code_to_str(disconnect_reason_code v) { + switch(v) + { + case disconnect_reason_code::normal_disconnection: return "normal_disconnection"; + case disconnect_reason_code::disconnect_with_will_message: return "disconnect_with_will_message"; + case disconnect_reason_code::unspecified_error: return "unspecified_error"; + case disconnect_reason_code::malformed_packet: return "malformed_packet"; + case disconnect_reason_code::protocol_error: return "protocol_error"; + case disconnect_reason_code::implementation_specific_error: return "implementation_specific_error"; + case disconnect_reason_code::not_authorized: return "not_authorized"; + case disconnect_reason_code::server_busy: return "server_busy"; + case disconnect_reason_code::server_shutting_down: return "server_shutting_down"; + case disconnect_reason_code::keep_alive_timeout: return "keep_alive_timeout"; + case disconnect_reason_code::session_taken_over: return "session_taken_over"; + case disconnect_reason_code::topic_filter_invalid: return "topic_filter_invalid"; + case disconnect_reason_code::topic_name_invalid: return "topic_name_invalid"; + case disconnect_reason_code::receive_maximum_exceeded: return "receive_maximum_exceeded"; + case disconnect_reason_code::topic_alias_invalid: return "topic_alias_invalid"; + case disconnect_reason_code::packet_too_large: return "packet_too_large"; + case disconnect_reason_code::message_rate_too_high: return "message_rate_too_high"; + case disconnect_reason_code::quota_exceeded: return "quota_exceeded"; + case disconnect_reason_code::administrative_action: return "administrative_action"; + case disconnect_reason_code::payload_format_invalid: return "payload_format_invalid"; + case disconnect_reason_code::retain_not_supported: return "retain_not_supported"; + case disconnect_reason_code::qos_not_supported: return "qos_not_supported"; + case disconnect_reason_code::use_another_server: return "use_another_server"; + case disconnect_reason_code::server_moved: return "server_moved"; + case disconnect_reason_code::shared_subscriptions_not_supported: return "shared_subscriptions_not_supported"; + case disconnect_reason_code::connection_rate_exceeded: return "connection_rate_exceeded"; + case disconnect_reason_code::maximum_connect_time: return "maximum_connect_time"; + case disconnect_reason_code::subscription_identifiers_not_supported: return "subscription_identifiers_not_supported"; + case disconnect_reason_code::wildcard_subscriptions_not_supported: return "wildcard_subscriptions_not_supported"; + default: return "unknown_disconnect_reason_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, disconnect_reason_code val) +{ + os << disconnect_reason_code_to_str(val); + return os; +} + + +enum class suback_reason_code : std::uint8_t { + granted_qos_0 = 0x00, + granted_qos_1 = 0x01, + granted_qos_2 = 0x02, + unspecified_error = 0x80, + implementation_specific_error = 0x83, + not_authorized = 0x87, + topic_filter_invalid = 0x8f, + packet_identifier_in_use = 0x91, + quota_exceeded = 0x97, + shared_subscriptions_not_supported = 0x9e, + subscription_identifiers_not_supported = 0xa1, + wildcard_subscriptions_not_supported = 0xa2, +}; + +constexpr +char const* suback_reason_code_to_str(suback_reason_code v) { + switch(v) + { + case suback_reason_code::granted_qos_0: return "granted_qos_0"; + case suback_reason_code::granted_qos_1: return "granted_qos_1"; + case suback_reason_code::granted_qos_2: return "granted_qos_2"; + case suback_reason_code::unspecified_error: return "unspecified_error"; + case suback_reason_code::implementation_specific_error: return "implementation_specific_error"; + case suback_reason_code::not_authorized: return "not_authorized"; + case suback_reason_code::topic_filter_invalid: return "topic_filter_invalid"; + case suback_reason_code::packet_identifier_in_use: return "packet_identifier_in_use"; + case suback_reason_code::quota_exceeded: return "quota_exceeded"; + case suback_reason_code::shared_subscriptions_not_supported: return "shared_subscriptions_not_supported"; + case suback_reason_code::subscription_identifiers_not_supported: return "subscription_identifiers_not_supported"; + case suback_reason_code::wildcard_subscriptions_not_supported: return "wildcard_subscriptions_not_supported"; + default: return "unknown_suback_reason_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, suback_reason_code val) +{ + os << suback_reason_code_to_str(val); + return os; +} + +constexpr suback_reason_code qos_to_suback_reason_code(qos q) { + return static_cast(q); +} + +enum class unsuback_reason_code : std::uint8_t { + success = 0x00, + no_subscription_existed = 0x11, + unspecified_error = 0x80, + implementation_specific_error = 0x83, + not_authorized = 0x87, + topic_filter_invalid = 0x8f, + packet_identifier_in_use = 0x91, +}; + +constexpr +char const* unsuback_reason_code_to_str(unsuback_reason_code v) { + switch(v) + { + case unsuback_reason_code::success: return "success"; + case unsuback_reason_code::no_subscription_existed: return "no_subscription_existed"; + case unsuback_reason_code::unspecified_error: return "unspecified_error"; + case unsuback_reason_code::implementation_specific_error: return "implementation_specific_error"; + case unsuback_reason_code::not_authorized: return "not_authorized"; + case unsuback_reason_code::topic_filter_invalid: return "topic_filter_invalid"; + case unsuback_reason_code::packet_identifier_in_use: return "packet_identifier_in_use"; + default: return "unknown_unsuback_reason_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, unsuback_reason_code val) +{ + os << unsuback_reason_code_to_str(val); + return os; +} + +enum class puback_reason_code : std::uint8_t { + success = 0x00, + no_matching_subscribers = 0x10, + unspecified_error = 0x80, + implementation_specific_error = 0x83, + not_authorized = 0x87, + topic_name_invalid = 0x90, + packet_identifier_in_use = 0x91, + quota_exceeded = 0x97, + payload_format_invalid = 0x99, +}; + +constexpr +char const* puback_reason_code_to_str(puback_reason_code v) { + switch(v) + { + case puback_reason_code::success: return "success"; + case puback_reason_code::no_matching_subscribers: return "no_matching_subscribers"; + case puback_reason_code::unspecified_error: return "unspecified_error"; + case puback_reason_code::implementation_specific_error: return "implementation_specific_error"; + case puback_reason_code::not_authorized: return "not_authorized"; + case puback_reason_code::topic_name_invalid: return "topic_name_invalid"; + case puback_reason_code::packet_identifier_in_use: return "packet_identifier_in_use"; + case puback_reason_code::quota_exceeded: return "quota_exceeded"; + case puback_reason_code::payload_format_invalid: return "payload_format_invalid"; + default: return "unknown_puback_reason_code"; + } +} + +constexpr +bool is_error(puback_reason_code v) { + return static_cast(v) >= 0x80; +} + +inline +std::ostream& operator<<(std::ostream& os, puback_reason_code val) +{ + os << puback_reason_code_to_str(val); + return os; +} + +enum class pubrec_reason_code : std::uint8_t { + success = 0x00, + no_matching_subscribers = 0x10, + unspecified_error = 0x80, + implementation_specific_error = 0x83, + not_authorized = 0x87, + topic_name_invalid = 0x90, + packet_identifier_in_use = 0x91, + quota_exceeded = 0x97, + payload_format_invalid = 0x99, +}; + +constexpr +char const* pubrec_reason_code_to_str(pubrec_reason_code v) { + switch(v) + { + case pubrec_reason_code::success: return "success"; + case pubrec_reason_code::no_matching_subscribers: return "no_matching_subscribers"; + case pubrec_reason_code::unspecified_error: return "unspecified_error"; + case pubrec_reason_code::implementation_specific_error: return "implementation_specific_error"; + case pubrec_reason_code::not_authorized: return "not_authorized"; + case pubrec_reason_code::topic_name_invalid: return "topic_name_invalid"; + case pubrec_reason_code::packet_identifier_in_use: return "packet_identifier_in_use"; + case pubrec_reason_code::quota_exceeded: return "quota_exceeded"; + case pubrec_reason_code::payload_format_invalid: return "payload_format_invalid"; + default: return "unknown_pubrec_reason_code"; + } +} + +constexpr +bool is_error(pubrec_reason_code v) { + return static_cast(v) >= 0x80; +} + +inline +std::ostream& operator<<(std::ostream& os, pubrec_reason_code val) +{ + os << pubrec_reason_code_to_str(val); + return os; +} + +enum class pubrel_reason_code : std::uint8_t { + success = 0x00, + packet_identifier_not_found = 0x92, +}; + +constexpr +char const* pubrel_reason_code_to_str(pubrel_reason_code v) { + switch(v) + { + case pubrel_reason_code::success: return "success"; + case pubrel_reason_code::packet_identifier_not_found: return "packet_identifier_not_found"; + default: return "unknown_pubrel_reason_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, pubrel_reason_code val) +{ + os << pubrel_reason_code_to_str(val); + return os; +} + +enum class pubcomp_reason_code : std::uint8_t { + success = 0x00, + packet_identifier_not_found = 0x92, +}; + +constexpr +char const* pubcomp_reason_code_to_str(pubcomp_reason_code v) { + switch(v) + { + case pubcomp_reason_code::success: return "success"; + case pubcomp_reason_code::packet_identifier_not_found: return "packet_identifier_not_found"; + default: return "unknown_pubcomp_reason_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, pubcomp_reason_code val) +{ + os << pubcomp_reason_code_to_str(val); + return os; +} + +enum class auth_reason_code : std::uint8_t { + success = 0x00, + continue_authentication = 0x18, + re_authenticate = 0x19, +}; + +constexpr +char const* auth_reason_code_to_str(auth_reason_code v) { + switch(v) + { + case auth_reason_code::success: return "success"; + case auth_reason_code::continue_authentication: return "continue_authentication"; + case auth_reason_code::re_authenticate: return "re_authenticate"; + default: return "unknown_auth_reason_code"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, auth_reason_code val) +{ + os << auth_reason_code_to_str(val); + return os; +} + +} // v5 +} // namespace MQTT_NS + +#endif // MQTT_REASON_CODE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/remaining_length.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/remaining_length.hpp new file mode 100644 index 000000000..e239a2e79 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/remaining_length.hpp @@ -0,0 +1,36 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_REMAINING_LENGTH_HPP) +#define MQTT_REMAINING_LENGTH_HPP + +#include +#include +#include + +namespace MQTT_NS { + +inline std::string +remaining_bytes(std::size_t size) { + std::string bytes = variable_bytes(size); + if (bytes.empty() || bytes.size() > 4) throw remaining_length_error(); + return bytes; +} + +constexpr std::tuple +remaining_length(string_view bytes) { + return variable_length(bytes); +} + +template +constexpr std::tuple +remaining_length(Iterator b, Iterator e) { + return variable_length(b, e); +} + +} // namespace MQTT_NS + +#endif // MQTT_REMAINING_LENGTH_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/server.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/server.hpp new file mode 100644 index 000000000..a9c2377e1 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/server.hpp @@ -0,0 +1,1065 @@ +// Copyright Takatoshi Kondo 2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SERVER_HPP) +#define MQTT_SERVER_HPP + +#include // should be top to configure variant limit + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +template class LockGuard, std::size_t PacketIdBytes> +class server_endpoint : public endpoint { +public: + using endpoint::endpoint; +protected: + void on_pre_send() noexcept override {} + void on_close() noexcept override {} + void on_error(error_code /*ec*/) noexcept override {} +protected: + ~server_endpoint() = default; +}; + +template < + typename Strand = strand, + typename Mutex = std::mutex, + template class LockGuard = std::lock_guard, + std::size_t PacketIdBytes = 2 +> +class server { +public: + using socket_t = tcp_endpoint; + using endpoint_t = callable_overlay>; + + /** + * @brief Accept handler + * @param ep endpoint of the connecting client + */ + using accept_handler = std::function ep)>; + + /** + * @brief Error handler + * @param ec error code + */ + using error_handler = std::function; + + template + server( + AsioEndpoint&& ep, + as::io_context& ioc_accept, + as::io_context& ioc_con, + AcceptorConfig&& config) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_(&ioc_con), + ioc_con_getter_([this]() -> as::io_context& { return *ioc_con_; }), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)) { + config_(acceptor_.value()); + } + + template + server( + AsioEndpoint&& ep, + as::io_context& ioc_accept, + as::io_context& ioc_con) + : server(std::forward(ep), ioc_accept, ioc_con, [](as::ip::tcp::acceptor&) {}) {} + + template + server( + AsioEndpoint&& ep, + as::io_context& ioc, + AcceptorConfig&& config) + : server(std::forward(ep), ioc, ioc, std::forward(config)) {} + + template + server( + AsioEndpoint&& ep, + as::io_context& ioc) + : server(std::forward(ep), ioc, ioc, [](as::ip::tcp::acceptor&) {}) {} + + template + server( + AsioEndpoint&& ep, + as::io_context& ioc_accept, + std::function ioc_con_getter, + AcceptorConfig&& config = [](as::ip::tcp::acceptor&) {}) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_getter_(force_move(ioc_con_getter)), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)) { + config_(acceptor_.value()); + } + + void listen() { + close_request_ = false; + + if (!acceptor_) { + try { + acceptor_.emplace(ioc_accept_, ep_); + config_(acceptor_.value()); + } + catch (boost::system::system_error const& e) { + as::post( + ioc_accept_, + [this, ec = e.code()] { + if (h_error_) h_error_(ec); + } + ); + return; + } + } + do_accept(); + } + + unsigned short port() const { return acceptor_.value().local_endpoint().port(); } + + void close() { + close_request_ = true; + as::post( + ioc_accept_, + [this] { + acceptor_.reset(); + } + ); + } + + void set_accept_handler(accept_handler h = accept_handler()) { + h_accept_ = force_move(h); + } + + /** + * @brief Set error handler + * @param h handler + */ + void set_error_handler(error_handler h = error_handler()) { + h_error_ = force_move(h); + } + + /** + * @brief Set MQTT protocol version + * @param version accepting protocol version + * If the specific version is set, only set version is accepted. + * If the version is set to protocol_version::undetermined, all versions are accepted. + * Initial value is protocol_version::undetermined. + */ + void set_protocol_version(protocol_version version) { + version_ = version; + } + +private: + void do_accept() { + if (close_request_) return; + auto& ioc_con = ioc_con_getter_(); + auto socket = std::make_shared(ioc_con); + acceptor_.value().async_accept( + socket->lowest_layer(), + [this, socket, &ioc_con] + (error_code ec) mutable { + if (ec) { + acceptor_.reset(); + if (h_error_) h_error_(ec); + return; + } + auto sp = std::make_shared(ioc_con, force_move(socket), version_); + if (h_accept_) h_accept_(force_move(sp)); + do_accept(); + } + ); + } + +private: + as::ip::tcp::endpoint ep_; + as::io_context& ioc_accept_; + as::io_context* ioc_con_ = nullptr; + std::function ioc_con_getter_; + optional acceptor_; + std::function config_; + bool close_request_{false}; + accept_handler h_accept_; + error_handler h_error_; + protocol_version version_ = protocol_version::undetermined; +}; + +#if defined(MQTT_USE_TLS) + +template < + typename Strand = strand, + typename Mutex = std::mutex, + template class LockGuard = std::lock_guard, + std::size_t PacketIdBytes = 2 +> +class server_tls { +public: + using socket_t = tcp_endpoint, Strand>; + using endpoint_t = callable_overlay>; + + /** + * @brief Accept handler + * @param ep endpoint of the connecting client + */ + using accept_handler = std::function ep)>; + + /** + * @brief Error handler + * @param ec error code + */ + using error_handler = std::function; + + template + server_tls( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc_accept, + as::io_context& ioc_con, + AcceptorConfig&& config) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_(&ioc_con), + ioc_con_getter_([this]() -> as::io_context& { return *ioc_con_; }), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)), + ctx_(force_move(ctx)) { + config_(acceptor_.value()); + } + + template + server_tls( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc_accept, + as::io_context& ioc_con) + : server_tls(std::forward(ep), force_move(ctx), ioc_accept, ioc_con, [](as::ip::tcp::acceptor&) {}) {} + + template + server_tls( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc, + AcceptorConfig&& config) + : server_tls(std::forward(ep), force_move(ctx), ioc, ioc, std::forward(config)) {} + + template + server_tls( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc) + : server_tls(std::forward(ep), force_move(ctx), ioc, ioc, [](as::ip::tcp::acceptor&) {}) {} + + template + server_tls( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc_accept, + std::function ioc_con_getter, + AcceptorConfig&& config = [](as::ip::tcp::acceptor&) {}) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_getter_(force_move(ioc_con_getter)), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)), + ctx_(force_move(ctx)) { + config_(acceptor_.value()); + } + + void listen() { + close_request_ = false; + + if (!acceptor_) { + try { + acceptor_.emplace(ioc_accept_, ep_); + config_(acceptor_.value()); + } + catch (boost::system::system_error const& e) { + as::post( + ioc_accept_, + [this, ec = e.code()] { + if (h_error_) h_error_(ec); + } + ); + return; + } + } + do_accept(); + } + + unsigned short port() const { return acceptor_.value().local_endpoint().port(); } + + void close() { + close_request_ = true; + as::post( + ioc_accept_, + [this] { + acceptor_.reset(); + } + ); + } + + void set_accept_handler(accept_handler h = accept_handler()) { + h_accept_ = force_move(h); + } + + /** + * @brief Set error handler + * @param h handler + */ + void set_error_handler(error_handler h = error_handler()) { + h_error_ = force_move(h); + } + + /** + * @brief Set MQTT protocol version + * @param version accepting protocol version + * If the specific version is set, only set version is accepted. + * If the version is set to protocol_version::undetermined, all versions are accepted. + * Initial value is protocol_version::undetermined. + */ + void set_protocol_version(protocol_version version) { + version_ = version; + } + + /** + * @bried Set underlying layer connection timeout. + * The timer is set after TCP layer connection accepted. + * The timer is cancelled just before accept handler is called. + * If the timer is fired, the endpoint is removed, the socket is automatically closed. + * The default timeout value is 10 seconds. + * @param timeout timeout value + */ + void set_underlying_connect_timeout(std::chrono::steady_clock::duration timeout) { + underlying_connect_timeout_ = force_move(timeout); + } + + /** + * @brief Get boost asio ssl context. + * @return ssl context + */ + tls::context& get_ssl_context() { + return ctx_; + } + + /** + * @brief Get boost asio ssl context. + * @return ssl context + */ + tls::context const& get_ssl_context() const { + return ctx_; + } + + using verify_cb_t = std::function> const&) >; + + void set_verify_callback(verify_cb_t verify_cb) { + verify_cb_with_username_ = verify_cb; + } + +private: + void do_accept() { + if (close_request_) return; + auto& ioc_con = ioc_con_getter_(); + auto socket = std::make_shared(ioc_con, ctx_); + + auto ps = socket.get(); + acceptor_.value().async_accept( + ps->lowest_layer(), + [this, socket = force_move(socket), &ioc_con] + (error_code ec) mutable { + if (ec) { + acceptor_.reset(); + if (h_error_) h_error_(ec); + return; + } + auto underlying_finished = std::make_shared(false); + auto tim = std::make_shared(ioc_con); + tim->expires_after(underlying_connect_timeout_); + tim->async_wait( + [socket, tim, underlying_finished] + (error_code ec) { + if (*underlying_finished) return; + if (ec) return; + socket->post( + [socket] { + boost::system::error_code close_ec; + socket->lowest_layer().close(close_ec); + } + ); + } + ); + auto ps = socket.get(); + + auto username = std::make_shared>(); // shared_ptr for username + auto verify_cb_ = [this, username] // copy capture socket shared_ptr + (bool preverified, boost::asio::ssl::verify_context& ctx) { + // user can set username in the callback + return verify_cb_with_username_ + ? verify_cb_with_username_(preverified, ctx, username) + : false; + }; + + ctx_.set_verify_mode(MQTT_NS::tls::verify_peer); + ctx_.set_verify_callback(verify_cb_); + + ps->async_handshake( + tls::stream_base::server, + [this, socket = force_move(socket), tim, underlying_finished, &ioc_con, username] + (error_code ec) mutable { + *underlying_finished = true; + tim->cancel(); + if (ec) { + return; + } + auto sp = std::make_shared(ioc_con, force_move(socket), version_); + sp->set_preauthed_user_name(*username); + if (h_accept_) h_accept_(force_move(sp)); + } + ); + do_accept(); + } + ); + } + +private: + verify_cb_t verify_cb_with_username_; + + as::ip::tcp::endpoint ep_; + as::io_context& ioc_accept_; + as::io_context* ioc_con_ = nullptr; + std::function ioc_con_getter_; + optional acceptor_; + std::function config_; + bool close_request_{false}; + accept_handler h_accept_; + error_handler h_error_; + tls::context ctx_; + protocol_version version_ = protocol_version::undetermined; + std::chrono::steady_clock::duration underlying_connect_timeout_ = std::chrono::seconds(10); +}; + +#endif // defined(MQTT_USE_TLS) + +#if defined(MQTT_USE_WS) + +template < + typename Strand = strand, + typename Mutex = std::mutex, + template class LockGuard = std::lock_guard, + std::size_t PacketIdBytes = 2 +> +class server_ws { +public: + using socket_t = ws_endpoint; + using endpoint_t = callable_overlay>; + + /** + * @brief Accept handler + * @param ep endpoint of the connecting client + */ + using accept_handler = std::function ep)>; + + /** + * @brief Error handler + * @param ec error code + */ + using error_handler = std::function; + + template + server_ws( + AsioEndpoint&& ep, + as::io_context& ioc_accept, + as::io_context& ioc_con, + AcceptorConfig&& config) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_(&ioc_con), + ioc_con_getter_([this]() -> as::io_context& { return *ioc_con_; }), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)) { + config_(acceptor_.value()); + } + + template + server_ws( + AsioEndpoint&& ep, + as::io_context& ioc_accept, + as::io_context& ioc_con) + : server_ws(std::forward(ep), ioc_accept, ioc_con, [](as::ip::tcp::acceptor&) {}) {} + + template + server_ws( + AsioEndpoint&& ep, + as::io_context& ioc, + AcceptorConfig&& config) + : server_ws(std::forward(ep), ioc, ioc, std::forward(config)) {} + + template + server_ws( + AsioEndpoint&& ep, + as::io_context& ioc) + : server_ws(std::forward(ep), ioc, ioc, [](as::ip::tcp::acceptor&) {}) {} + + template + server_ws( + AsioEndpoint&& ep, + as::io_context& ioc_accept, + std::function ioc_con_getter, + AcceptorConfig&& config = [](as::ip::tcp::acceptor&) {}) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_getter_(force_move(ioc_con_getter)), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)) { + config_(acceptor_.value()); + } + void listen() { + close_request_ = false; + + if (!acceptor_) { + try { + acceptor_.emplace(ioc_accept_, ep_); + config_(acceptor_.value()); + } + catch (boost::system::system_error const& e) { + as::post( + ioc_accept_, + [this, ec = e.code()] { + if (h_error_) h_error_(ec); + } + ); + return; + } + } + do_accept(); + } + + unsigned short port() const { return acceptor_.value().local_endpoint().port(); } + + void close() { + close_request_ = true; + as::post( + ioc_accept_, + [this] { + acceptor_.reset(); + } + ); + } + + void set_accept_handler(accept_handler h = accept_handler()) { + h_accept_ = force_move(h); + } + + /** + * @brief Set error handler + * @param h handler + */ + void set_error_handler(error_handler h = error_handler()) { + h_error_ = force_move(h); + } + + /** + * @brief Set MQTT protocol version + * @param version accepting protocol version + * If the specific version is set, only set version is accepted. + * If the version is set to protocol_version::undetermined, all versions are accepted. + * Initial value is protocol_version::undetermined. + */ + void set_protocol_version(protocol_version version) { + version_ = version; + } + + /** + * @bried Set underlying layer connection timeout. + * The timer is set after TCP layer connection accepted. + * The timer is cancelled just before accept handler is called. + * If the timer is fired, the endpoint is removed, the socket is automatically closed. + * The default timeout value is 10 seconds. + * @param timeout timeout value + */ + void set_underlying_connect_timeout(std::chrono::steady_clock::duration timeout) { + underlying_connect_timeout_ = force_move(timeout); + } + +private: + void do_accept() { + if (close_request_) return; + auto& ioc_con = ioc_con_getter_(); + auto socket = std::make_shared(ioc_con); + auto ps = socket.get(); + acceptor_.value().async_accept( + ps->next_layer(), + [this, socket = force_move(socket), &ioc_con] + (error_code ec) mutable { + if (ec) { + acceptor_.reset(); + if (h_error_) h_error_(ec); + return; + } + auto underlying_finished = std::make_shared(false); + auto tim = std::make_shared(ioc_con); + tim->expires_after(underlying_connect_timeout_); + tim->async_wait( + [socket, tim, underlying_finished] + (error_code ec) { + if (*underlying_finished) return; + if (ec) return; + socket->post( + [socket] { + boost::system::error_code close_ec; + socket->lowest_layer().close(close_ec); + } + ); + } + ); + + auto sb = std::make_shared(); + auto request = std::make_shared>(); + auto ps = socket.get(); + boost::beast::http::async_read( + ps->next_layer(), + *sb, + *request, + [this, socket = force_move(socket), sb, request, tim, underlying_finished, &ioc_con] + (error_code ec, std::size_t) mutable { + if (ec) { + *underlying_finished = true; + tim->cancel(); + return; + } + if (!boost::beast::websocket::is_upgrade(*request)) { + *underlying_finished = true; + tim->cancel(); + return; + } + auto ps = socket.get(); + +#if BOOST_BEAST_VERSION >= 248 + + auto it = request->find("Sec-WebSocket-Protocol"); + if (it != request->end()) { + ps->set_option( + boost::beast::websocket::stream_base::decorator( + [name = it->name(), value = it->value()] // name is enum, value is boost::string_view + (boost::beast::websocket::response_type& res) { + // This lambda is called before the scope out point *1 + res.set(name, value); + } + ) + ); + } + ps->async_accept( + *request, + [this, socket = force_move(socket), tim, underlying_finished, &ioc_con] + (error_code ec) mutable { + *underlying_finished = true; + tim->cancel(); + if (ec) { + return; + } + auto sp = std::make_shared(ioc_con, force_move(socket), version_); + if (h_accept_) h_accept_(force_move(sp)); + } + ); + +#else // BOOST_BEAST_VERSION >= 248 + + ps->async_accept_ex( + *request, + [request] + (boost::beast::websocket::response_type& m) { + auto it = request->find("Sec-WebSocket-Protocol"); + if (it != request->end()) { + m.insert(it->name(), it->value()); + } + }, + [this, socket = force_move(socket), tim, underlying_finished, &ioc_con] + (error_code ec) mutable { + *underlying_finished = true; + tim->cancel(); + if (ec) { + return; + } + auto sp = std::make_shared(ioc_con, force_move(socket), version_); + if (h_accept_) h_accept_(force_move(sp)); + } + ); + +#endif // BOOST_BEAST_VERSION >= 248 + + // scope out point *1 + } + ); + do_accept(); + } + ); + } + +private: + as::ip::tcp::endpoint ep_; + as::io_context& ioc_accept_; + as::io_context* ioc_con_ = nullptr; + std::function ioc_con_getter_; + optional acceptor_; + std::function config_; + bool close_request_{false}; + accept_handler h_accept_; + error_handler h_error_; + protocol_version version_ = protocol_version::undetermined; + std::chrono::steady_clock::duration underlying_connect_timeout_ = std::chrono::seconds(10); +}; + + +#if defined(MQTT_USE_TLS) + +template < + typename Strand = strand, + typename Mutex = std::mutex, + template class LockGuard = std::lock_guard, + std::size_t PacketIdBytes = 2 +> +class server_tls_ws { +public: + using socket_t = ws_endpoint, Strand>; + using endpoint_t = callable_overlay>; + + /** + * @brief Accept handler + * @param ep endpoint of the connecting client + */ + using accept_handler = std::function ep)>; + + /** + * @brief Error handler + * @param ec error code + */ + using error_handler = std::function; + + template + server_tls_ws( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc_accept, + as::io_context& ioc_con, + AcceptorConfig&& config) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_(&ioc_con), + ioc_con_getter_([this]() -> as::io_context& { return *ioc_con_; }), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)), + ctx_(force_move(ctx)) { + config_(acceptor_.value()); + } + + template + server_tls_ws( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc_accept, + as::io_context& ioc_con) + : server_tls_ws(std::forward(ep), force_move(ctx), ioc_accept, ioc_con, [](as::ip::tcp::acceptor&) {}) {} + + template + server_tls_ws( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc, + AcceptorConfig&& config) + : server_tls_ws(std::forward(ep), force_move(ctx), ioc, ioc, std::forward(config)) {} + + template + server_tls_ws( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc) + : server_tls_ws(std::forward(ep), force_move(ctx), ioc, ioc, [](as::ip::tcp::acceptor&) {}) {} + + template + server_tls_ws( + AsioEndpoint&& ep, + tls::context&& ctx, + as::io_context& ioc_accept, + std::function ioc_con_getter, + AcceptorConfig&& config = [](as::ip::tcp::acceptor&) {}) + : ep_(std::forward(ep)), + ioc_accept_(ioc_accept), + ioc_con_getter_(force_move(ioc_con_getter)), + acceptor_(as::ip::tcp::acceptor(ioc_accept_, ep_)), + config_(std::forward(config)), + ctx_(force_move(ctx)) { + config_(acceptor_.value()); + } + + void listen() { + close_request_ = false; + + if (!acceptor_) { + try { + acceptor_.emplace(ioc_accept_, ep_); + config_(acceptor_.value()); + } + catch (boost::system::system_error const& e) { + as::post( + ioc_accept_, + [this, ec = e.code()] { + if (h_error_) h_error_(ec); + } + ); + return; + } + } + do_accept(); + } + + unsigned short port() const { return acceptor_.value().local_endpoint().port(); } + + void close() { + close_request_ = true; + as::post( + ioc_accept_, + [this] { + acceptor_.reset(); + } + ); + } + + void set_accept_handler(accept_handler h = accept_handler()) { + h_accept_ = force_move(h); + } + + /** + * @brief Set error handler + * @param h handler + */ + void set_error_handler(error_handler h = error_handler()) { + h_error_ = force_move(h); + } + + /** + * @brief Set MQTT protocol version + * @param version accepting protocol version + * If the specific version is set, only set version is accepted. + * If the version is set to protocol_version::undetermined, all versions are accepted. + * Initial value is protocol_version::undetermined. + */ + void set_protocol_version(protocol_version version) { + version_ = version; + } + + /** + * @bried Set underlying layer connection timeout. + * The timer is set after TCP layer connection accepted. + * The timer is cancelled just before accept handler is called. + * If the timer is fired, the endpoint is removed, the socket is automatically closed. + * The default timeout value is 10 seconds. + * @param timeout timeout value + */ + void set_underlying_connect_timeout(std::chrono::steady_clock::duration timeout) { + underlying_connect_timeout_ = force_move(timeout); + } + + /** + * @brief Get boost asio ssl context. + * @return ssl context + */ + tls::context& get_ssl_context() { + return ctx_; + } + + /** + * @brief Get boost asio ssl context. + * @return ssl context + */ + tls::context const& get_ssl_context() const { + return ctx_; + } + + using verify_cb_t = std::function> const&) >; + + void set_verify_callback(verify_cb_t verify_cb) { + verify_cb_with_username_ = verify_cb; + } + +private: + void do_accept() { + if (close_request_) return; + auto& ioc_con = ioc_con_getter_(); + auto socket = std::make_shared(ioc_con, ctx_); + auto ps = socket.get(); + acceptor_.value().async_accept( + ps->next_layer().next_layer(), + [this, socket = force_move(socket), &ioc_con] + (error_code ec) mutable { + if (ec) { + acceptor_.reset(); + if (h_error_) h_error_(ec); + return; + } + auto underlying_finished = std::make_shared(false); + auto tim = std::make_shared(ioc_con); + tim->expires_after(underlying_connect_timeout_); + tim->async_wait( + [socket, tim, underlying_finished] + (error_code ec) { + if (*underlying_finished) return; + if (ec) return; + socket->post( + [socket] { + boost::system::error_code close_ec; + socket->lowest_layer().close(close_ec); + } + ); + } + ); + + auto ps = socket.get(); + + auto username = std::make_shared>(); // shared_ptr for username + auto verify_cb_ = [this, username] // copy capture socket shared_ptr + (bool preverified, boost::asio::ssl::verify_context& ctx) { + // user can set username in the callback + return verify_cb_with_username_ + ? verify_cb_with_username_(preverified, ctx, username) + : false; + }; + + ctx_.set_verify_mode(MQTT_NS::tls::verify_peer); + ctx_.set_verify_callback(verify_cb_); + + ps->next_layer().async_handshake( + tls::stream_base::server, + [this, socket = force_move(socket), tim, underlying_finished, &ioc_con, username] + (error_code ec) mutable { + if (ec) { + *underlying_finished = true; + tim->cancel(); + return; + } + auto sb = std::make_shared(); + auto request = std::make_shared>(); + auto ps = socket.get(); + boost::beast::http::async_read( + ps->next_layer(), + *sb, + *request, + [this, socket = force_move(socket), sb, request, tim, underlying_finished, &ioc_con, username] + (error_code ec, std::size_t) mutable { + if (ec) { + *underlying_finished = true; + tim->cancel(); + return; + } + if (!boost::beast::websocket::is_upgrade(*request)) { + *underlying_finished = true; + tim->cancel(); + return; + } + auto ps = socket.get(); + +#if BOOST_BEAST_VERSION >= 248 + + auto it = request->find("Sec-WebSocket-Protocol"); + if (it != request->end()) { + ps->set_option( + boost::beast::websocket::stream_base::decorator( + [name = it->name(), value = it->value()] // name is enum, value is boost::string_view + (boost::beast::websocket::response_type& res) { + // This lambda is called before the scope out point *1 + res.set(name, value); + } + ) + ); + } + ps->async_accept( + *request, + [this, socket = force_move(socket), tim, underlying_finished, &ioc_con, username] + (error_code ec) mutable { + *underlying_finished = true; + tim->cancel(); + if (ec) { + return; + } + auto sp = std::make_shared(ioc_con, force_move(socket), version_); + sp->set_preauthed_user_name(*username); + if (h_accept_) h_accept_(force_move(sp)); + } + ); + +#else // BOOST_BEAST_VERSION >= 248 + + ps->async_accept_ex( + *request, + [request] + (boost::beast::websocket::response_type& m) { + auto it = request->find("Sec-WebSocket-Protocol"); + if (it != request->end()) { + m.insert(it->name(), it->value()); + } + }, + [this, socket = force_move(socket), tim, underlying_finished, &ioc_con, username] + (error_code ec) mutable { + *underlying_finished = true; + tim->cancel(); + if (ec) { + return; + } + // TODO: The use of force_move on this line of code causes + // a static assertion that socket is a const object when + // TLS is enabled, and WS is enabled, with Boost 1.70, and gcc 8.3.0 + auto sp = std::make_shared(ioc_con, socket, version_); + sp->set_preauthed_user_name(*username); + if (h_accept_) h_accept_(force_move(sp)); + } + ); + +#endif // BOOST_BEAST_VERSION >= 248 + + // scope out point *1 + } + ); + } + ); + do_accept(); + } + ); + } + +private: + verify_cb_t verify_cb_with_username_; + + as::ip::tcp::endpoint ep_; + as::io_context& ioc_accept_; + as::io_context* ioc_con_ = nullptr; + std::function ioc_con_getter_; + optional acceptor_; + std::function config_; + bool close_request_{false}; + accept_handler h_accept_; + error_handler h_error_; + tls::context ctx_; + protocol_version version_ = protocol_version::undetermined; + std::chrono::steady_clock::duration underlying_connect_timeout_ = std::chrono::seconds(10); +}; + +#endif // defined(MQTT_USE_TLS) + +#endif // defined(MQTT_USE_WS) + +} // namespace MQTT_NS + +#endif // MQTT_SERVER_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/session_present.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/session_present.hpp new file mode 100644 index 000000000..92df24ff3 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/session_present.hpp @@ -0,0 +1,20 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SESSION_PRESENT_HPP) +#define MQTT_SESSION_PRESENT_HPP + +#include + +namespace MQTT_NS { + +constexpr bool is_session_present(char v) { + return v & 0b00000001; +} + +} // namespace MQTT_NS + +#endif // MQTT_SESSION_PRESENT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/setup_log.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/setup_log.hpp new file mode 100644 index 000000000..2d3e8a038 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/setup_log.hpp @@ -0,0 +1,154 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SETUP_LOG_HPP) +#define MQTT_SETUP_LOG_HPP + +// This is an example implementation for logging setup. +// If your code doesn't use Boost.Log then you can use the setup_log() directly. +// setup_log() provides a typical console logging setup. +// If you want to use existing Boost.Log related code with mqtt_cpp, +// then you can write your own logging setup code. +// setup_log() could be a good reference for your own logging setup code. + +#include +#include + +#if defined(MQTT_USE_LOG) + +#include + +#include +#include + +#endif // defined(MQTT_USE_LOG) + +namespace MQTT_NS { + +#if defined(MQTT_USE_LOG) + +static constexpr char const* log_color_table[] { + "\033[0m", // trace + "\033[36m", // debug + "\033[32m", // info + "\033[33m", // warning + "\033[35m", // error + "\033[31m", // fatal +}; + +/** + * @brief Setup logging + * @param threshold + * Set threshold severity_level by channel + * If the log severity_level >= threshold then log message outputs. + */ +inline +void setup_log(std::map threshold) { + // https://www.boost.org/doc/libs/1_73_0/libs/log/doc/html/log/tutorial/advanced_filtering.html + + auto fmt = + [](boost::log::record_view const& rec, boost::log::formatting_ostream& strm) { + // Timestamp custom formatting example + if (auto v = boost::log::extract("TimeStamp", rec)) { + strm.imbue( + std::locale( + strm.getloc(), + // https://www.boost.org/doc/html/date_time/date_time_io.html#date_time.format_flags + new boost::posix_time::time_facet("%H:%M:%s") // ownership is moved here + ) + ); + strm << v.get() << " "; + } + // ThreadID example + if (auto v = boost::log::extract("ThreadID", rec)) { + strm << "T:" << v.get() << " "; + } + // Adjust severity length example + if (auto v = boost::log::extract("Severity", rec)) { + strm << log_color_table[static_cast(v.get())]; + strm << "S:" << std::setw(7) << std::left << v.get() << " "; + } + if (auto v = boost::log::extract("Channel", rec)) { + strm << "C:" << std::setw(5) << std::left << v.get() << " "; + } + // Shorten file path example + if (auto v = boost::log::extract("MqttFile", rec)) { + strm << boost::filesystem::path(v.get()).filename().string() << ":"; + } + if (auto v = boost::log::extract("MqttLine", rec)) { + strm << v.get() << " "; + } + if (auto v = boost::log::extract("MqttAddress", rec)) { + strm << "A:" << v.get() << " "; + } + +#if 0 // function is ofthen noisy + if (auto v = boost::log::extract("MqttFunction", rec)) { + strm << v << ":"; + } +#endif + strm << rec[boost::log::expressions::smessage]; + strm << "\033[0m"; + }; + + // https://www.boost.org/doc/libs/1_73_0/libs/log/doc/html/log/tutorial/sinks.html + boost::shared_ptr stream(&std::clog, boost::null_deleter()); + + using text_sink = boost::log::sinks::synchronous_sink; + auto sink = boost::make_shared(); + sink->locked_backend()->add_stream(stream); + sink->set_formatter(fmt); + + auto fil = + [threshold = force_move(threshold)] + (boost::log::attribute_value_set const& avs) { + { + // For mqtt + auto chan = boost::log::extract("Channel", avs); + auto sev = boost::log::extract("Severity", avs); + if (chan && sev) { + auto it = threshold.find(chan.get()); + if (it == threshold.end()) return false; + return sev.get() >= it->second; + } + } + return true; + }; + + boost::log::core::get()->set_filter(fil); + boost::log::core::get()->add_sink(sink); + + boost::log::add_common_attributes(); +} + +/** + * @brief Setup logging + * @param threshold + * Set threshold severity_level for all channels + * If the log severity_level >= threshold then log message outputs. + */ +inline +void setup_log(severity_level threshold = severity_level::warning) { + setup_log( + { + { "mqtt_api", threshold }, + { "mqtt_cb", threshold }, + { "mqtt_impl", threshold }, + { "mqtt_broker", threshold }, + } + ); +} + +#else // defined(MQTT_USE_LOG) + +template +void setup_log(Params&&...) {} + +#endif // defined(MQTT_USE_LOG) + +} // namespace MQTT_NS + +#endif // MQTT_SETUP_LOG_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_ptr_array.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_ptr_array.hpp new file mode 100644 index 000000000..de3d3574a --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_ptr_array.hpp @@ -0,0 +1,79 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SHARED_PTR_ARRAY_HPP) +#define MQTT_SHARED_PTR_ARRAY_HPP + +#if defined(_DOXYGEN_) + +/** + * @brief Type alias of shared_ptr char array. + * You can choose the target type. + * - If MQTT_STD_SHARED_PTR_ARRAY is defined, `std::shared_ptr` is used. + * - std::shared_ptr is supported since C++17. + * - If MQTT_STD_SHARED_PTR_ARRAY is not defined (default), `boost::shared_ptr` is used. + * - `boost::shared_ptr` can be used on C++14. + */ +using shared_ptr_array = std::shared_ptr; +using const_shared_ptr_array = std::shared_ptr; + +/** + * @brief shared_ptr_array creating function. + * You can choose the target type. + * - If MQTT_STD_SHARED_PTR_ARRAY is defined, + * - and if your compiler setting is C++20 or later, then `std::make_shared(size)` is used. + * - It can allocate an array of characters and the control block in a single allocation. + * - otherwise `std::shared_ptr(new char[size])` is used. + * - It requires two times allocations. + * - If MQTT_STD_SHARED_PTR_ARRAY is not defined (default), then `boost::make_shared(size)` is used. + * - It can allocate an array of characters and the control block in a single allocation. + */ +inline shared_ptr_array make_shared_ptr_array(std::size_t size); + +#else // defined(_DOXYGEN_) + +#include + +#ifdef MQTT_STD_SHARED_PTR_ARRAY + +#include + +namespace MQTT_NS { + +using shared_ptr_array = std::shared_ptr; +using const_shared_ptr_array = std::shared_ptr; + +inline shared_ptr_array make_shared_ptr_array(std::size_t size) { +#if __cpp_lib_shared_ptr_arrays >= 201707L + return std::make_shared(size); +#else // __cpp_lib_shared_ptr_arrays >= 201707L + return std::shared_ptr(new char[size]); +#endif // __cpp_lib_shared_ptr_arrays >= 201707L +} + +} // namespace MQTT_NS + +#else // MQTT_STD_SHARED_PTR_ARRAY + +#include +#include + +namespace MQTT_NS { + +using shared_ptr_array = boost::shared_ptr; +using const_shared_ptr_array = boost::shared_ptr; + +inline shared_ptr_array make_shared_ptr_array(std::size_t size) { + return boost::make_shared(size); +} + +} // namespace MQTT_NS + +#endif // MQTT_STD_SHARED_PTR_ARRAY + +#endif // defined(_DOXYGEN_) + +#endif // MQTT_SHARED_PTR_ARRAY_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_scope_guard.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_scope_guard.hpp new file mode 100644 index 000000000..45a023bec --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_scope_guard.hpp @@ -0,0 +1,24 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SHARED_SCOPE_GUARD_HPP) +#define MQTT_SHARED_SCOPE_GUARD_HPP + +#include +#include +#include + +namespace MQTT_NS { + +template +inline auto shared_scope_guard(Proc&& proc) { + auto deleter = [proc = std::forward(proc)](void*) mutable { std::forward(proc)(); }; + return std::shared_ptr(nullptr, std::move(deleter)); +} + +} // namespace MQTT_NS + +#endif // MQTT_SHARED_SCOPE_GUARD_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_subscriptions.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_subscriptions.hpp new file mode 100644 index 000000000..3068bb698 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/shared_subscriptions.hpp @@ -0,0 +1,105 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#if !defined(MQTT_SHARED_SUBSCRIPTIONS_HPP) +#define MQTT_SHARED_SUBSCRIPTIONS_HPP + +#include + +#include +#include + +#include + +#include +#include +#include +#include + +namespace MQTT_NS { + +struct share_name_topic_filter { + share_name_topic_filter(buffer share_name, buffer topic_filter) + : share_name { force_move(share_name) }, topic_filter{ force_move(topic_filter) } + { + BOOST_ASSERT(!topic_filter.empty()); + } + + buffer share_name; + buffer topic_filter; +}; + +inline bool operator<(share_name_topic_filter const& lhs, share_name_topic_filter const& rhs) { + if (lhs.share_name < rhs.share_name) return true; + if (rhs.share_name < lhs.share_name) return false; + return lhs.topic_filter < rhs.topic_filter; +} + +inline bool operator==(share_name_topic_filter const& lhs, share_name_topic_filter const& rhs) { + return lhs.share_name == rhs.share_name && lhs.topic_filter == rhs.topic_filter; +} + +inline bool operator!=(share_name_topic_filter const& lhs, share_name_topic_filter const& rhs) { + return !(lhs == rhs); +} + + +inline optional parse_shared_subscription(buffer whole_topic_filter) { + auto const shared_prefix = string_view("$share/"); + if (whole_topic_filter.substr(0, shared_prefix.size()) != shared_prefix) { + return share_name_topic_filter{ buffer{}, force_move(whole_topic_filter) }; + } + + // Remove $share/ + whole_topic_filter.remove_prefix(shared_prefix.size()); + + // This is the '/' seperating the subscription group from the actual topic_filter. + auto const idx = whole_topic_filter.find_first_of('/'); + if (idx == string_view::npos) return nullopt; + + // We return the share_name and the topic_filter as buffers that point to the same + // storage. So we grab the substr for "share", and then remove it from whole_topic_filter. + auto share_name = whole_topic_filter.substr(0, idx); + whole_topic_filter.remove_prefix(std::min(idx + 1, whole_topic_filter.size())); + + if (share_name.empty() || whole_topic_filter.empty()) return nullopt; + return share_name_topic_filter{ force_move(share_name), force_move(whole_topic_filter) }; +} + +namespace detail { + +template +inline buffer create_topic_filter_buffer(T const& share_name, U const& topic_filter) { + string_view prefix = "$share/"; + // 1 is the length of '/' between share_name and topic_filter + auto spa = make_shared_ptr_array(prefix.size() + share_name.size() + 1 + topic_filter.size()); + auto it = spa.get(); + auto start = it; + std::copy(prefix.begin(), prefix.end(), it); + it += prefix.size(); + std::copy(share_name.begin(), share_name.end(), it); + it += share_name.size(); + *it++ = '/'; + std::copy(topic_filter.begin(), topic_filter.end(), it); + it += topic_filter.size(); + return buffer(string_view(start, static_cast(it - start)), force_move(spa)); +} + +} // namespace detail + +inline buffer create_topic_filter_buffer(string_view share_name, string_view topic_filter) { + if (share_name.empty()) return allocate_buffer(topic_filter); + return detail::create_topic_filter_buffer(share_name, topic_filter); +} +inline buffer create_topic_filter_buffer(string_view share_name, buffer topic_filter) { + if (share_name.empty()) return topic_filter; + return detail::create_topic_filter_buffer(share_name, topic_filter); +} + +} // namespace MQTT_NS + +#endif // MQTT_SHARED_SUBSCRIPTIONS_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/strand.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/strand.hpp new file mode 100644 index 000000000..1046a00f8 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/strand.hpp @@ -0,0 +1,33 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_STRAND_HPP) +#define MQTT_STRAND_HPP + +#include +#include + +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +// Determines which strand to use +#if defined(MQTT_NO_TS_EXECUTORS) + +// Use standard executor style strand +using strand = as::strand; + +#else // defined(MQTT_NO_TS_EXECUTORS) + +// Use networking TS style strand +using strand = as::io_context::strand; + +#endif // defined(MQTT_NO_TS_EXECUTORS) +} + +#endif // MQTT_STRAND_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/string_check.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/string_check.hpp new file mode 100644 index 000000000..b55b39ad3 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/string_check.hpp @@ -0,0 +1,34 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_STRING_CHECK_HPP) +#define MQTT_STRING_CHECK_HPP + +#include +#include +#include +#include +#include + +namespace as = boost::asio; + +namespace MQTT_NS { + +inline void utf8string_check(string_view str) { + if (!utf8string::is_valid_length(str)) throw utf8string_length_error(); + auto r = utf8string::validate_contents(str); + if (r != utf8string::validation::well_formed) { + throw utf8string_contents_error(r); + } +} + +inline void utf8string_check(as::const_buffer str) { + utf8string_check(string_view(get_pointer(str), get_size(str))); +} + +} // namespace MQTT_NS + +#endif // MQTT_STRING_CHECK_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/string_view.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/string_view.hpp new file mode 100644 index 000000000..e9d0b0515 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/string_view.hpp @@ -0,0 +1,106 @@ +// Copyright Takatoshi Kondo 2016 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_STRING_VIEW_HPP) +#define MQTT_STRING_VIEW_HPP + +#include + +#include + +#ifdef MQTT_STD_STRING_VIEW + +#include + +namespace MQTT_NS { + +using std::string_view; + +using std::basic_string_view; + +} // namespace MQTT_NS + +#else // MQTT_STD_STRING_VIEW + +#include + +#if !defined(MQTT_NO_BOOST_STRING_VIEW) + +#if BOOST_VERSION >= 106100 + +#define MQTT_NO_BOOST_STRING_VIEW 0 + +#include +#include + +namespace MQTT_NS { + +using string_view = boost::string_view; + +template > +using basic_string_view = boost::basic_string_view; + +} // namespace MQTT_NS + +#if BOOST_VERSION < 106900 +namespace boost { +template +std::size_t hash_value(basic_string_view s) { + return hash_range(s.begin(), s.end()); +} +} + +#endif // BOOST_VERSION < 106900 + +#else // BOOST_VERSION >= 106100 + +#define MQTT_NO_BOOST_STRING_VIEW 1 + +#include + +namespace MQTT_NS { + +using string_view = boost::string_ref; + +template > +using basic_string_view = boost::basic_string_ref; + +} // namespace MQTT_NS + +#endif // BOOST_VERSION >= 106100 + + +#endif // !defined(MQTT_NO_BOOST_STRING_VIEW) + +#endif // !defined(MQTT_STD_STRING_VIEW) + +namespace MQTT_NS { + +namespace detail { + +template +T* to_address(T* p) noexcept +{ + return p; +} + +template +auto to_address(const T& p) noexcept +{ + return detail::to_address(p.operator->()); +} + +} // namespace detail + +// Make a string_view from a pair of iterators. +template +string_view make_string_view(Begin begin, End end) { + return string_view(detail::to_address(begin), static_cast(std::distance(begin, end))); +} + +} // namespace MQTT_NS + +#endif // MQTT_STRING_VIEW_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/subscribe_entry.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/subscribe_entry.hpp new file mode 100644 index 000000000..8485aa57a --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/subscribe_entry.hpp @@ -0,0 +1,65 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SUBSCRIBE_ENTRY_HPP) +#define MQTT_SUBSCRIBE_ENTRY_HPP + +#include + +#include +#include +#include + +namespace MQTT_NS { + +struct subscribe_entry { + subscribe_entry( + buffer share_name, + buffer topic_filter, + subscribe_options subopts) + : share_name { force_move(share_name) }, + topic_filter { force_move(topic_filter) }, + subopts { subopts } + {} + + subscribe_entry( + buffer topic_filter, + subscribe_options subopts) + : topic_filter { force_move(topic_filter) }, + subopts { subopts } + {} + + // empty share name means no share name + // $share//topic_filter is protocol error + // + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901250 + // A Shared Subscription's Topic Filter MUST start with $share/ and MUST contain + // a ShareName that is at least one character long [MQTT-4.8.2-1]. + buffer share_name; + buffer topic_filter; + subscribe_options subopts; +}; + +struct unsubscribe_entry { + unsubscribe_entry( + buffer share_name, + buffer topic_filter) + : share_name { force_move(share_name) }, + topic_filter { force_move(topic_filter) } + {} + + unsubscribe_entry( + buffer topic_filter) + : topic_filter { force_move(topic_filter) } + {} + + buffer share_name; + buffer topic_filter; +}; + +} // namespace MQTT_NS + +#endif // MQTT_SUBSCRIBE_ENTRY_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/subscribe_options.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/subscribe_options.hpp new file mode 100644 index 000000000..321dfa92b --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/subscribe_options.hpp @@ -0,0 +1,161 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SUBSCRIBE_OPTIONS_HPP) +#define MQTT_SUBSCRIBE_OPTIONS_HPP + +#include +#include + +#include + +namespace MQTT_NS { + +enum class retain_handling : std::uint8_t +{ + send = 0b00000000, + send_only_new_subscription = 0b00010000, + not_send = 0b00100000, +}; +enum class rap : std::uint8_t +{ + dont = 0b00000000, + retain = 0b00001000, +}; +enum class nl : std::uint8_t +{ + no = 0b00000000, + yes = 0b00000100, +}; +enum class qos : std::uint8_t +{ + at_most_once = 0b00000000, + at_least_once = 0b00000001, + exactly_once = 0b00000010, +}; + +struct subscribe_options final { + constexpr subscribe_options() = delete; + ~subscribe_options() = default; + constexpr subscribe_options(subscribe_options &&) = default; + constexpr subscribe_options(subscribe_options const&) = default; + constexpr subscribe_options& operator=(subscribe_options &&) = default; + constexpr subscribe_options& operator=(subscribe_options const&) = default; + + explicit constexpr subscribe_options(std::uint8_t value) : data_(value) { } + + constexpr subscribe_options(retain_handling value) : data_(static_cast(value)) { } + constexpr subscribe_options(rap value) : data_(static_cast(value)) { } + constexpr subscribe_options(nl value) : data_(static_cast(value)) { } + constexpr subscribe_options(qos value) : data_(static_cast(value)) { } + + constexpr subscribe_options operator|(subscribe_options rhs) const { return subscribe_options(data_ | rhs.data_); } + constexpr subscribe_options operator|(retain_handling rhs) const { return *this | subscribe_options(rhs); } + constexpr subscribe_options operator|(rap rhs) const { return *this | subscribe_options(rhs); } + constexpr subscribe_options operator|(nl rhs) const { return *this | subscribe_options(rhs); } + constexpr subscribe_options operator|(qos rhs) const { return *this | subscribe_options(rhs); } + + constexpr subscribe_options& operator|=(subscribe_options rhs) { return (*this = (*this | rhs)); } + constexpr subscribe_options& operator|=(retain_handling rhs) { return (*this = (*this | rhs)); } + constexpr subscribe_options& operator|=(rap rhs) { return (*this = (*this | rhs)); } + constexpr subscribe_options& operator|=(nl rhs) { return (*this = (*this | rhs)); } + constexpr subscribe_options& operator|=(qos rhs) { return (*this = (*this | rhs)); } + + constexpr retain_handling get_retain_handling() const + { return static_cast(data_ & 0b00110000); } + constexpr rap get_rap() const + { return static_cast(data_ & 0b00001000); } + constexpr nl get_nl() const + { return static_cast(data_ & 0b00000100); } + constexpr qos get_qos() const + { return static_cast(data_ & 0b00000011); } + + explicit constexpr operator std::uint8_t() const { return data_; } +private: + std::uint8_t data_; +}; + +constexpr subscribe_options operator|(retain_handling lhs, rap rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(retain_handling lhs, nl rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(retain_handling lhs, qos rhs) { return subscribe_options(lhs) | rhs; } + +constexpr subscribe_options operator|(rap lhs, retain_handling rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(rap lhs, nl rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(rap lhs, qos rhs) { return subscribe_options(lhs) | rhs; } + +constexpr subscribe_options operator|(nl lhs, retain_handling rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(nl lhs, rap rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(nl lhs, qos rhs) { return subscribe_options(lhs) | rhs; } + +constexpr subscribe_options operator|(qos lhs, retain_handling rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(qos lhs, rap rhs) { return subscribe_options(lhs) | rhs; } +constexpr subscribe_options operator|(qos lhs, nl rhs) { return subscribe_options(lhs) | rhs; } + +constexpr char const* retain_handling_to_str(retain_handling v) { + switch(v) { + case retain_handling::send: return "send"; + case retain_handling::send_only_new_subscription: return "send_only_new_subscription"; + case retain_handling::not_send: return "not_send"; + default: return "invalid_retain_handling"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, retain_handling val) +{ + os << retain_handling_to_str(val); + return os; +} + +constexpr char const* rap_to_str(rap v) { + switch(v) { + case rap::dont: return "dont"; + case rap::retain: return "retain"; + default: return "invalid_rap"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, rap val) +{ + os << rap_to_str(val); + return os; +} + +constexpr char const* nl_to_str(nl v) { + switch(v) { + case nl::no: return "no"; + case nl::yes: return "yes"; + default: return "invalid_nl"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, nl val) +{ + os << nl_to_str(val); + return os; +} + +constexpr char const* qos_to_str(qos v) { + switch(v) { + case qos::at_most_once: return "at_most_once"; + case qos::at_least_once: return "at_least_once"; + case qos::exactly_once: return "exactly_once"; + default: return "invalid_qos"; + } +} + +inline +std::ostream& operator<<(std::ostream& os, qos val) +{ + os << qos_to_str(val); + return os; +} + +} // namespace MQTT_NS + +#endif // MQTT_SUBSCRIBE_OPTIONS_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/sync_client.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/sync_client.hpp new file mode 100644 index 000000000..fe7768116 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/sync_client.hpp @@ -0,0 +1,1236 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_SYNC_CLIENT_HPP) +#define MQTT_SYNC_CLIENT_HPP + +#include +#include +#include +#include + +namespace MQTT_NS { + +template +class sync_client : public client { + using this_type = sync_client; + using base = client; + using constructor_access = typename base::constructor_access; +public: + + /** + * Constructor used by factory functions at the end of this file. + */ + template + explicit sync_client(constructor_access, Args && ... args) + : sync_client(std::forward(args)...) + { } + + /** + * @brief Create no tls sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > + make_sync_client(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create no tls sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > + make_sync_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object. + * strand is controlled by ws_endpoint, not endpoint, so sync_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > + make_sync_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > + make_sync_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + /** + * @brief Create tls sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > + make_tls_sync_client(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create tls sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > + make_tls_sync_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object. + * strand is controlled by ws_endpoint, not endpoint, so sync_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + strand + > + > + > + > + make_tls_sync_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > + make_tls_sync_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) +#endif // defined(MQTT_USE_TLS) + + /** + * @brief Create no tls sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > + make_sync_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create no tls sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > + make_sync_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object. + * strand is controlled by ws_endpoint, not endpoint, so sync_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > + make_sync_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > + make_sync_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + /** + * @brief Create tls sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > + make_tls_sync_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + + /** + * @brief Create tls sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > + make_tls_sync_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version); + +#if defined(MQTT_USE_WS) + /** + * @brief Create no tls websocket sync_client with strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object. + * strand is controlled by ws_endpoint, not endpoint, so sync_client has null_strand template argument. + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > + make_tls_sync_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); + + /** + * @brief Create no tls websocket sync_client without strand. + * @param ioc io_context object. + * @param host hostname + * @param port port number + * @param path path string + * @return sync_client object + */ + friend std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > + make_tls_sync_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path, protocol_version version); +#endif // defined(MQTT_USE_WS) +#endif // defined(MQTT_USE_TLS) + + /** + * @brief Set auto publish response mode. + * @param b set value + * @param sync auto publish ressponse send synchronous + * + * When set auto publish response mode to true, puback, pubrec, pubrel,and pub comp automatically send.
+ */ + void set_auto_pub_response(bool b = true) { + base::set_auto_pub_response(b); + } + + void async_connect() = delete; + void async_disconnect() = delete; + void async_force_disconnect() = delete; + + void async_publish() = delete; + void async_subscribe() = delete; + void async_unsubscribe() = delete; + void async_pingresp() = delete; + void async_connack() = delete; + void async_puback() = delete; + void async_pubrec() = delete; + void async_pubrel() = delete; + void async_pubcomp() = delete; + void async_suback() = delete; + void async_unsuback() = delete; + +protected: + // Ensure that only code that knows the *exact* type of an object + // inheriting from this abstract base class can destruct it. + // This avoids issues of the destructor not triggering destruction + // of derived classes, and any member variables contained in them. + // Note: Not virtual to avoid need for a vtable when possible. + ~sync_client() = default; + + sync_client( + as::io_context& ioc, + std::string host, + std::string port +#if defined(MQTT_USE_WS) + , + std::string path = "/" +#endif // defined(MQTT_USE_WS) + , + protocol_version version = protocol_version::v3_1_1 + ):base(ioc, force_move(host), force_move(port) +#if defined(MQTT_USE_WS) + , force_move(path) +#endif // defined(MQTT_USE_WS) + , + version + ) { + set_auto_pub_response(); + } +}; + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_sync_client(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_sync_client(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_sync_client( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_sync_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >>; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_sync_client_no_strand(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_sync_client_no_strand( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_sync_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + > + > + > + > +make_sync_client_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_sync_client_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_sync_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + > + > + > + > +make_sync_client_no_strand_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_sync_client_no_strand_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_sync_client(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + tls::stream, + strand + > + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_sync_client(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_sync_client_no_strand(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + tls::stream, + null_strand + > + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_sync_client_no_strand(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client_no_strand( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_sync_client_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + tls::stream, + strand + > + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + strand + > + > + > + > +make_tls_sync_client_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_sync_client_no_strand_ws(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + tls::stream, + null_strand + > + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + null_strand + > + > + > + > +make_tls_sync_client_no_strand_ws(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client_no_strand_ws( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + +// 32bit Packet Id (experimental) + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_sync_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_sync_client_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_sync_client_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_sync_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_sync_client_no_strand_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_sync_client_no_strand_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_sync_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + strand + >, + 4 + > + > + > +make_sync_client_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_sync_client_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_sync_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + as::ip::tcp::socket, + null_strand + >, + 4 + > + > + > +make_sync_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_sync_client_no_strand_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#if defined(MQTT_USE_TLS) + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_sync_client_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_sync_client_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_sync_client_no_strand_32(as::io_context& ioc, std::string host, std::string port, protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), +#if defined(MQTT_USE_WS) + "/", +#endif // defined(MQTT_USE_WS) + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + tcp_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_sync_client_no_strand_32(as::io_context& ioc, std::string host, std::uint16_t port, protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client_no_strand_32( + ioc, + force_move(host), + std::to_string(port), + version + ); +} + +#if defined(MQTT_USE_WS) + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_sync_client_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + strand + >, + 4 + > + > + > +make_tls_sync_client_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_sync_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::string port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + using sync_client_t = sync_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + >; + return std::make_shared>( + sync_client_t::constructor_access(), + ioc, + force_move(host), + force_move(port), + force_move(path), + version + ); +} + +inline std::shared_ptr< + callable_overlay< + sync_client< + ws_endpoint< + tls::stream, + null_strand + >, + 4 + > + > + > +make_tls_sync_client_no_strand_ws_32(as::io_context& ioc, std::string host, std::uint16_t port, std::string path = "/", protocol_version version = protocol_version::v3_1_1) { + return make_tls_sync_client_no_strand_ws_32( + ioc, + force_move(host), + std::to_string(port), + force_move(path), + version + ); +} + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + +} // namespace MQTT_NS + +#endif // MQTT_SYNC_CLIENT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/tcp_endpoint.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/tcp_endpoint.hpp new file mode 100644 index 000000000..774181b02 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/tcp_endpoint.hpp @@ -0,0 +1,212 @@ +// Copyright Takatoshi Kondo 2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TCP_ENDPOINT_HPP) +#define MQTT_TCP_ENDPOINT_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +template +class tcp_endpoint : public socket { +public: + template + explicit tcp_endpoint(as::io_context& ioc, Args&&... args) + :tcp_(ioc, std::forward(args)...), +#if defined(MQTT_NO_TS_EXECUTORS) + strand_(ioc.get_executor()) +#else + strand_(ioc) +#endif + {} + + MQTT_ALWAYS_INLINE void async_read( + as::mutable_buffer buffers, + std::function handler + ) override final { + as::async_read( + tcp_, + force_move(buffers), + as::bind_executor( + strand_, + force_move(handler) + ) + ); + } + + MQTT_ALWAYS_INLINE void async_write( + std::vector buffers, + std::function handler + ) override final { + as::async_write( + tcp_, + force_move(buffers), + as::bind_executor( + strand_, + force_move(handler) + ) + ); + } + + MQTT_ALWAYS_INLINE std::size_t write( + std::vector buffers, + boost::system::error_code& ec + ) override final { + return as::write(tcp_,force_move(buffers), ec); + } + + MQTT_ALWAYS_INLINE void post(std::function handler) override final { + as::post( + strand_, + force_move(handler) + ); + } + + MQTT_ALWAYS_INLINE void dispatch(std::function handler) override final { + as::dispatch( + strand_, + force_move(handler) + ); + } + + MQTT_ALWAYS_INLINE void defer(std::function handler) override final { + as::defer( + strand_, + force_move(handler) + ); + } + + MQTT_ALWAYS_INLINE bool running_in_this_thread() const override final { + return strand_.running_in_this_thread(); + } + + MQTT_ALWAYS_INLINE as::ip::tcp::socket::lowest_layer_type& lowest_layer() override final { + return tcp_.lowest_layer(); + } + + MQTT_ALWAYS_INLINE any native_handle() override final { + return tcp_.native_handle(); + } + + MQTT_ALWAYS_INLINE void clean_shutdown_and_close(boost::system::error_code& ec) override final { + shutdown_and_close_impl(tcp_, ec); + } + + MQTT_ALWAYS_INLINE void async_clean_shutdown_and_close(std::function handler) override final { + async_shutdown_and_close_impl(tcp_, force_move(handler)); + } + + MQTT_ALWAYS_INLINE void force_shutdown_and_close(boost::system::error_code& ec) override final { + tcp_.lowest_layer().shutdown(as::ip::tcp::socket::shutdown_both, ec); + tcp_.lowest_layer().close(ec); + } + +#if BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + MQTT_ALWAYS_INLINE as::executor get_executor() override final { + return lowest_layer().get_executor(); + } +#else // BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + MQTT_ALWAYS_INLINE as::any_io_executor get_executor() override final { + return lowest_layer().get_executor(); + } +#endif // BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + + auto& socket() { return tcp_; } + auto const& socket() const { return tcp_; } + + template + void set_option(Args&& ... args) { + tcp_.set_option(std::forward(args)...); + } + + template + void async_accept(Args&& ... args) { + tcp_.async_accept(std::forward(args)...); + } + +#if defined(MQTT_USE_TLS) + + template + void handshake(Args&& ... args) { + tcp_.handshake(std::forward(args)...); + } + + template + void async_handshake(Args&& ... args) { + tcp_.async_handshake(std::forward(args)...); + } + +#endif // defined(MQTT_USE_TLS) + +private: + void shutdown_and_close_impl(as::basic_socket& s, boost::system::error_code& ec) { + s.shutdown(as::ip::tcp::socket::shutdown_both, ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "shutdown ec:" + << ec.message(); + s.close(ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "close ec:" + << ec.message(); + } + + void async_shutdown_and_close_impl(as::basic_socket& s, std::function handler) { + post( + [this, &s, handler = force_move(handler)] () mutable { + error_code ec; + shutdown_and_close_impl(s, ec); + force_move(handler)(ec); + } + ); + } + +#if defined(MQTT_USE_TLS) + void shutdown_and_close_impl(tls::stream& s, boost::system::error_code& ec) { + s.shutdown(ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "shutdown ec:" + << ec.message(); + shutdown_and_close_impl(lowest_layer(), ec); + } + void async_shutdown_and_close_impl(tls::stream& s, std::function handler) { + s.async_shutdown( + as::bind_executor( + strand_, + [this, &s, handler = force_move(handler)] (error_code ec) mutable { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "shutdown ec:" + << ec.message(); + shutdown_and_close_impl(s.lowest_layer(), ec); + force_move(handler)(ec); + } + ) + ); + } +#endif // defined(MQTT_USE_TLS) + +private: + Socket tcp_; + Strand strand_; +}; + +} // namespace MQTT_NS + +#endif // MQTT_TCP_ENDPOINT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/time_point_t.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/time_point_t.hpp new file mode 100644 index 000000000..88dca437e --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/time_point_t.hpp @@ -0,0 +1,20 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TIME_POINT_T_HPP) +#define MQTT_TIME_POINT_T_HPP + +#include + +#include + +namespace MQTT_NS { + +using time_point_t = std::chrono::time_point; + +} // namespace MQTT_NS + +#endif // MQTT_TIME_POINT_T_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/tls.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/tls.hpp new file mode 100644 index 000000000..c9480d98f --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/tls.hpp @@ -0,0 +1,42 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TLS_HPP) +#define MQTT_TLS_HPP + +#if defined(MQTT_USE_TLS) + +#if !defined(MQTT_TLS_INCLUDE) +#define MQTT_TLS_INCLUDE +#endif // !defined(MQTT_TLS_INCLUDE) + +#include MQTT_TLS_INCLUDE + +#if !defined(MQTT_TLS_NS) +#define MQTT_TLS_NS boost::asio::ssl +#endif // !defined(MQTT_TLS_NS) + +#include + +namespace MQTT_NS { +namespace tls = MQTT_TLS_NS; +} // namespace MQTT_NS + + +#if defined(MQTT_USE_WS) + +#if !defined(MQTT_TLS_WS_INCLUDE) +#define MQTT_TLS_WS_INCLUDE +#endif // !defined(MQTT_TLS_WS_INCLUDE) + +#include MQTT_TLS_WS_INCLUDE + +#endif // defined(MQTT_USE_WS) + +#endif // defined(MQTT_USE_TLS) + + +#endif // MQTT_TLS_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/topic_alias_recv.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/topic_alias_recv.hpp new file mode 100644 index 000000000..d0fb41ac2 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/topic_alias_recv.hpp @@ -0,0 +1,106 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TOPIC_ALIAS_RECV_HPP) +#define MQTT_TOPIC_ALIAS_RECV_HPP + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace mi = boost::multi_index; + +class topic_alias_recv { +public: + topic_alias_recv(topic_alias_t max) + :max_{max} {} + + void insert_or_update(string_view topic, topic_alias_t alias) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "topic_alias_recv insert" + << " topic:" << topic + << " alias:" << alias; + BOOST_ASSERT(!topic.empty() && alias >= min_ && alias <= max_); + auto it = aliases_.lower_bound(alias); + if (it == aliases_.end() || it->alias != alias) { + aliases_.emplace_hint(it, std::string(topic), alias); + } + else { + aliases_.modify( + it, + [&](entry& e) { + e.topic = std::string{topic}; + }, + [](auto&) { BOOST_ASSERT(false); } + ); + + } + } + + std::string find(topic_alias_t alias) const { + BOOST_ASSERT(alias >= min_ && alias <= max_); + std::string topic; + auto it = aliases_.find(alias); + if (it != aliases_.end()) topic = it->topic; + + MQTT_LOG("mqtt_impl", info) + << MQTT_ADD_VALUE(address, this) + << "find_topic_by_alias" + << " alias:" << alias + << " topic:" << topic; + + return topic; + } + + void clear() { + MQTT_LOG("mqtt_impl", info) + << MQTT_ADD_VALUE(address, this) + << "clear_topic_alias"; + aliases_.clear(); + } + + topic_alias_t max() const { return max_; } + +private: + static constexpr topic_alias_t min_ = 1; + topic_alias_t max_; + + struct entry { + entry(std::string topic, topic_alias_t alias) + : topic{force_move(topic)}, alias{alias} {} + + std::string topic; + topic_alias_t alias; + }; + using mi_topic_alias = mi::multi_index_container< + entry, + mi::indexed_by< + mi::ordered_unique< + BOOST_MULTI_INDEX_MEMBER(entry, topic_alias_t, alias) + > + > + >; + + mi_topic_alias aliases_; +}; + +} // namespace MQTT_NS + +#endif // MQTT_TOPIC_ALIAS_RECV_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/topic_alias_send.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/topic_alias_send.hpp new file mode 100644 index 000000000..42ac0a720 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/topic_alias_send.hpp @@ -0,0 +1,159 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TOPIC_ALIAS_SEND_HPP) +#define MQTT_TOPIC_ALIAS_SEND_HPP + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace mi = boost::multi_index; + +class topic_alias_send { +public: + topic_alias_send(topic_alias_t max) + :max_{max}, va_{min_, max_} {} + + void insert_or_update(string_view topic, topic_alias_t alias) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "topic_alias_send insert" + << " topic:" << topic + << " alias:" << alias; + BOOST_ASSERT(!topic.empty() && alias >= min_ && alias <= max_); + va_.use(alias); + auto& idx = aliases_.get(); + auto it = idx.lower_bound(alias); + if (it == idx.end() || it->alias != alias) { + idx.emplace_hint(it, std::string(topic), alias, std::chrono::steady_clock::now()); + } + else { + idx.modify( + it, + [&](entry& e) { + e.topic = std::string{topic}; + e.tp = std::chrono::steady_clock::now(); + }, + [](auto&) { BOOST_ASSERT(false); } + ); + + } + } + + std::string find(topic_alias_t alias) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "find_topic_by_alias" + << " alias:" << alias; + + BOOST_ASSERT(alias >= min_ && alias <= max_); + auto& idx = aliases_.get(); + auto it = idx.find(alias); + if (it == idx.end()) return std::string(); + + idx.modify( + it, + [&](entry& e) { + e.tp = std::chrono::steady_clock::now(); + }, + [](auto&) { BOOST_ASSERT(false); } + ); + return it->topic; + } + + optional find(string_view topic) const { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "find_alias_by_topic" + << " topic:" << topic; + + auto& idx = aliases_.get(); + auto it = idx.find(topic); + if (it == idx.end()) return nullopt; + return it->alias; + } + + void clear() { + MQTT_LOG("mqtt_impl", info) + << MQTT_ADD_VALUE(address, this) + << "clear_topic_alias"; + aliases_.clear(); + va_.clear(); + } + + topic_alias_t get_lru_alias() const { + BOOST_ASSERT(max_ > 0); + if (auto alias_opt = va_.first_vacant()) { + return alias_opt.value(); + } + auto& idx = aliases_.get(); + return idx.begin()->alias; + } + + topic_alias_t max() const { return max_; } + +private: + static constexpr topic_alias_t min_ = 1; + topic_alias_t max_; + + struct entry { + entry(std::string topic, topic_alias_t alias, time_point_t tp) + : topic{force_move(topic)}, alias{alias}, tp{force_move(tp)} {} + + string_view get_topic_as_view() const { + return topic; + } + + std::string topic; + topic_alias_t alias; + time_point_t tp; + }; + struct tag_tp {}; + struct tag_alias {}; + struct tag_topic_name {}; + using mi_topic_alias = mi::multi_index_container< + entry, + mi::indexed_by< + mi::ordered_unique< + mi::tag, + BOOST_MULTI_INDEX_MEMBER(entry, topic_alias_t, alias) + >, + mi::ordered_unique< + mi::tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(entry, string_view, get_topic_as_view) + >, + mi::ordered_non_unique< + mi::tag, + BOOST_MULTI_INDEX_MEMBER(entry, time_point_t, tp) + > + > + >; + + mi_topic_alias aliases_; + value_allocator va_; +}; + +} // namespace MQTT_NS + +#endif // MQTT_TOPIC_ALIAS_SEND_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/two_byte_util.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/two_byte_util.hpp new file mode 100644 index 000000000..fefd51bb0 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/two_byte_util.hpp @@ -0,0 +1,48 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TWO_BYTE_UTIL_HPP) +#define MQTT_TWO_BYTE_UTIL_HPP + +#include +#include + +#include +#include + +#include + +namespace MQTT_NS { + +inline boost::container::static_vector num_to_2bytes(std::uint16_t val) { + return { + static_cast(val >> 8), + static_cast(val & 0xff) + }; +} + +template +inline void add_uint16_t_to_buf(T& buf, std::uint16_t num) { + buf.push_back(static_cast(num >> 8)); + buf.push_back(static_cast(num & 0xff)); +} + +template +constexpr std::uint16_t make_uint16_t(It b, It e) { + (void)e; // Avoid warning in release builds about unused variable + BOOST_ASSERT(std::distance(b, e) == 2); + auto b1 = b++; + auto b2 = b++; + return + static_cast( + (static_cast(*b1) & 0xff) << 8 | + (static_cast(*b2) & 0xff) + ); +} + +} // namespace MQTT_NS + +#endif // MQTT_TWO_BYTE_UTIL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/two_or_four_byte_util.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/two_or_four_byte_util.hpp new file mode 100644 index 000000000..e322592ff --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/two_or_four_byte_util.hpp @@ -0,0 +1,72 @@ +// Copyright Takatoshi Kondo 2021 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TWO_OR_FOUR_BYTE_UTIL_HPP) +#define MQTT_TWO_OR_FOUR_BYTE_UTIL_HPP + +#include +#include + +#include +#include +#include + +namespace MQTT_NS { + +template +struct two_or_four_byte_type; + +template <> +struct two_or_four_byte_type<2> { + using type = std::uint16_t; +}; + +template <> +struct two_or_four_byte_type<4> { + using type = std::uint32_t; +}; + +template +struct make_two_or_four_byte; + +template <> +struct make_two_or_four_byte<2> { + template + static constexpr std::uint16_t apply(It b, It e) { + return make_uint16_t(b, e); + } +}; + +template <> +struct make_two_or_four_byte<4> { + template + static constexpr std::uint32_t apply(It b, It e) { + return make_uint32_t(b, e); + } +}; + +template +struct add_two_or_four_byte_to_buf; + +template <> +struct add_two_or_four_byte_to_buf<2> { + template + static void apply(T& buf, std::uint16_t two_or_four_byte) { + add_uint16_t_to_buf(buf, two_or_four_byte); + } +}; + +template <> +struct add_two_or_four_byte_to_buf<4> { + template + static void apply(T& buf, std::uint32_t two_or_four_byte) { + add_uint32_t_to_buf(buf, two_or_four_byte); + } +}; + +} // namespace MQTT_NS + +#endif // MQTT_TWO_OR_FOUR_BYTE_UTIL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/type.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/type.hpp new file mode 100644 index 000000000..46dc017c5 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/type.hpp @@ -0,0 +1,22 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TYPE_HPP) +#define MQTT_TYPE_HPP + +#include + +#include + +namespace MQTT_NS { + +using session_expiry_interval_t = std::uint32_t; +using topic_alias_t = std::uint16_t; +using receive_maximum_t = std::uint16_t; + +} // namespace MQTT_NS + +#endif // MQTT_TYPE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/type_erased_socket.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/type_erased_socket.hpp new file mode 100644 index 000000000..d83335ce7 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/type_erased_socket.hpp @@ -0,0 +1,46 @@ +// Copyright Takatoshi Kondo 2019 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_TYPE_ERASED_SOCKET_HPP) +#define MQTT_TYPE_ERASED_SOCKET_HPP + +#include + +#include + +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +class socket { +public: + virtual ~socket() = default; + virtual void async_read(as::mutable_buffer, std::function) = 0; + virtual void async_write(std::vector, std::function) = 0; + virtual std::size_t write(std::vector, boost::system::error_code&) = 0; + virtual void post(std::function) = 0; + virtual void dispatch(std::function) = 0; + virtual void defer(std::function) = 0; + virtual bool running_in_this_thread() const = 0; + virtual as::ip::tcp::socket::lowest_layer_type& lowest_layer() = 0; + virtual any native_handle() = 0; + virtual void clean_shutdown_and_close(boost::system::error_code&) = 0; + virtual void async_clean_shutdown_and_close(std::function) = 0; + virtual void force_shutdown_and_close(boost::system::error_code&) = 0; +#if BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + virtual as::executor get_executor() = 0; +#else // BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + virtual as::any_io_executor get_executor() = 0; +#endif // BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) +}; + +} // namespace MQTT_NS + +#endif // MQTT_TYPE_ERASED_SOCKET_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/unique_scope_guard.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/unique_scope_guard.hpp new file mode 100644 index 000000000..549d66faa --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/unique_scope_guard.hpp @@ -0,0 +1,24 @@ +// Copyright Takatoshi Kondo 2022 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_UNIQUE_SCOPE_GUARD_HPP) +#define MQTT_UNIQUE_SCOPE_GUARD_HPP + +#include +#include +#include + +namespace MQTT_NS { + +template +inline auto unique_scope_guard(Proc&& proc) { + auto deleter = [proc = std::forward(proc)](void*) mutable { std::forward(proc)(); }; + return std::unique_ptr(&deleter, force_move(deleter)); +} + +} // namespace MQTT_NS + +#endif // MQTT_UNIQUE_SCOPE_GUARD_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/utf8encoded_strings.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/utf8encoded_strings.hpp new file mode 100644 index 000000000..c62bca4bc --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/utf8encoded_strings.hpp @@ -0,0 +1,149 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_UTF8ENCODED_STRINGS_HPP) +#define MQTT_UTF8ENCODED_STRINGS_HPP + +#include +#include + +namespace MQTT_NS { + +namespace utf8string { + +enum struct validation +{ + /** + * @brief UTF-8 string is well_formed. + * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718016 + * 1.5.3 UTF-8 encoded strings + */ + well_formed = 0, + + /** + * @brief UTF-8 string is ill_formed or contains null character. + * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718016 + * 1.5.3 UTF-8 encoded strings + */ + ill_formed, + + /** + * @brief UTF-8 string is well_formed and contains control character and non-character. + * See http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718016 + * 1.5.3 UTF-8 encoded strings + */ + well_formed_with_non_charactor, +}; + +constexpr bool +is_valid_length(string_view str) { + return str.size() <= 0xffff; +} + +constexpr validation +validate_contents(string_view str) { + // This code is based on https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c + auto result = validation::well_formed; +#if defined(MQTT_USE_STR_CHECK) + auto it = str.begin(); + auto end = str.end(); + + while (it != end) { + if (static_cast(*(it + 0)) < 0b1000'0000) { + // 0xxxxxxxxx + if (static_cast(*(it + 0)) == 0x00) { + result = validation::ill_formed; + break; + } + if ((static_cast(*(it + 0)) >= 0x01 && + static_cast(*(it + 0)) <= 0x1f) || + static_cast(*(it + 0)) == 0x7f) { + result = validation::well_formed_with_non_charactor; + } + ++it; + } + else if ((static_cast(*(it + 0)) & 0b1110'0000) == 0b1100'0000) { + // 110XXXXx 10xxxxxx + if (it + 1 >= end) { + result = validation::ill_formed; + break; + } + if ((static_cast(*(it + 1)) & 0b1100'0000) != 0b1000'0000 || + (static_cast(*(it + 0)) & 0b1111'1110) == 0b1100'0000) { // overlong + result = validation::ill_formed; + break; + } + if (static_cast(*(it + 0)) == 0b1100'0010 && + static_cast(*(it + 1)) >= 0b1000'0000 && + static_cast(*(it + 1)) <= 0b1001'1111) { + result = validation::well_formed_with_non_charactor; + } + it += 2; + } + else if ((static_cast(*(it + 0)) & 0b1111'0000) == 0b1110'0000) { + // 1110XXXX 10Xxxxxx 10xxxxxx + if (it + 2 >= end) { + result = validation::ill_formed; + break; + } + if ((static_cast(*(it + 1)) & 0b1100'0000) != 0b1000'0000 || + (static_cast(*(it + 2)) & 0b1100'0000) != 0b1000'0000 || + (static_cast(*(it + 0)) == 0b1110'0000 && + (static_cast(*(it + 1)) & 0b1110'0000) == 0b1000'0000) || // overlong? + (static_cast(*(it + 0)) == 0b1110'1101 && + (static_cast(*(it + 1)) & 0b1110'0000) == 0b1010'0000)) { // surrogate? + result = validation::ill_formed; + break; + } + if (static_cast(*(it + 0)) == 0b1110'1111 && + static_cast(*(it + 1)) == 0b1011'1111 && + (static_cast(*(it + 2)) & 0b1111'1110) == 0b1011'1110) { + // U+FFFE or U+FFFF? + result = validation::well_formed_with_non_charactor; + } + it += 3; + } + else if ((static_cast(*(it + 0)) & 0b1111'1000) == 0b1111'0000) { + // 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx + if (it + 3 >= end) { + result = validation::ill_formed; + break; + } + if ((static_cast(*(it + 1)) & 0b1100'0000) != 0b1000'0000 || + (static_cast(*(it + 2)) & 0b1100'0000) != 0b1000'0000 || + (static_cast(*(it + 3)) & 0b1100'0000) != 0b1000'0000 || + (static_cast(*(it + 0)) == 0b1111'0000 && + (static_cast(*(it + 1)) & 0b1111'0000) == 0b1000'0000) || // overlong? + (static_cast(*(it + 0)) == 0b1111'0100 && + static_cast(*(it + 1)) > 0b1000'1111) || + static_cast(*(it + 0)) > 0b1111'0100) { // > U+10FFFF? + result = validation::ill_formed; + break; + } + if ((static_cast(*(it + 1)) & 0b1100'1111) == 0b1000'1111 && + static_cast(*(it + 2)) == 0b1011'1111 && + (static_cast(*(it + 3)) & 0b1111'1110) == 0b1011'1110) { + // U+nFFFE or U+nFFFF? + result = validation::well_formed_with_non_charactor; + } + it += 4; + } + else { + result = validation::ill_formed; + break; + } + } +#else // MQTT_USE_STR_CHECK + static_cast(str); +#endif // MQTT_USE_STR_CHECK + return result; +} + +} // namespace utf8string + +} // namespace MQTT_NS + +#endif // MQTT_UTF8ENCODED_STRINGS_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/v5_message.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/v5_message.hpp new file mode 100644 index 000000000..e90bee051 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/v5_message.hpp @@ -0,0 +1,2939 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_V5_MESSAGE_HPP) +#define MQTT_V5_MESSAGE_HPP + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(MQTT_ALWAYS_SEND_REASON_CODE) +#define MQTT_ALWAYS_SEND_REASON_CODE false +#endif // !defined(MQTT_ALWAYS_SEND_REASON_CODE) + +namespace MQTT_NS { + +namespace as = boost::asio; + +namespace v5 { + +namespace detail { + +class header_only_message { +public: + /** + * @brief Create empty header_packet_id_message. + */ + header_only_message(control_packet_type type, std::uint8_t flags) + : message_ { static_cast(make_fixed_header(type, flags)), 0 } + {} + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + return { as::buffer(message_.data(), message_.size()) }; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return message_.size(); + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + static constexpr std::size_t num_of_const_buffer_sequence() { + return 1; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + return std::string(message_.data(), message_.size()); + } +private: + boost::container::static_vector message_; +}; + +} // namespace detail + +class connect_message { +public: + connect_message( + std::uint16_t keep_alive_sec, + buffer client_id, + bool clean_start, + optional w, + optional user_name, + optional password, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::connect, 0b0000)), + connect_flags_(0), + // protocol name length, protocol name, protocol level, connect flag, client id length, client id, keep alive + remaining_length_( + 2 + // protocol name length + 4 + // protocol name + 1 + // protocol level + 1 + // connect flag + 2 + // keep alive + 2 + // client id length + client_id.size() // client id + ), + protocol_name_and_level_ { 0x00, 0x04, 'M', 'Q', 'T', 'T', 0x05 }, + client_id_(force_move(client_id)), + client_id_length_buf_{ num_to_2bytes(boost::numeric_cast(client_id_.size())) }, + will_property_length_( + w ? + std::accumulate( + w.value().props().begin(), + w.value().props().end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + : 0U + ), + will_props_( + w ? + force_move(w.value().props()) + : properties() + ), + keep_alive_buf_ ({ num_to_2bytes(keep_alive_sec ) }), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // protocol name and level + 1 + // connect flags + 1 + // keep alive + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + + 2 // client id length, client id + ) + { + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ += property_length_buf_.size() + property_length_; + + utf8string_check(client_id_); + if (clean_start) connect_flags_ |= connect_flags::clean_start; + if (user_name) { + utf8string_check(user_name.value()); + connect_flags_ |= connect_flags::user_name_flag; + user_name_ = force_move(user_name.value()); + add_uint16_t_to_buf(user_name_length_buf_, boost::numeric_cast(user_name_.size())); + + remaining_length_ += 2 + user_name_.size(); + num_of_const_buffer_sequence_ += 2; // user name length, user name + } + if (password) { + connect_flags_ |= connect_flags::password_flag; + password_ = force_move(password.value()); + add_uint16_t_to_buf(password_length_buf_, boost::numeric_cast(password_.size())); + + remaining_length_ += 2 + password_.size(); + num_of_const_buffer_sequence_ += 2; // password length, password + } + if (w) { + connect_flags_ |= connect_flags::will_flag; + if (w.value().get_retain() == retain::yes) connect_flags_ |= connect_flags::will_retain; + connect_flags::set_will_qos(connect_flags_, w.value().get_qos()); + + auto wpb = variable_bytes(will_property_length_); + for (auto e : wpb) { + will_property_length_buf_.push_back(e); + } + + utf8string_check(w.value().topic()); + will_topic_name_ = force_move(w.value().topic()); + add_uint16_t_to_buf( + will_topic_name_length_buf_, + boost::numeric_cast(will_topic_name_.size()) + ); + if (w.value().message().size() > 0xffffL) throw will_message_length_error(); + will_message_ = force_move(w.value().message()); + add_uint16_t_to_buf( + will_message_length_buf_, + boost::numeric_cast(will_message_.size())); + + remaining_length_ += + will_property_length_buf_.size() + + will_property_length_ + + 2 + will_topic_name_.size() + 2 + will_message_.size(); + num_of_const_buffer_sequence_ += + std::accumulate( + will_props_.begin(), + will_props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + + 2 + // will topic name length, will topic name + 2; // will message length, will message + + } + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(protocol_name_and_level_.data(), protocol_name_and_level_.size())); + ret.emplace_back(as::buffer(&connect_flags_, 1)); + ret.emplace_back(as::buffer(keep_alive_buf_.data(), keep_alive_buf_.size())); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + + ret.emplace_back(as::buffer(client_id_length_buf_.data(), client_id_length_buf_.size())); + ret.emplace_back(as::buffer(client_id_)); + + if (connect_flags::has_will_flag(connect_flags_)) { + ret.emplace_back(as::buffer(will_property_length_buf_.data(), will_property_length_buf_.size())); + for (auto const& p : will_props_) { + v5::add_const_buffer_sequence(ret, p); + } + ret.emplace_back(as::buffer(will_topic_name_length_buf_.data(), will_topic_name_length_buf_.size())); + ret.emplace_back(as::buffer(will_topic_name_)); + ret.emplace_back(as::buffer(will_message_length_buf_.data(), will_message_length_buf_.size())); + ret.emplace_back(as::buffer(will_message_)); + } + + if (connect_flags::has_user_name_flag(connect_flags_)) { + ret.emplace_back(as::buffer(user_name_length_buf_.data(), user_name_length_buf_.size())); + ret.emplace_back(as::buffer(user_name_)); + } + + if (connect_flags::has_password_flag(connect_flags_)) { + ret.emplace_back(as::buffer(password_length_buf_.data(), password_length_buf_.size())); + ret.emplace_back(as::buffer(password_)); + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + ret.append(protocol_name_and_level_.data(), protocol_name_and_level_.size()); + ret.push_back(connect_flags_); + ret.append(keep_alive_buf_.data(), keep_alive_buf_.size()); + + ret.append(property_length_buf_.data(), property_length_buf_.size()); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + + ret.append(client_id_length_buf_.data(), client_id_length_buf_.size()); + ret.append(client_id_.data(), client_id_.size()); + + if (connect_flags::has_will_flag(connect_flags_)) { + ret.append(will_property_length_buf_.data(), will_property_length_buf_.size()); + auto it = ret.end(); + ret.resize(ret.size() + will_property_length_); + auto end = ret.end(); + for (auto const& p : will_props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + ret.append(will_topic_name_length_buf_.data(), will_topic_name_length_buf_.size()); + ret.append(will_topic_name_.data(), will_topic_name_.size()); + ret.append(will_message_length_buf_.data(), will_message_length_buf_.size()); + ret.append(will_message_.data(), will_message_.size()); + } + + if (connect_flags::has_user_name_flag(connect_flags_)) { + ret.append(user_name_length_buf_.data(), user_name_length_buf_.size()); + ret.append(user_name_.data(), user_name_.size()); + } + + if (connect_flags::has_password_flag(connect_flags_)) { + ret.append(password_length_buf_.data(), password_length_buf_.size()); + ret.append(password_.data(), password_.size()); + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + char connect_flags_; + + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + + boost::container::static_vector protocol_name_and_level_; + buffer client_id_; + boost::container::static_vector client_id_length_buf_; + + std::size_t will_property_length_; + boost::container::static_vector will_property_length_buf_; + properties will_props_; + + buffer will_topic_name_; + boost::container::static_vector will_topic_name_length_buf_; + buffer will_message_; + boost::container::static_vector will_message_length_buf_; + + buffer user_name_; + boost::container::static_vector user_name_length_buf_; + buffer password_; + boost::container::static_vector password_length_buf_; + + boost::container::static_vector keep_alive_buf_; + + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + + std::size_t num_of_const_buffer_sequence_; +}; + +class connack_message { +public: + connack_message( + bool session_present, + connect_reason_code reason_code, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::connack, 0b0000)), + remaining_length_( + 1 + // connect acknowledge flags + 1 // reason code + ), + connect_acknowledge_flags_(session_present ? 1 : 0), + reason_code_(reason_code), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // connect acknowledge flags + 1 + // reason code + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + ) + { + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ += property_length_buf_.size() + property_length_; + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(&connect_acknowledge_flags_, 1)); + ret.emplace_back(as::buffer(&reason_code_, 1)); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + ret.push_back(static_cast(connect_acknowledge_flags_)); + ret.push_back(static_cast(reason_code_)); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + + std::uint8_t connect_acknowledge_flags_; + + connect_reason_code reason_code_; + + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + + std::size_t num_of_const_buffer_sequence_; +}; + +template +class basic_publish_message { +public: + template < + typename ConstBufferSequence, + typename std::enable_if< + as::is_const_buffer_sequence::value, + std::nullptr_t + >::type = nullptr + > + basic_publish_message( + typename packet_id_type::type packet_id, + as::const_buffer topic_name, + ConstBufferSequence payloads, + publish_options pubopts, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::publish, 0b0000) | pubopts.operator std::uint8_t()), + topic_name_(topic_name), + topic_name_length_buf_ { num_to_2bytes(boost::numeric_cast(topic_name_.size())) }, + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + remaining_length_( + 2 // topic name length + + topic_name_.size() // topic name + + ( (pubopts.get_qos() == qos::at_least_once || pubopts.get_qos() == qos::exactly_once) + ? PacketIdBytes // packet_id + : 0) + ), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // topic name length + 1 + // topic name + ((pubopts.get_qos() == qos::at_most_once) ? 0U : 1U) + // packet id + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + ) + { + auto b = as::buffer_sequence_begin(payloads); + auto e = as::buffer_sequence_end(payloads); + auto num_of_payloads = static_cast(std::distance(b, e)); + payloads_.reserve(num_of_payloads); + for (; b != e; ++b) { + auto const& payload = *b; + remaining_length_ += payload.size(); + payloads_.push_back(payload); + } + num_of_const_buffer_sequence_ += num_of_payloads; + + utf8string_check(topic_name_); + + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ += property_length_buf_.size() + property_length_; + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + if (pubopts.get_qos() == qos::at_least_once || + pubopts.get_qos() == qos::exactly_once) { + packet_id_.reserve(PacketIdBytes); + add_packet_id_to_buf::apply(packet_id_, packet_id); + } + } + + basic_publish_message(buffer buf) { + if (buf.empty()) throw remaining_length_error(); + fixed_header_ = static_cast(buf.front()); + qos qos_value = get_qos(); + buf.remove_prefix(1); + + if (buf.empty()) throw remaining_length_error(); + auto len_consumed = remaining_length(buf.begin(), buf.end()); + remaining_length_ = std::get<0>(len_consumed); + auto consumed = std::get<1>(len_consumed); + + std::copy( + buf.begin(), + std::next(buf.begin(), static_cast(consumed)), + std::back_inserter(remaining_length_buf_)); + buf.remove_prefix(consumed); + + if (buf.size() < 2) throw remaining_length_error(); + std::copy(buf.begin(), std::next(buf.begin(), 2), std::back_inserter(topic_name_length_buf_)); + auto topic_name_length = make_uint16_t(buf.begin(), std::next(buf.begin(), 2)); + buf.remove_prefix(2); + + if (buf.size() < topic_name_length) throw remaining_length_error(); + + topic_name_ = as::buffer(buf.substr(0, topic_name_length)); + utf8string_check(topic_name_); + buf.remove_prefix(topic_name_length); + + switch (qos_value) { + case qos::at_most_once: + break; + case qos::at_least_once: + case qos::exactly_once: + if (buf.size() < PacketIdBytes) throw remaining_length_error(); + std::copy(buf.begin(), std::next(buf.begin(), PacketIdBytes), std::back_inserter(packet_id_)); + buf.remove_prefix(PacketIdBytes); + break; + default: + throw protocol_error(); + break; + }; + + auto len_consume = variable_length( + buf.begin(), + buf.end() + ); + property_length_ = std::get<0>(len_consume); + auto consume = std::get<1>(len_consume); + if (consume == 0) throw property_length_error(); + std::copy( + buf.begin(), + std::next(buf.begin(), static_cast(consume)), + std::back_inserter(property_length_buf_) + ); + buf.remove_prefix(consume); + if (buf.size() < property_length_) throw property_length_error(); + + props_ = property::parse(buf.substr(0, property_length_)); + buf.remove_prefix(property_length_); + if (!buf.empty()) { + payloads_.emplace_back(as::buffer(buf)); + } + num_of_const_buffer_sequence_ = + 1 + // fixed header + 1 + // remaining length + 1 + // topic name length + 1 + // topic name + ((qos_value == qos::at_most_once) ? 0U : 1U) + // packet id + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + + payloads_.size(); // payload + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(topic_name_length_buf_.data(), topic_name_length_buf_.size()); + ret.emplace_back(as::buffer(topic_name_)); + + if (!packet_id_.empty()) { + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + } + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + + std::copy(payloads_.begin(), payloads_.end(), std::back_inserter(ret)); + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(topic_name_length_buf_.data(), topic_name_length_buf_.size()); + ret.append(get_pointer(topic_name_), get_size(topic_name_)); + + ret.append(packet_id_.data(), packet_id_.size()); + + ret.append(property_length_buf_.data(), property_length_buf_.size()); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + + for (auto const& payload : payloads_) { + ret.append(get_pointer(payload), get_size(payload)); + } + + return ret; + } + + /** + * @brief Get packet id + * @return packet_id + */ + typename packet_id_type::type packet_id() const { + return make_packet_id::apply(packet_id_.begin(), packet_id_.end()); + } + + /** + * @brief Get publish_options + * @return publish_options. + */ + constexpr publish_options get_options() const { + return publish_options(fixed_header_); + } + + /** + * @brief Get qos + * @return qos + */ + constexpr qos get_qos() const { + return publish::get_qos(fixed_header_); + } + + /** + * @brief Check retain flag + * @return true if retain, otherwise return false. + */ + constexpr bool is_retain() const { + return publish::is_retain(fixed_header_); + } + + /** + * @brief Check dup flag + * @return true if dup, otherwise return false. + */ + constexpr bool is_dup() const { + return publish::is_dup(fixed_header_); + } + + /** + * @brief Get topic name + * @return topic name + */ + string_view topic() const { + return string_view(get_pointer(topic_name_), get_size(topic_name_)); + } + + /** + * @brief Get payload + * @return payload + */ + std::vector payload() const { + std::vector ret; + ret.reserve(payloads_.size()); + for (auto const& payload : payloads_) { + ret.emplace_back(get_pointer(payload), get_size(payload)); + } + return ret; + } + + /** + * @brief Get payload as single buffer + * @return payload + */ + buffer payload_as_buffer() const { + auto size = std::accumulate( + payloads_.begin(), + payloads_.end(), + std::size_t(0), + [](std::size_t s, as::const_buffer const& payload) { + return s += payload.size(); + } + ); + + if (size == 0) return buffer(); + + auto spa = make_shared_ptr_array(size); + auto ptr = spa.get(); + auto it = ptr; + for (auto const& payload : payloads_) { + auto b = get_pointer(payload); + auto s = get_size(payload); + auto e = b + s; + std::copy(b, e, it); + it += s; + } + return buffer(string_view(ptr, size), force_move(spa)); + } + + /** + * @brief Get properties + * @return properties + */ + properties const& props() const { + return props_; + } + + /** + * @brief Add property + * @param p property to add + */ + void add_prop(property_variant p) { + auto add_size = v5::size(p); + props_.push_back(force_move(p)); + property_length_ += add_size; + property_length_buf_.clear(); + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_buf_.clear(); + remaining_length_ += add_size; + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Update property + * Only fixed size property can be updated. + * @param p property to update + */ + template + std::enable_if_t< + std::is_base_of, Property>::value || + std::is_base_of, Property>::value || + std::is_base_of, Property>::value + > + update_prop(Property update_prop) { + for (auto& p : props_) { + MQTT_NS::visit( + make_lambda_visitor( + [&update_prop](Property& t) { t = std::forward(update_prop); }, + [](auto&) { } + ), + p + ); + } + } + + /** + * @brief Remove property + * @param id property::id to remove + */ + void remove_prop(v5::property::id id) { + std::size_t removed_size = 0; + auto it = props_.begin(); + auto end = props_.begin(); + while (it != end) { + if (v5::id(*it) == id) { + removed_size += v5::size(*it); + it = props_.erase(it); + } + else { + ++it; + } + } + + property_length_ -= removed_size; + property_length_buf_.clear(); + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_buf_.clear(); + remaining_length_ -= removed_size; + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Set dup flag + * @param dup flag value to set + */ + constexpr void set_dup(bool dup) { + publish::set_dup(fixed_header_, dup); + } + + /** + * @brief Set topic name + * @param topic_name value to set + */ + void set_topic_name(as::const_buffer topic_name) { + auto prev_topic_name_size = get_size(topic_name_); + topic_name_ = force_move(topic_name); + topic_name_length_buf_ = boost::container::static_vector{ + num_to_2bytes(boost::numeric_cast(get_size(topic_name_))) + }; + + remaining_length_buf_.clear(); + remaining_length_ = remaining_length_ - prev_topic_name_size + get_size(topic_name_); + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + +private: + std::uint8_t fixed_header_; + as::const_buffer topic_name_; + boost::container::static_vector topic_name_length_buf_; + boost::container::static_vector packet_id_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::vector payloads_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + std::size_t num_of_const_buffer_sequence_; +}; + +using publish_message = basic_publish_message<2>; +using publish_32_message = basic_publish_message<4>; + +template +struct basic_puback_message { + basic_puback_message( + typename packet_id_type::type packet_id, + v5::puback_reason_code reason_code, + properties props) + : fixed_header_(make_fixed_header(control_packet_type::puback, 0b0000)), + reason_code_(reason_code), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124 + // 3.4.2.1 PUBACK Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBACK has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::puback_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + 1 + // property length + std::accumulate( // properties + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ); + } + } + else { + return 0; + } + } () + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ = + PacketIdBytes + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124 + // 3.4.2.1 PUBACK Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBACK has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::puback_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + property_length_buf_.size() + + property_length_; + } + } + else { + return 0; + } + } (); + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124 + // 3.4.2.1 PUBACK Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBACK has a Remaining Length of 2. + if (reason_code_ != v5::puback_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.emplace_back(as::buffer(&reason_code_, 1)); + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + } + } + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + auto sz = size(); + ret.reserve(sz); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901124 + // 3.4.2.1 PUBACK Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBACK has a Remaining Length of 2. + if (reason_code_ != v5::puback_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.push_back(static_cast(reason_code_)); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901126 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.append(property_length_buf_.data(), property_length_buf_.size()); + + auto it = ret.end(); + ret.resize(sz); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + } + } + return ret; + } + + std::uint8_t fixed_header_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + boost::container::static_vector packet_id_; + v5::puback_reason_code reason_code_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using puback_message = basic_puback_message<2>; + +template +struct basic_pubrec_message { + basic_pubrec_message( + typename packet_id_type::type packet_id, + pubrec_reason_code reason_code, + properties props) + : fixed_header_(make_fixed_header(control_packet_type::pubrec, 0b0000)), + reason_code_(reason_code), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134 + // 3.5.2.1 PUBREC Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREC has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::pubrec_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + 1 + // property length + std::accumulate( // properties + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ); + } + } + else { + return 0; + } + } () + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ = + PacketIdBytes + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134 + // 3.5.2.1 PUBREC Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREC has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::pubrec_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + property_length_buf_.size() + + property_length_; + } + } + else { + return 0; + } + } (); + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134 + // 3.5.2.1 PUBREC Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREC has a Remaining Length of 2. + if (reason_code_ != v5::pubrec_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.emplace_back(as::buffer(&reason_code_, 1)); + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + } + } + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + auto sz = size(); + ret.reserve(sz); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901134 + // 3.5.2.1 PUBREC Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREC has a Remaining Length of 2. + if (reason_code_ != v5::pubrec_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.push_back(static_cast(reason_code_)); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901136 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.append(property_length_buf_.data(), property_length_buf_.size()); + + auto it = ret.end(); + ret.resize(sz); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + } + } + return ret; + } + + + std::uint8_t fixed_header_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + boost::container::static_vector packet_id_; + pubrec_reason_code reason_code_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using pubrec_message = basic_pubrec_message<2>; + +template +struct basic_pubrel_message { + basic_pubrel_message( + typename packet_id_type::type packet_id, + v5::pubrel_reason_code reason_code, + properties props) + : fixed_header_(make_fixed_header(control_packet_type::pubrel, 0b0010)), + reason_code_(reason_code), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.6.2.1 PUBREL Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREL has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::pubrel_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + 1 + // property length + std::accumulate( // properties + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ); + } + } + else { + return 0; + } + } () + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ = + PacketIdBytes + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.6.2.1 PUBREL Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREL has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::pubrel_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + property_length_buf_.size() + + property_length_; + } + } + else { + return 0; + } + } (); + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + basic_pubrel_message(buffer buf) { + if (buf.empty()) throw remaining_length_error(); + fixed_header_ = static_cast(buf.front()); + buf.remove_prefix(1); + + if (buf.empty()) throw remaining_length_error(); + auto len_consumed = remaining_length(buf.begin(), buf.end()); + remaining_length_ = std::get<0>(len_consumed); + auto consumed = std::get<1>(len_consumed); + + std::copy( + buf.begin(), + std::next(buf.begin(), static_cast(consumed)), + std::back_inserter(remaining_length_buf_)); + buf.remove_prefix(consumed); + + if (buf.size() < PacketIdBytes) throw remaining_length_error(); + std::copy(buf.begin(), std::next(buf.begin(), PacketIdBytes), std::back_inserter(packet_id_)); + buf.remove_prefix(PacketIdBytes); + + if (buf.empty()) { + num_of_const_buffer_sequence_ = + 1 + // fixed header + 1 + // remaining length + 1; // packet id + reason_code_ = v5::pubrel_reason_code::success; + return; + } + + reason_code_ = static_cast(buf.front()); + buf.remove_prefix(1); + + if (buf.empty()) { + property_length_ = 0; + } + else { + auto len_consume = variable_length( + buf.begin(), + buf.end() + ); + property_length_ = std::get<0>(len_consume); + auto consume = std::get<1>(len_consume); + if (consume == 0) throw property_length_error(); + std::copy( + buf.begin(), + std::next(buf.begin(), static_cast(consume)), + std::back_inserter(property_length_buf_) + ); + buf.remove_prefix(consume); + if (buf.size() != property_length_) throw property_length_error(); + + props_ = property::parse(buf); + buf.remove_prefix(property_length_); + } + + num_of_const_buffer_sequence_ = + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.6.2.1 PUBREL Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREL has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::pubrel_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + 1 + // property length + std::accumulate( // properties + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ); + } + } + else { + return 0; + } + } (); + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.6.2.1 PUBREL Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREL has a Remaining Length of 2. + if(reason_code_ != v5::pubrel_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.emplace_back(as::buffer(&reason_code_, 1)); + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + } + } + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + auto sz = size(); + ret.reserve(sz); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + ret.append(packet_id_.data(), packet_id_.size()); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.6.2.1 PUBREL Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBREL has a Remaining Length of 2. + if (reason_code_ != v5::pubrel_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.push_back(static_cast(reason_code_)); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901146 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.append(property_length_buf_.data(), property_length_buf_.size()); + + auto it = ret.end(); + ret.resize(sz); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + } + } + return ret; + } + + /** + * @brief Get packet id + * @return packet_id + */ + decltype(auto) packet_id() const { + return make_packet_id::apply(packet_id_.begin(), packet_id_.end()); + } + + /** + * @brief Get reason_code + * @return reason_code + */ + v5::pubrel_reason_code reason_code() const { + return reason_code_; + } + + /** + * @brief Get properties + * @return properties + */ + properties const& props() const { + return props_; + } + + std::uint8_t fixed_header_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + boost::container::static_vector packet_id_; + v5::pubrel_reason_code reason_code_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using pubrel_message = basic_pubrel_message<2>; +using pubrel_32_message = basic_pubrel_message<4>; + +template +struct basic_pubcomp_message { + basic_pubcomp_message( + typename packet_id_type::type packet_id, + pubcomp_reason_code reason_code, + properties props) + : fixed_header_(make_fixed_header(control_packet_type::pubcomp, 0b0000)), + reason_code_(reason_code), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154 + // 3.7.2.1 PUBCOMP Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBCOMP has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::pubcomp_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + 1 + // property length + std::accumulate( // properties + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ); + } + } + else { + return 0; + } + } () + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ = + PacketIdBytes + // packet id + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154 + // 3.7.2.1 PUBCOMP Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBCOMP has a Remaining Length of 2. + [&] () -> std::size_t { + if ((reason_code_ != v5::pubcomp_reason_code::success) || MQTT_ALWAYS_SEND_REASON_CODE) { + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (props_.empty()) { + return 1; // reason code + } + else { + return + 1 + // reason code + property_length_buf_.size() + + property_length_; + } + } + else { + return 0; + } + } (); + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154 + // 3.7.2.1 PUBCOMP Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBCOMP has a Remaining Length of 2. + if (reason_code_ != v5::pubcomp_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.emplace_back(as::buffer(&reason_code_, 1)); + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + } + } + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + auto sz = size(); + ret.reserve(sz); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154 + // 3.7.2.1 PUBCOMP Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no Properties. + // In this case the PUBCOMP has a Remaining Length of 2. + if (reason_code_ != v5::pubcomp_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.push_back(static_cast(reason_code_)); + + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901156 + // If the Remaining Length is less than 4 there is no Property Length and the value of 0 is used. + if (!props_.empty()) { + ret.append(property_length_buf_.data(), property_length_buf_.size()); + + auto it = ret.end(); + ret.resize(sz); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + } + } + return ret; + } + + + std::uint8_t fixed_header_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + boost::container::static_vector packet_id_; + pubcomp_reason_code reason_code_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using pubcomp_message = basic_pubcomp_message<2>; + +template +class basic_subscribe_message { +private: + struct entry { + entry(as::const_buffer topic_filter, subscribe_options options) + : topic_filter_(topic_filter), + topic_filter_length_buf_ { num_to_2bytes(boost::numeric_cast(topic_filter_.size())) }, + options_(options) + {} + + as::const_buffer topic_filter_; + boost::container::static_vector topic_filter_length_buf_; + subscribe_options options_; + }; + +public: + basic_subscribe_message( + std::vector> params, + typename packet_id_type::type packet_id, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::subscribe, 0b0010)), + remaining_length_(PacketIdBytes), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + + params.size() * 3 // topic filter length, topic filter, qos + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ += + property_length_buf_.size() + + property_length_; + + // Check for errors before allocating. + for (auto&& e : params) { + as::const_buffer topic_filter = std::get<0>(e); + utf8string_check(topic_filter); + } + + entries_.reserve(params.size()); + for (auto&& e : params) { + as::const_buffer topic_filter = std::get<0>(e); + size_t size = topic_filter.size(); + + entries_.emplace_back(topic_filter, std::get<1>(e)); + remaining_length_ += + 2 + // topic filter length + size + // topic filter + 1; // means QoS + } + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + + for (auto const& e : entries_) { + ret.emplace_back(as::buffer(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size())); + ret.emplace_back(as::buffer(e.topic_filter_)); + ret.emplace_back(as::buffer(&e.options_, 1)); + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(packet_id_.data(), packet_id_.size()); + + ret.append(property_length_buf_.data(), property_length_buf_.size()); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + + for (auto const& e : entries_) { + ret.append(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size()); + ret.append(get_pointer(e.topic_filter_), get_size(e.topic_filter_)); + ret.push_back(static_cast(e.options_.operator std::uint8_t())); + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + std::vector entries_; + boost::container::static_vector packet_id_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using subscribe_message = basic_subscribe_message<2>; + +template +class basic_suback_message { +public: + basic_suback_message( + std::vector reason_codes, + typename packet_id_type::type packet_id, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::suback, 0b0000)), + remaining_length_(reason_codes.size() + PacketIdBytes), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + + 1 // entries (reason code ...) + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ += + property_length_buf_.size() + + property_length_; + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + entries_.reserve(reason_codes.size()); + for (auto e : reason_codes) { + entries_.push_back(static_cast(e)); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + + ret.emplace_back(as::buffer(entries_)); + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(packet_id_.data(), packet_id_.size()); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + + ret.append(entries_); + + return ret; + } + +private: + std::uint8_t fixed_header_; + std::string entries_; + boost::container::static_vector packet_id_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using suback_message = basic_suback_message<2>; + +template +class basic_unsubscribe_message { +private: + struct entry { + entry(as::const_buffer topic_filter) + : topic_filter_(topic_filter), + topic_filter_length_buf_ { num_to_2bytes(boost::numeric_cast(topic_filter.size())) } + {} + + as::const_buffer topic_filter_; + boost::container::static_vector topic_filter_length_buf_; + }; + +public: + basic_unsubscribe_message( + std::vector params, + typename packet_id_type::type packet_id, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::unsubscribe, 0b0010)), + remaining_length_(PacketIdBytes), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + + params.size() * 2 // topic filter length, topic filter + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ += + property_length_buf_.size() + + property_length_; + + // Check for errors before allocating. + for (auto&& e : params) { + utf8string_check(e); + } + + entries_.reserve(params.size()); + for (auto&& e : params) { + auto size = e.size(); + entries_.emplace_back(e); + remaining_length_ += + 2 + // topic filter length + size; // topic filter + } + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + + for (auto const& e : entries_) { + ret.emplace_back(as::buffer(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size())); + ret.emplace_back(as::buffer(e.topic_filter_)); + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(packet_id_.data(), packet_id_.size()); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + + for (auto const& e : entries_) { + ret.append(e.topic_filter_length_buf_.data(), e.topic_filter_length_buf_.size()); + ret.append(get_pointer(e.topic_filter_), get_size(e.topic_filter_)); + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + std::vector entries_; + boost::container::static_vector packet_id_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using unsubscribe_message = basic_unsubscribe_message<2>; + +template +class basic_unsuback_message { +public: + basic_unsuback_message( + std::vector reason_codes, + typename packet_id_type::type packet_id, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::unsuback, 0b0000)), + reason_codes_(force_move(reason_codes)), + remaining_length_(reason_codes_.size() + PacketIdBytes), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + 1 + // packet id + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + ) + { + add_packet_id_to_buf::apply(packet_id_, packet_id); + + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + + remaining_length_ += + property_length_buf_.size() + + property_length_; + + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + ret.emplace_back(as::buffer(packet_id_.data(), packet_id_.size())); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + + ret.emplace_back(as::buffer(reinterpret_cast(reason_codes_.data()), reason_codes_.size())); + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + ret.append(packet_id_.data(), packet_id_.size()); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + + ret.append(reinterpret_cast(reason_codes_.data()), reason_codes_.size()); + + return ret; + } + +private: + std::uint8_t fixed_header_; + std::vector reason_codes_; + boost::container::static_vector packet_id_; + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +using unsuback_message = basic_unsuback_message<2>; + +struct pingreq_message : detail::header_only_message { + pingreq_message() + : detail::header_only_message(control_packet_type::pingreq, 0b0000) + {} +}; + +struct pingresp_message : detail::header_only_message { + pingresp_message() + : detail::header_only_message(control_packet_type::pingresp, 0b0000) + {} +}; + +struct disconnect_message { + disconnect_message( + v5::disconnect_reason_code reason_code, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::disconnect, 0b0000)), + remaining_length_(0), + reason_code_(reason_code), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + ( + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.14.2.1 Disconnect Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Normal disconnecton) and there are no + // Properties. In this case the DISCONNECT has a Remaining Length of 0. + reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE ? ( + 1 + // reason code + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + ) + : 0 + ) + ) + { + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.14.2.1 Disconnect Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Normal disconnecton) and there are no + // Properties. In this case the DISCONNECT has a Remaining Length of 0. + if (reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE) { + remaining_length_ = + 1 + // reason code + property_length_buf_.size() + + property_length_; + } + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.14.2.1 Disconnect Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Normal disconnecton) and there are no + // Properties. In this case the DISCONNECT has a Remaining Length of 0. + if (reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.emplace_back(as::buffer(&reason_code_, 1)); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 + // 3.14.2.1 Disconnect Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Normal disconnecton) and there are no + // Properties. In this case the DISCONNECT has a Remaining Length of 0. + if (reason_code_ != v5::disconnect_reason_code::normal_disconnection || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.push_back(static_cast(reason_code_)); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + + v5::disconnect_reason_code reason_code_; + + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +struct auth_message { + auth_message( + v5::auth_reason_code reason_code, + properties props + ) + : fixed_header_(make_fixed_header(control_packet_type::auth, 0b0000)), + remaining_length_(0), + reason_code_(reason_code), + property_length_( + std::accumulate( + props.begin(), + props.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::size(pv); + } + ) + ), + props_(force_move(props)), + num_of_const_buffer_sequence_( + 1 + // fixed header + 1 + // remaining length + ( + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220 + // 3.15.2.1 Authenticate Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no + // Properties. In this case the AUTH has a Remaining Length of 0. + reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE ? + ( + 1 + // reason code + 1 + // property length + std::accumulate( + props_.begin(), + props_.end(), + std::size_t(0U), + [](std::size_t total, property_variant const& pv) { + return total + v5::num_of_const_buffer_sequence(pv); + } + ) + ) + : 0 + ) + ) + { + auto pb = variable_bytes(property_length_); + for (auto e : pb) { + property_length_buf_.push_back(e); + } + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220 + // 3.15.2.1 Authenticate Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no + // Properties. In this case the AUTH has a Remaining Length of 0. + if (reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + remaining_length_ = + 1 + // reason code + property_length_buf_.size() + + property_length_; + } + auto rb = remaining_bytes(remaining_length_); + for (auto e : rb) { + remaining_length_buf_.push_back(e); + } + } + + /** + * @brief Create const buffer sequence + * it is for boost asio APIs + * @return const buffer sequence + */ + std::vector const_buffer_sequence() const { + std::vector ret; + ret.reserve(num_of_const_buffer_sequence()); + + ret.emplace_back(as::buffer(&fixed_header_, 1)); + ret.emplace_back(as::buffer(remaining_length_buf_.data(), remaining_length_buf_.size())); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220 + // 3.15.2.1 Authenticate Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no + // Properties. In this case the AUTH has a Remaining Length of 0. + if (reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.emplace_back(as::buffer(&reason_code_, 1)); + + ret.emplace_back(as::buffer(property_length_buf_.data(), property_length_buf_.size())); + for (auto const& p : props_) { + v5::add_const_buffer_sequence(ret, p); + } + } + + return ret; + } + + /** + * @brief Get whole size of sequence + * @return whole size + */ + std::size_t size() const { + return + 1 + // fixed header + remaining_length_buf_.size() + + remaining_length_; + } + + /** + * @brief Get number of element of const_buffer_sequence + * @return number of element of const_buffer_sequence + */ + constexpr std::size_t num_of_const_buffer_sequence() const { + return num_of_const_buffer_sequence_; + } + + /** + * @brief Create one continuours buffer. + * All sequence of buffers are concatinated. + * It is useful to store to file/database. + * @return continuous buffer + */ + std::string continuous_buffer() const { + std::string ret; + + ret.reserve(size()); + + ret.push_back(static_cast(fixed_header_)); + ret.append(remaining_length_buf_.data(), remaining_length_buf_.size()); + + // TODO: This is wrong. The reason code MUST be provided + // if there are properties. Not the other way around. + // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901220 + // 3.15.2.1 Authenticate Reason Code + // The Reason Code and Property Length can be omitted if + // the Reason Code is 0x00 (Success) and there are no + // Properties. In this case the AUTH has a Remaining Length of 0. + if (reason_code_ != v5::auth_reason_code::success || MQTT_ALWAYS_SEND_REASON_CODE) { + ret.push_back(static_cast(reason_code_)); + + auto it = ret.end(); + ret.resize(ret.size() + property_length_); + auto end = ret.end(); + for (auto const& p : props_) { + v5::fill(p, it, end); + it += static_cast(v5::size(p)); + } + } + + return ret; + } + +private: + std::uint8_t fixed_header_; + + std::size_t remaining_length_; + boost::container::static_vector remaining_length_buf_; + + v5::auth_reason_code reason_code_; + + std::size_t property_length_; + boost::container::static_vector property_length_buf_; + properties props_; + std::size_t num_of_const_buffer_sequence_; +}; + +} // namespace v5 + +} // namespace MQTT_NS + +#endif // MQTT_V5_MESSAGE_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/value_allocator.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/value_allocator.hpp new file mode 100644 index 000000000..f5fff1ada --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/value_allocator.hpp @@ -0,0 +1,286 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_VALUE_ALLOCATOR_HPP) +#define MQTT_VALUE_ALLOCATOR_HPP + +#include // should be top to configure variant limit + +#include +#include + +#include +#include +#include + +#include + +namespace MQTT_NS { + +namespace mi = boost::multi_index; + +template +class value_allocator { + using value_type = T; + + class value_interval { + public: + explicit value_interval(value_type v) : low_{v}, high_{v} {} + value_interval(value_type l, value_type h) : low_{l}, high_{h} {} + + // true + // | lhs | | rhs | + // + // false + // | lhs | + // | rhs | + // + // false + // | lhs | + // | rhs | + // + // false + // | lhs | + // | rhs | + // + // false + // | lhs | + // | rhs | + // + // false + // | rhs | | lhs | + // + friend bool operator<(value_interval const& lhs, value_interval const& rhs) { + return + (lhs.low_ < rhs.low_) && + (lhs.high_ < rhs.low_); + } + value_type low() const { + return low_; + } + value_type high() const { + return high_; + } + + friend std::ostream& operator<<(std::ostream& o, value_interval const v) { + o << '[' << v.low() << ',' << v.high() << ']'; + return o; + } + + private: + value_type low_; + value_type high_; + }; + +public: + /** + * @brief Create value_allocator + * The allocator has [lowest, highest] values. + * @param lowest The lowest value + * @param highest The highest value. + */ + value_allocator(value_type lowest, value_type highest) + :lowest_{lowest}, highest_{highest} { + + BOOST_ASSERT(std::numeric_limits::min() <= lowest); + BOOST_ASSERT(highest <= std::numeric_limits::max()); + // create one interval that contains whole values + pool_.emplace(lowest_, highest_); + } + + /** + * @brief Allocate one value. + * @return If allocator has at least one value, then returns lowest value, otherwise return nullopt. + */ + optional allocate() { + if (pool_.empty()) return nullopt; + + // The smallest interval is the target. + auto it = pool_.begin(); + value_type value = it->low(); + + if (it->low() + 1 <= it->high()) { + // If the interval contains other value, then update the interval. + pool_.modify( + it, + [&](auto& e) { + BOOST_ASSERT(it->low() < highest_); + e = value_interval{value_type(it->low() + 1) , it->high()}; + } + ); + } + else { + pool_.erase(it); + } + + return value; + } + + /** + * @brief Get the first vacant value. + * @return If allocator has at least one vacant value, then returns lowest value, otherwise return nullopt. + */ + optional first_vacant() const { + if (pool_.empty()) return nullopt; + + // The smallest interval is the target. + auto it = pool_.begin(); + return it->low(); + } + + /** + * @brief Dellocate one value. + * @param value value to deallocate. The value must be gotten by allocate() or declared by use(). + */ + void deallocate(value_type value) { + BOOST_ASSERT(lowest_ <= value && value <= highest_); + auto itr = pool_.upper_bound(value_interval{value}); + if (itr == pool_.end()) { + + // ..... v + + if (itr == pool_.begin()) { + // value is fully allocated + pool_.emplace(value); + return; + } + + auto itl = itr; + --itl; + if (itl->high() + 1 == value) { // Can concat to the left interval + // Concat left + pool_.modify( + itl, + [&](auto& e) { + e = value_interval{itl->low(), value}; + } + ); + } + else { + // No concat + pool_.emplace(value); + } + } + else if (itr == pool_.begin()) { + + // v ..... + + if (value + 1 == itr->low()) { // Can concat to the right interval + // Concat right + pool_.modify( + itr, + [&](auto& e) { + e = value_interval{value, itr->high()}; + } + ); + } + else { + // No concat + pool_.emplace(value); + } + } + else { + + // .. v .. + + auto itl = itr; + --itl; + if (itl->high() + 1 == value) { // Can concat to the left interval + if (value + 1 == itr->low()) { // Can concat to the right interval + // Concat both + auto right = itr->high(); + pool_.erase(itr); + pool_.modify( + itl, + [&](auto& e) { + e = value_interval{itl->low(), right}; + } + ); + + } + else { + // Concat left + pool_.modify( + itl, + [&](auto& e) { + e = value_interval{itl->low(), value}; + } + ); + } + } + else { + if (value + 1 == itr->low()) { // Can concat to the right interval + // Concat right + pool_.modify( + itr, + [&](auto& e) { + e = value_interval{value, itr->high()}; + } + ); + } + else { + // No concat + pool_.emplace(value); + } + } + } + } + + /** + * @brief Declare the value as used. + * @param value The value to declare using + * @return If value is not used or allocated then true, otherwise false + */ + bool use(value_type value) { + auto it = pool_.find(value_interval{value}); + if (it == pool_.end()) return false; + + value_interval iv = *it; + pool_.erase (it); + if (iv.low() < value) { + pool_.emplace(iv.low(), value - 1); + } + if (value + 1 <= iv.high()) { + pool_.emplace(value + 1, iv.high()); + } + return true; + } + + /** + * @brief Clear all allocated or used values. + */ + void clear() { + pool_.clear(); + pool_.emplace(lowest_, highest_); + } + + std::size_t interval_count() const { + return pool_.size(); + } + + std::ostream& dump(std::ostream& o) { + for (auto const& e : pool_) { + o << e; + } + return o; + } +private: + using mi_value_interval = mi::multi_index_container< + value_interval, + mi::indexed_by< + mi::ordered_unique< + mi::identity + > + > + >; + mi_value_interval pool_; + value_type lowest_; + value_type highest_; +}; + +} // namespace MQTT_NS + +#endif // MQTT_VALUE_ALLOCATOR_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/variable_length.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/variable_length.hpp new file mode 100644 index 000000000..a76a722f0 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/variable_length.hpp @@ -0,0 +1,74 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_VARIABLE_LENGTH_HPP) +#define MQTT_VARIABLE_LENGTH_HPP + +#include + +#include +#include + +namespace MQTT_NS { + +inline std::string +variable_bytes(std::size_t size) { + std::string bytes; + if (size > 0xfffffff) return bytes; + while (size > 127) { + bytes.push_back(static_cast((size & 0b01111111) | 0b10000000)); + size >>= 7; + } + bytes.push_back(size & 0b01111111); + return bytes; +} + +template +inline void +variable_push(Container& c, std::size_t size) { + if (size > 0xfffffff) return; + while (size > 127) { + c.push_back(static_cast((size & 0b01111111) | 0b10000000)); + size >>= 7; + } + c.push_back(size & 0b01111111); +} + +template +constexpr std::tuple +variable_length(T const& bytes) { + std::size_t len = 0; + std::size_t mul = 1; + std::size_t consumed = 0; + for (auto b : bytes) { + len += (b & 0b01111111) * mul; + mul *= 128; + ++consumed; + if (mul > 128 * 128 * 128 * 128) return {0, 0}; + if (!(b & 0b10000000)) break; + } + return {len, consumed}; +} + +template +constexpr std::tuple +variable_length(Iterator b, Iterator e) { + std::size_t len = 0; + std::size_t mul = 1; + std::size_t consumed = 0; + for (; b != e; ++b) { + len += (*b & 0b01111111) * mul; + mul *= 128; + ++consumed; + if (mul > 128 * 128 * 128 * 128) return {0, 0}; + if (!(*b & 0b10000000)) break; + } + return {len, consumed}; +} + +} // namespace MQTT_NS + +#endif // MQTT_VARIABLE_LENGTH_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/variant.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/variant.hpp new file mode 100644 index 000000000..a7121c2b1 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/variant.hpp @@ -0,0 +1,69 @@ +// Copyright Takatoshi Kondo 2018 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_VARIANT_HPP) +#define MQTT_VARIANT_HPP + +#include +#include + +#if defined(MQTT_STD_VARIANT) + +#include + +namespace MQTT_NS { + +using std::variant; + +template +decltype(auto) variant_get(U && arg) +{ + return std::get(std::forward(arg)); +} + +template +decltype(auto) variant_idx(T const& arg) +{ + return arg.index(); +} + +using std::visit; + +} // namespace MQTT_NS + +#else // defined(MQTT_STD_VARIANT) + +#include +#include +#include + +namespace MQTT_NS { + +using boost::variant; + +template +decltype(auto) variant_get(U && arg) +{ + return boost::get(std::forward(arg)); +} + +template +decltype(auto) variant_idx(T const& arg) +{ + return arg.which(); +} + +template +constexpr decltype(auto) visit(Visitor&& vis, Variants&&... vars) +{ + return boost::apply_visitor(std::forward(vis), std::forward(vars)...); +} + +} // namespace MQTT_NS + +#endif // defined(MQTT_STD_VARIANT) + +#endif // MQTT_VARIANT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/variant_visit.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/variant_visit.hpp new file mode 100644 index 000000000..bf6c6356c --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/variant_visit.hpp @@ -0,0 +1,36 @@ +// Copyright Takatoshi Kondo 2020 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_VARIANT_VISIT_HPP) +#define MQTT_VARIANT_VISIT_HPP + +#include + +#include +#include +#include + +namespace MQTT_NS { + +#if defined(MQTT_STD_VARIANT) + +template +std::ostream& operator<<(std::ostream& os, variant const& v) { + MQTT_NS::visit( + make_lambda_visitor( + [&os] (auto const& e) { + os << e; + } + ), v + ); + return os; +} + +#endif // defined(MQTT_USE_STD_VARIANT) + +} // namespace MQTT_NS + +#endif // MQTT_VARIANT_VISIT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/visitor_util.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/visitor_util.hpp new file mode 100644 index 000000000..1ff8a36d2 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/visitor_util.hpp @@ -0,0 +1,43 @@ +// Copyright Takatoshi Kondo 2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_VISITOR_UTIL_HPP) +#define MQTT_VISITOR_UTIL_HPP + +#include +#include + +namespace MQTT_NS { + +template +struct lambda_visitor; + +template +struct lambda_visitor + : Lambda1, lambda_visitor { + using Lambda1::operator(); + using lambda_visitor::operator(); + lambda_visitor(Lambda1 lambda1, Lambdas... lambdas) + : Lambda1(lambda1), lambda_visitor(lambdas...) {} +}; + + +template +struct lambda_visitor : Lambda1 { + using Lambda1::operator(); + lambda_visitor(Lambda1 lambda1) + : Lambda1(lambda1) {} +}; + + +template +inline lambda_visitor make_lambda_visitor(Lambdas&&... lambdas) { + return { std::forward(lambdas)... }; +} + +} // namespace MQTT_NS + +#endif // MQTT_VISITOR_UTIL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/will.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/will.hpp new file mode 100644 index 000000000..6703f14c3 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/will.hpp @@ -0,0 +1,78 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_WILL_HPP) +#define MQTT_WILL_HPP + +#include + +#include + +#include +#include +#include +#include + +namespace MQTT_NS { + +class will { +public: + /** + * @brief constructor + * @param topic + * A topic name to publish as a will + * @param message + * The contents to publish as a will + * @param pubopts + * Qos and retain flag + * @param qos + * qos + */ + will(buffer topic, + buffer message, + publish_options pubopts = {}, + v5::properties props = {}) + :topic_(force_move(topic)), + message_(force_move(message)), + pubopts_(pubopts), + props_(force_move(props)) + {} + + constexpr buffer const& topic() const { + return topic_; + } + constexpr buffer& topic() { + return topic_; + } + constexpr buffer const& message() const { + return message_; + } + constexpr buffer& message() { + return message_; + } + constexpr retain get_retain() const { + return pubopts_.get_retain(); + } + constexpr qos get_qos() const { + return pubopts_.get_qos(); + } + constexpr v5::properties const& props() const { + return props_; + } + constexpr v5::properties& props() { + return props_; + } + +private: + buffer topic_; + buffer message_; + publish_options pubopts_; + v5::properties props_; +}; + +} // namespace MQTT_NS + +#endif // MQTT_WILL_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt/ws_endpoint.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt/ws_endpoint.hpp new file mode 100644 index 000000000..4869b0551 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt/ws_endpoint.hpp @@ -0,0 +1,378 @@ +// Copyright Takatoshi Kondo 2016 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#if !defined(MQTT_WS_ENDPOINT_HPP) +#define MQTT_WS_ENDPOINT_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace MQTT_NS { + +namespace as = boost::asio; + +template +class ws_endpoint : public socket { +public: + template + explicit ws_endpoint(as::io_context& ioc, Args&&... args) + :ws_(ioc, std::forward(args)...), +#if defined(MQTT_NO_TS_EXECUTORS) + strand_(ioc.get_executor()) +#else + strand_(ioc) +#endif + { + ws_.binary(true); + ws_.set_option( + boost::beast::websocket::stream_base::decorator( + [](boost::beast::websocket::request_type& req) { + req.set("Sec-WebSocket-Protocol", "mqtt"); + } + ) + ); + } + + MQTT_ALWAYS_INLINE void async_read( + as::mutable_buffer buffers, + std::function handler + ) override final { + auto req_size = as::buffer_size(buffers); + + using beast_read_handler_t = + std::function)>; + + std::shared_ptr beast_read_handler; + if (req_size <= buffer_.size()) { + as::buffer_copy(buffers, buffer_.data(), req_size); + buffer_.consume(req_size); + handler(boost::system::errc::make_error_code(boost::system::errc::success), req_size); + return; + } + + beast_read_handler.reset( + new beast_read_handler_t( + [this, req_size, buffers, handler = force_move(handler)] + (error_code ec, std::shared_ptr const& v) mutable { + if (ec) { + force_move(handler)(ec, 0); + return; + } + if (!ws_.got_binary()) { + buffer_.consume(buffer_.size()); + force_move(handler) + (boost::system::errc::make_error_code(boost::system::errc::bad_message), 0); + return; + } + if (req_size > buffer_.size()) { + auto beast_read_handler = std::static_pointer_cast(v); + ws_.async_read( + buffer_, + as::bind_executor( + strand_, + [beast_read_handler] + (error_code ec, std::size_t) { + (*beast_read_handler)(ec, beast_read_handler); + } + ) + ); + return; + } + as::buffer_copy(buffers, buffer_.data(), req_size); + buffer_.consume(req_size); + force_move(handler)(boost::system::errc::make_error_code(boost::system::errc::success), req_size); + } + ) + ); + ws_.async_read( + buffer_, + as::bind_executor( + strand_, + [beast_read_handler] + (error_code ec, std::size_t) { + (*beast_read_handler)(ec, beast_read_handler); + } + ) + ); + } + + MQTT_ALWAYS_INLINE void async_write( + std::vector buffers, + std::function handler + ) override final { + ws_.async_write( + buffers, + as::bind_executor( + strand_, + force_move(handler) + ) + ); + } + + MQTT_ALWAYS_INLINE std::size_t write( + std::vector buffers, + boost::system::error_code& ec + ) override final { + ws_.write(buffers, ec); + return as::buffer_size(buffers); + } + + MQTT_ALWAYS_INLINE void post(std::function handler) override final { + as::post( + strand_, + force_move(handler) + ); + } + + MQTT_ALWAYS_INLINE void dispatch(std::function handler) override final { + as::dispatch( + strand_, + force_move(handler) + ); + } + + MQTT_ALWAYS_INLINE void defer(std::function handler) override final { + as::defer( + strand_, + force_move(handler) + ); + } + + MQTT_ALWAYS_INLINE bool running_in_this_thread() const override final { + return strand_.running_in_this_thread(); + } + +#if BOOST_VERSION >= 107000 + + MQTT_ALWAYS_INLINE as::ip::tcp::socket::lowest_layer_type& lowest_layer() override final { + return boost::beast::get_lowest_layer(ws_); + } + +#else // BOOST_VERSION >= 107000 + + MQTT_ALWAYS_INLINE as::ip::tcp::socket::lowest_layer_type& lowest_layer() override final { + return ws_.lowest_layer(); + } + +#endif // BOOST_VERSION >= 107000 + + MQTT_ALWAYS_INLINE any native_handle() override final { + return next_layer().native_handle(); + } + + MQTT_ALWAYS_INLINE void clean_shutdown_and_close(boost::system::error_code& ec) override final { + if (ws_.is_open()) { + // WebSocket closing process + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "call beast close"; + ws_.close(boost::beast::websocket::close_code::normal, ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "ws close ec:" + << ec.message(); + if (!ec) { + do { + boost::beast::flat_buffer buffer; + ws_.read(buffer, ec); + } while (!ec); + if (ec == boost::beast::websocket::error::closed) { + ec = boost::system::errc::make_error_code(boost::system::errc::success); + } + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "ws read ec:" + << ec.message(); + } + } + shutdown_and_close_impl(next_layer(), ec); + } + + MQTT_ALWAYS_INLINE void async_clean_shutdown_and_close(std::function handler) override final { + if (ws_.is_open()) { + // WebSocket closing process + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "call beast async_close"; + ws_.async_close( + boost::beast::websocket::close_code::normal, + as::bind_executor( + strand_, + [this, handler = force_move(handler)] + (error_code ec) mutable { + if (ec) { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "ws async_close ec:" + << ec.message(); + async_shutdown_and_close_impl(next_layer(), force_move(handler)); + } + else { + async_read_until_closed(force_move(handler)); + } + } + ) + ); + } + else { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "ws async_close already closed"; + async_shutdown_and_close_impl(next_layer(), force_move(handler)); + } + } + + MQTT_ALWAYS_INLINE void force_shutdown_and_close(boost::system::error_code& ec) override final { + lowest_layer().shutdown(as::ip::tcp::socket::shutdown_both, ec); + lowest_layer().close(ec); + } + +#if BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + MQTT_ALWAYS_INLINE as::executor get_executor() override final { + return lowest_layer().get_executor(); + } +#else // BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + MQTT_ALWAYS_INLINE as::any_io_executor get_executor() override final { + return lowest_layer().get_executor(); + } +#endif // BOOST_VERSION < 107400 || defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) + + typename boost::beast::websocket::stream::next_layer_type& next_layer() { + return ws_.next_layer(); + } + + template + void set_option(T&& t) { + ws_.set_option(std::forward(t)); + } + + template + void async_accept( + ConstBufferSequence const& buffers, + AcceptHandler&& handler) { + ws_.async_accept(buffers, std::forward(handler)); + } + + template + void async_accept_ex( + ConstBufferSequence const& buffers, + ResponseDecorator const& decorator, + AcceptHandler&& handler) { + ws_.async_accept_ex(buffers, decorator, std::forward(handler)); + } + + template + void async_handshake(Args&& ... args) { + ws_.async_handshake(std::forward(args)...); + } + + template + void handshake(Args&& ... args) { + ws_.handshake(std::forward(args)...); + } + + template + std::size_t write( + ConstBufferSequence const& buffers) { + ws_.write(buffers); + return as::buffer_size(buffers); + } + +private: + void async_read_until_closed(std::function handler) { + auto buffer = std::make_shared(); + ws_.async_read( + *buffer, + as::bind_executor( + strand_, + [this, handler = force_move(handler)] + (error_code ec, std::size_t) mutable { + if (ec) { + if (ec == boost::beast::websocket::error::closed) { + ec = boost::system::errc::make_error_code(boost::system::errc::success); + } + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "ws async_read ec:" + << ec.message(); + async_shutdown_and_close_impl(next_layer(), force_move(handler)); + } + else { + async_read_until_closed(force_move(handler)); + } + } + ) + ); + } + + void shutdown_and_close_impl(as::basic_socket& s, boost::system::error_code& ec) { + s.shutdown(as::ip::tcp::socket::shutdown_both, ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "shutdown ec:" + << ec.message(); + s.close(ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "close ec:" + << ec.message(); + } + + void async_shutdown_and_close_impl(as::basic_socket& s, std::function handler) { + post( + [this, &s, handler = force_move(handler)] () mutable { + error_code ec; + shutdown_and_close_impl(s, ec); + force_move(handler)(ec); + } + ); + } + +#if defined(MQTT_USE_TLS) + void shutdown_and_close_impl(tls::stream& s, boost::system::error_code& ec) { + s.shutdown(ec); + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "shutdown ec:" + << ec.message(); + shutdown_and_close_impl(lowest_layer(), ec); + } + void async_shutdown_and_close_impl(tls::stream& s, std::function handler) { + s.async_shutdown( + as::bind_executor( + strand_, + [this, handler = force_move(handler)] (error_code ec) mutable { + MQTT_LOG("mqtt_impl", trace) + << MQTT_ADD_VALUE(address, this) + << "shutdown ec:" + << ec.message(); + shutdown_and_close_impl(lowest_layer(), ec); + force_move(handler)(ec); + } + ) + ); + } +#endif // defined(MQTT_USE_TLS) + +private: + boost::beast::websocket::stream ws_; + boost::beast::flat_buffer buffer_; + Strand strand_; +}; + +} // namespace MQTT_NS + +#endif // MQTT_WS_ENDPOINT_HPP diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt_client_cpp.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt_client_cpp.hpp new file mode 100644 index 000000000..7ee942160 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt_client_cpp.hpp @@ -0,0 +1,28 @@ +// Copyright Takatoshi Kondo 2015 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include // should be top to configure boost::variant limit +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/cpp/3rdparty/mqtt_cpp/mqtt_server_cpp.hpp b/src/cpp/3rdparty/mqtt_cpp/mqtt_server_cpp.hpp new file mode 100644 index 000000000..97a7573a0 --- /dev/null +++ b/src/cpp/3rdparty/mqtt_cpp/mqtt_server_cpp.hpp @@ -0,0 +1,25 @@ +// Copyright Takatoshi Kondo 2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#include // should be top to configure boost::variant limit +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/cpp/3rdparty/sciplot/Canvas.hpp b/src/cpp/3rdparty/sciplot/Canvas.hpp new file mode 100755 index 000000000..220f311c0 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Canvas.hpp @@ -0,0 +1,295 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2022 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include + +// sciplot includes +#include + +namespace sciplot +{ + +/// The class used to create multiple figures in one canvas. A canvas can be show on screen or output to file. +class Canvas +{ + public: + /// Construct a Canvas object with given figures. + Canvas(const std::initializer_list>& figures); + + /// Construct a Canvas object with given figures. + Canvas(const std::vector>& figures); + + /// Get reference to figure object on canvas + /// @note Will throw if figure does not exist + Figure& get(int i, int j); + + /// Toggle automatic cleaning of temporary files (enabled by default). Pass false if you want to keep your script / data files. + /// Call cleanup() to remove those files manually. + auto autoclean(bool enable = true) -> void; + + /// Set the default palette of colors for all plots that DO NOT have a palette set. + /// @param name Any palette name displayed in https://github.com/Gnuplotting/gnuplot-palettes, such as "viridis", "parula", "jet". + auto defaultPalette(const std::string& name) -> Canvas&; + + /// Set the output size of the canvas (in unit of points, with 1 inch = 72 points). + auto size(std::size_t width, std::size_t height) -> Canvas&; + + /// Set the font name for all the plots on the canvas (e.g., Helvetica, Georgia, Times). + auto fontName(std::string name) -> Canvas&; + + /// Set the font size for all the plots on the canvas (e.g., 10, 12, 16). + auto fontSize(std::size_t size) -> Canvas&; + + /// Set the title of the canvas. + /// @note This only work for show() atm! + auto title(const std::string& title) -> Canvas&; + + /// Write the current plot data of all figures to the data file(s). + auto saveplotdata() const -> void; + + /// Show the canvas in a pop-up window. + /// @note This method removes temporary files after saving if `Canvas::autoclean(true)` (default). + auto show() const -> void; + + /// Save the canvas to a file, with its extension defining the file format. + /// The extension of the file name determines the file format. + /// The supported formats are: `pdf`, `eps`, `svg`, `png`, and `jpeg`. + /// Thus, to save the canvas in `pdf` format, choose a file name as in `canvas.pdf`. + /// @note This method removes temporary files after saving if `Canvas::autoclean(true)` (default). + auto save(const std::string& filename) const -> void; + + /// Delete all files used to store plot data or scripts. + auto cleanup() const -> void; + + private: + /// Counter of how many canvas objects have been instanciated in the application + static std::size_t m_counter; + + /// Canvas id derived from m_counter upon construction + /// Must be the first member due to constructor initialization order! + std::size_t m_id = 0; + + /// Toggle automatic cleaning of temporary files (enabled by default) + bool m_autoclean = true; + + /// The name of the default gnuplot palette to be used + std::string m_defaultPalette; + + /// The font name and size used in the plots + FontSpecs m_font; + + /// The size of the plot in x + std::size_t m_width = 0; + + /// The size of the plot in y + std::size_t m_height = 0; + + /// The number of rows in the multiplot layout + std::size_t m_layoutrows = 0; + + /// The number of columns in the multiplot layout + std::size_t m_layoutcols = 0; + + /// The title of the plot + std::string m_title; + + /// The name of the file where the plot commands are saved + std::string m_scriptfilename; + + /// All the figures that have been added to the canvas + std::vector> m_figures; +}; + +// Initialize the counter of plot objects +inline std::size_t Canvas::m_counter = 0; + +inline Canvas::Canvas(const std::initializer_list>& figures) + : m_id(m_counter++), m_scriptfilename("multishow" + internal::str(m_id) + ".plt") +{ + m_layoutrows = figures.size(); + m_layoutcols = 1; + for (const auto& row : figures) + m_layoutcols = std::max(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows + + for (const auto& row : figures) + m_figures.emplace_back(row.begin(), row.end()); +} + +inline Canvas::Canvas(const std::vector>& figures) + : m_id(m_counter++), m_scriptfilename("multishow" + internal::str(m_id) + ".plt"), m_figures(figures) +{ + m_layoutrows = figures.size(); + m_layoutcols = 1; + for (const auto& row : figures) + m_layoutcols = std::max(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows +} + +inline Figure& Canvas::get(int i, int j) +{ + return m_figures.at(j).at(i); +} + +inline auto Canvas::autoclean(bool enable) -> void +{ + m_autoclean = enable; +} + +inline auto Canvas::defaultPalette(const std::string& name) -> Canvas& +{ + m_defaultPalette = name; + return *this; +} + +inline auto Canvas::size(std::size_t width, std::size_t height) -> Canvas& +{ + m_width = width; + m_height = height; + return *this; +} + +inline auto Canvas::fontName(std::string name) -> Canvas& +{ + m_font.fontName(name); + return *this; +} + +inline auto Canvas::fontSize(std::size_t size) -> Canvas& +{ + m_font.fontSize(size); + return *this; +} + +inline auto Canvas::title(const std::string& title) -> Canvas& +{ + m_title = title; + return *this; +} + +inline auto Canvas::saveplotdata() const -> void +{ + for (const auto& row : m_figures) + { + for (const auto& figure : row) + { + figure.saveplotdata(); + } + } +} + +inline auto Canvas::show() const -> void +{ + // Open script file and truncate it + std::ofstream script(m_scriptfilename); + + // Add palette info. Use default palette if the user hasn't set one + gnuplot::palettecmd(script, m_defaultPalette.empty() ? internal::SCIPLOT_DEFAULT_PALETTE : m_defaultPalette); + // Add terminal info + auto width = m_width == 0 ? internal::DEFAULT_FIGURE_WIDTH : m_width; + auto height = m_height == 0 ? internal::DEFAULT_FIGURE_HEIGHT : m_height; + std::string size = gnuplot::canvasSizeStr(width, height, false); + gnuplot::showterminalcmd(script, size, m_font, m_title); + // Add the plot commands + for (const auto& row : m_figures) + { + for (const auto& figure : row) + { + // Add the plot commands + script << figure.repr(); + } + } + // Add an empty line at the end and close the script to avoid crashes with gnuplot + script << std::endl; + script.close(); + // save plot data to file(s) + saveplotdata(); + // Show the figure + gnuplot::runscript(m_scriptfilename, true); + // remove the temporary files if user wants to + if (m_autoclean) + { + cleanup(); + } +} + +inline auto Canvas::save(const std::string& filename) const -> void +{ + // Clean the file name to prevent errors + auto cleanedfilename = gnuplot::cleanpath(filename); + // Get extension from file name + auto extension = cleanedfilename.substr(cleanedfilename.rfind(".") + 1); + // Open script file + std::ofstream script(m_scriptfilename); + // Add palette info. Use default palette if the user hasn't set one + gnuplot::palettecmd(script, m_defaultPalette.empty() ? internal::SCIPLOT_DEFAULT_PALETTE : m_defaultPalette); + // Add terminal info including output size + auto width = m_width == 0 ? internal::DEFAULT_FIGURE_WIDTH : m_width; + auto height = m_height == 0 ? internal::DEFAULT_FIGURE_HEIGHT : m_height; + std::string size = gnuplot::canvasSizeStr(width, height, extension == "pdf"); + gnuplot::saveterminalcmd(script, extension, size, m_font); + // Add output command + gnuplot::outputcmd(script, cleanedfilename); + // Add the plot commands + for (const auto& row : m_figures) + { + for (const auto& figure : row) + { + // Add the plot commands + script << figure.repr(); + } + } + // Unset the output + script << std::endl; + script << "set output"; + // Add an empty line at the end and close the script to avoid crashes with gnuplot + script << std::endl; + script.close(); + // save plot data to file(s) + saveplotdata(); + // Save the figure as a file + gnuplot::runscript(m_scriptfilename, false); + // remove the temporary files if user wants to + if (m_autoclean) + { + cleanup(); + } +} + +inline auto Canvas::cleanup() const -> void +{ + std::remove(m_scriptfilename.c_str()); + for (const auto& row : m_figures) + { + for (const auto& figure : row) + { + figure.cleanup(); + } + } +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/ColumnIndex.hpp b/src/cpp/3rdparty/sciplot/ColumnIndex.hpp new file mode 100755 index 000000000..1c4b06ec9 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/ColumnIndex.hpp @@ -0,0 +1,52 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include + +namespace sciplot { + +/// An auxiliary type used to represent a data column index. +struct ColumnIndex +{ + /// Construct a default ColumnIndex object. + ColumnIndex() : ColumnIndex(0) {} + + /// Construct a ColumnIndex object with given integer. + ColumnIndex(int col) : value(std::to_string(col)) {} // 1 => "1" + + /// Construct a ColumnIndex object with given string (the header of the column). + ColumnIndex(std::string col) : value("'" + col + "'") {} // "Name" => "'Name'" + + /// Construct a ColumnIndex object with given string. + ColumnIndex(const char* col) : ColumnIndex(std::string(col)) {} + + /// The column index value. + std::string value; +}; + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Constants.hpp b/src/cpp/3rdparty/sciplot/Constants.hpp new file mode 100755 index 000000000..59410bdd5 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Constants.hpp @@ -0,0 +1,43 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include + +namespace sciplot { + +// const auto PI = 3.14159265359; +const auto GOLDEN_RATIO = 1.618034; +const auto GOLDEN_RATIO_INVERSE = 1.0 / GOLDEN_RATIO; +const auto INCH_TO_POINTS = 72.0; // based on pdfcairo terminal conversion +const auto POINT_TO_INCHES = 1.0 / INCH_TO_POINTS; + +constexpr auto NaN = std::numeric_limits::quiet_NaN(); // can be used to indicate missing values in a numeric vector +const auto MISSING_INDICATOR = "\"?\""; // The string used to indicate missing y values. + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Default.hpp b/src/cpp/3rdparty/sciplot/Default.hpp new file mode 100755 index 000000000..696844065 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Default.hpp @@ -0,0 +1,81 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include + +// sciplot includes +#include +#include + +namespace sciplot +{ +namespace internal +{ + +const auto DEFAULT_FIGURE_HEIGHT = 200; // this is equivalent to 6 inches if 1 in = 72 points +const auto DEFAULT_FIGURE_WIDTH = static_cast(std::round(DEFAULT_FIGURE_HEIGHT * GOLDEN_RATIO)); +const auto DEFAULT_FIGURE_BOXWIDTH_RELATIVE = 0.9; + +const auto SCIPLOT_DEFAULT_PALETTE = "dark2"; + +const auto DEFAULT_TEXTCOLOR = "#404040"; + +const auto DEFAULT_LINEWIDTH = 2; +const auto DEFAULT_POINTSIZE = 2; + +const auto DEFAULT_FILL_INTENSITY = 1.0; +const auto DEFAULT_FILL_TRANSPARENCY = false; +const auto DEFAULT_FILL_BORDER_LINEWIDTH = 2; + +const auto DEFAULT_BORDER_LINECOLOR = "#404040"; +const auto DEFAULT_BORDER_LINETYPE = 1; +const auto DEFAULT_BORDER_LINEWIDTH = 2; + +const auto DEFAULT_GRID_LINECOLOR = "#d6d7d9"; +const auto DEFAULT_GRID_LINEWIDTH = 1; +const auto DEFAULT_GRID_LINETYPE = 1; +const auto DEFAULT_GRID_DASHTYPE = 0; + +const auto DEFAULT_LEGEND_TEXTCOLOR = DEFAULT_TEXTCOLOR; +const auto DEFAULT_LEGEND_FRAME_SHOW = false; +const auto DEFAULT_LEGEND_FRAME_LINECOLOR = DEFAULT_GRID_LINECOLOR; +const auto DEFAULT_LEGEND_FRAME_LINEWIDTH = DEFAULT_GRID_LINEWIDTH; +const auto DEFAULT_LEGEND_FRAME_LINETYPE = 1; +const auto DEFAULT_LEGEND_FRAME_EXTRA_WIDTH = 0; +const auto DEFAULT_LEGEND_FRAME_EXTRA_HEIGHT = 1; +const auto DEFAULT_LEGEND_SPACING = 1; +const auto DEFAULT_LEGEND_SAMPLE_LENGTH = 4; + +const auto DEFAULT_TICS_MIRROR = false; +const auto DEFAULT_TICS_ROTATE = false; +const auto DEFAULT_TICS_SCALE_MAJOR_BY = 0.50; +const auto DEFAULT_TICS_SCALE_MINOR_BY = 0.25; +const auto DEFAULT_TICS_MINOR_SHOW = false; + +} // namespace internal +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Enums.hpp b/src/cpp/3rdparty/sciplot/Enums.hpp new file mode 100755 index 000000000..3f826b586 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Enums.hpp @@ -0,0 +1,40 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +namespace sciplot { + +/// The extension formats supported by sciplot when saving a plot to a file. +enum class Extension +{ + emf, + png, + svg, + pdf, + eps +}; + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Figure.hpp b/src/cpp/3rdparty/sciplot/Figure.hpp new file mode 100755 index 000000000..64325e8ec --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Figure.hpp @@ -0,0 +1,264 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2022 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include +#include + +// sciplot includes +#include +#include +#include +#include + +namespace sciplot +{ + +/// The auxiliary type to represent either a 2D or 3D plot. +using PlotVariant = std::variant; + +template +struct Overload : Ts... +{ + using Ts::operator()...; +}; +template +Overload(Ts...) -> Overload; + +static constexpr auto SavePlotVisitor = Overload{ + [](const Plot2D& p) + { p.savePlotData(); }, + [](const Plot3D& p) + { p.savePlotData(); }}; + +static constexpr auto ReprPlotVisitor = Overload{ + [](const Plot2D& p) + { return p.repr(); }, + [](const Plot3D& p) + { return p.repr(); }}; + +static constexpr auto CleanupPlotVisitor = Overload{ + [](const Plot2D& p) + { p.cleanup(); }, + [](const Plot3D& p) + { p.cleanup(); }}; + +/// The class used to create multiple plots in one canvas. A container for plots. +class Figure +{ + public: + /// Construct a Figure object with given plots. + Figure(const std::initializer_list>& plots); + + /// Construct a Figure object with given plots. + Figure(const std::vector>& plots); + + /// Get reference to generic plot object in figure + /// @note Will throw if plot does not exist + Plot& get(int i, int j); + + /// Get reference to specific plot object (2D / 3D) in figure + /// @note Will throw if plot does not exist or T is of wrong type + template + T& get(int i, int j); + + /// Set the palette of colors for all plots in the figure. + /// @param name Any palette name displayed in https://github.com/Gnuplotting/gnuplot-palettes, such as "viridis", "parula", "jet". + auto palette(const std::string& name) -> Figure&; + + /// Set the layout of the figure inside the canvas and return a reference to the corresponding specs object. + auto layout() -> LayoutSpecs&; + + /// Set the font name for all the plots in the figure (e.g., Helvetica, Georgia, Times). + auto fontName(std::string name) -> Figure&; + + /// Set the font size for all the plots in the figure (e.g., 10, 12, 16). + auto fontSize(std::size_t size) -> Figure&; + + /// Set the title of the figure. + auto title(const std::string& title) -> Figure&; + + /// Write the current plot data of all plots to the data file(s). + auto saveplotdata() const -> void; + + /// Delete all files used to store plot data or scripts. + auto cleanup() const -> void; + + /// Convert this figure into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// Counter of how many plot / singleplot objects have been instanciated in the application + static std::size_t m_counter; + + /// Plot id derived from m_counter upon construction + /// Must be the first member due to constructor initialization order! + std::size_t m_id = 0; + + /// The layout of the figure inside the canvas + LayoutSpecs m_layout; + + /// The number of rows in the multiplot layout + std::size_t m_layoutrows = 0; + /// The number of columns in the multiplot layout + std::size_t m_layoutcols = 0; + + /// The title of the figure + std::string m_title; + + /// All the plots that have been added to the figure + std::vector> m_plots; +}; + +// Initialize the counter of plot objects +inline std::size_t Figure::m_counter = 0; + +inline Figure::Figure(const std::initializer_list>& plots) + : m_id(m_counter++) +{ + m_layoutrows = plots.size(); + m_layoutcols = 1; + for (const auto& row : plots) + m_layoutcols = std::max(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows + + for (const auto& row : plots) + m_plots.emplace_back(row.begin(), row.end()); +} + +inline Figure::Figure(const std::vector>& plots) + : m_id(m_counter++), m_plots(plots) +{ + m_layoutrows = plots.size(); + m_layoutcols = 1; + for (const auto& row : plots) + m_layoutcols = std::max(m_layoutcols, row.size()); // m_layoutcols = max number of columns among all rows +} + +inline Plot& Figure::get(int i, int j) +{ + auto& plot = m_plots.at(j).at(i); + if (std::holds_alternative(plot)) + { + return std::get(plot); + } + else if (std::holds_alternative(plot)) + { + return std::get(plot); + } + throw std::runtime_error("Unknown plot type / Empty variant"); +} + +template <> +inline Plot2D& Figure::get(int i, int j) +{ + return std::get(m_plots.at(j).at(i)); +} + +template <> +inline Plot3D& Figure::get(int i, int j) +{ + return std::get(m_plots.at(j).at(i)); +} + +inline auto Figure::palette(const std::string& name) -> Figure& +{ + for (auto& row : m_plots) + { + for (auto& plot : row) + { + if (std::holds_alternative(plot)) + { + std::get(plot).palette(name); + } + else if (std::holds_alternative(plot)) + { + std::get(plot).palette(name); + } + } + } + return *this; +} + +inline auto Figure::layout() -> LayoutSpecs& +{ + return m_layout; +} + +inline auto Figure::title(const std::string& title) -> Figure& +{ + m_title = title; + return *this; +} + +inline auto Figure::repr() const -> std::string +{ + std::stringstream script; + // Add multiplot commands +// if (m_layoutrows > 1 || m_layoutcols > 1) + { + gnuplot::multiplotcmd(script, m_layoutrows, m_layoutcols, m_title); + } + script << m_layout << std::endl; + for (const auto& row : m_plots) + { + for (const auto& plot : row) + { + script << std::visit(ReprPlotVisitor, plot); + } + } + // Close multiplot +// if (m_layoutrows > 1 || m_layoutcols > 1) + { + script << "unset multiplot" << std::endl; + } + return script.str(); +} + +inline auto Figure::saveplotdata() const -> void +{ + for (const auto& row : m_plots) + { + for (const auto& plot : row) + { + std::visit(SavePlotVisitor, plot); + } + } +} + +inline auto Figure::cleanup() const -> void +{ + for (const auto& row : m_plots) + { + for (const auto& plot : row) + { + std::visit(CleanupPlotVisitor, plot); + } + } +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Palettes.hpp b/src/cpp/3rdparty/sciplot/Palettes.hpp new file mode 100755 index 000000000..0caf79df6 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Palettes.hpp @@ -0,0 +1,87 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include + +namespace sciplot { + +/// Gnuplot color palettes for sciplot adapted from https://github.com/Gnuplotting/gnuplot-palettes +const std::map palettes = { + { "accent", "# line styles for ColorBrewer Accent\n# for use with qualitative/categorical data\n# provides 8 colors, 4 pale and 4 saturated\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#7FC97F' # pale green\nset style line 2 lt 1 lc rgb '#BEAED4' # pale purple\nset style line 3 lt 1 lc rgb '#FDC086' # pale orange\nset style line 4 lt 1 lc rgb '#FFFF99' # pale yellow\nset style line 5 lt 1 lc rgb '#386CB0' # blue\nset style line 6 lt 1 lc rgb '#F0027F' # magenta\nset style line 7 lt 1 lc rgb '#BF5B17' # brown\nset style line 8 lt 1 lc rgb '#666666' # grey\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#7FC97F',\\\n \t \t 1 '#BEAED4',\\\n\t\t 2 '#FDC086',\\\n\t\t 3 '#FFFF99',\\\n\t\t 4 '#386CB0',\\\n\t\t 5 '#F0027F',\\\n\t\t 6 '#BF5B17',\\\n\t\t 7 '#666666' )\n" }, + { "blues", "# line styles for ColorBrewer Blues\n# for use with sequential data\n# provides 8 blue colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#F7FBFF' # very light blue\nset style line 2 lt 1 lc rgb '#DEEBF7' # \nset style line 3 lt 1 lc rgb '#C6DBEF' # \nset style line 4 lt 1 lc rgb '#9ECAE1' # light blue\nset style line 5 lt 1 lc rgb '#6BAED6' # \nset style line 6 lt 1 lc rgb '#4292C6' # medium blue\nset style line 7 lt 1 lc rgb '#2171B5' #\nset style line 8 lt 1 lc rgb '#084594' # dark blue\n\n# palette\nset palette defined ( 0 '#F7FBFF',\\\n \t \t 1 '#DEEBF7',\\\n\t\t 2 '#C6DBEF',\\\n\t\t 3 '#9ECAE1',\\\n\t\t 4 '#6BAED6',\\\n\t\t 5 '#4292C6',\\\n\t\t 6 '#2171B5',\\\n\t\t 7 '#084594' )\n" }, + { "brbg", "# line styles for ColorBrewer BrBG\n# for use with divering data\n# provides 8 colors with brown low, white middle, and blue-green high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#8C510A' # dark brown\nset style line 2 lt 1 lc rgb '#BF812D' # medium brown\nset style line 3 lt 1 lc rgb '#DFC27D' # \nset style line 4 lt 1 lc rgb '#F6E8C3' # pale brown\nset style line 5 lt 1 lc rgb '#C7EAE5' # pale blue-green\nset style line 6 lt 1 lc rgb '#80CDC1' # \nset style line 7 lt 1 lc rgb '#35978F' # medium blue-green\nset style line 8 lt 1 lc rgb '#01665E' # dark blue-green\n\n# palette\nset palette defined ( 0 '#8C510A',\\\n \t \t 1 '#BF812D',\\\n\t\t 2 '#DFC27D',\\\n\t\t 3 '#F6E8C3',\\\n\t\t 4 '#C7EAE5',\\\n\t\t 5 '#80CDC1',\\\n\t\t 6 '#35978F',\\\n\t\t 7 '#01665E' )\n" }, + { "bugn", "# line styles for ColorBrewer BuGn\n# for use with sequential data\n# provides 8 blue-green colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#F7FCFD' # very light blue-green\nset style line 2 lt 1 lc rgb '#E5F5F9' # \nset style line 3 lt 1 lc rgb '#CCECE6' # \nset style line 4 lt 1 lc rgb '#99D8C9' # light blue-green\nset style line 5 lt 1 lc rgb '#66C2A4' # \nset style line 6 lt 1 lc rgb '#41AE76' # medium blue-green\nset style line 7 lt 1 lc rgb '#238B45' #\nset style line 8 lt 1 lc rgb '#005824' # dark blue-green\n\n# palette\nset palette defined ( 0 '#F7FCFD',\\\n \t \t 1 '#E5F5F9',\\\n\t\t 2 '#CCECE6',\\\n\t\t 3 '#99D8C9',\\\n\t\t 4 '#66C2A4',\\\n\t\t 5 '#41AE76',\\\n\t\t 6 '#238B45',\\\n\t\t 7 '#005824' )\n" }, + { "bupu", "# line styles for ColorBrewer BuPu\n# for use with sequential data\n# provides 8 blue-purple colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#F7FCFD' # very light blue-purple\nset style line 2 lt 1 lc rgb '#E0ECF4' # \nset style line 3 lt 1 lc rgb '#BFD3E6' # \nset style line 4 lt 1 lc rgb '#9EBCDA' # light blue-purple\nset style line 5 lt 1 lc rgb '#8C96C6' # \nset style line 6 lt 1 lc rgb '#8C6BB1' # medium blue-purple\nset style line 7 lt 1 lc rgb '#88419D' #\nset style line 8 lt 1 lc rgb '#6E016B' # dark blue-purple\n\n# palette\nset palette defined ( 0 '#F7FCFD',\\\n \t \t 1 '#E0ECF4',\\\n\t\t 2 '#BFD3E6',\\\n\t\t 3 '#9EBCDA',\\\n\t\t 4 '#8C96C6',\\\n\t\t 5 '#8C6BB1',\\\n\t\t 6 '#88419D',\\\n\t\t 7 '#6E016B' )\n" }, + { "chromajs", "# line styles for chromajs\n# see:\n# http://gka.github.io/palettes/#colors=lightyellow,orangered,deeppink,darkred|steps=7|bez=1|coL=1\n# https://vis4.net/blog/posts/mastering-multi-hued-color-scales/\n\n# line styles\nset style line 1 lt 1 lc rgb '#ffffe0' # light yellow\nset style line 2 lt 1 lc rgb '#ffdfb8' #\nset style line 3 lt 1 lc rgb '#ffbc94' # light orange\nset style line 4 lt 1 lc rgb '#ff9777' #\nset style line 5 lt 1 lc rgb '#ff6962' # light red\nset style line 6 lt 1 lc rgb '#ee4256' #\nset style line 7 lt 1 lc rgb '#d21f47' # red\nset style line 8 lt 1 lc rgb '#b0062c' #\nset style line 9 lt 1 lc rgb '#8b0000' # dark red\n\n# palette\nset palette maxcolors 9\nset palette defined ( 0 '#ffffe0',\\\n \t \t 1 '#ffdfb8',\\\n \t\t 2 '#ffbc94',\\\n\t\t 3 '#ff9777',\\\n\t\t 4 '#ff6962',\\\n\t\t 5 '#ee4256',\\\n\t\t 6 '#d21f47',\\\n\t\t 7 '#b0062c',\\\n 8 '#8b0000')\n" }, + { "dark2", "# line styles for ColorBrewer Dark2\n# for use with qualitative/categorical data\n# provides 8 dark colors based on Set2\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#1B9E77' # dark teal\nset style line 2 lt 1 lc rgb '#D95F02' # dark orange\nset style line 3 lt 1 lc rgb '#7570B3' # dark lilac\nset style line 4 lt 1 lc rgb '#E7298A' # dark magenta\nset style line 5 lt 1 lc rgb '#66A61E' # dark lime green\nset style line 6 lt 1 lc rgb '#E6AB02' # dark banana\nset style line 7 lt 1 lc rgb '#A6761D' # dark tan\nset style line 8 lt 1 lc rgb '#666666' # dark gray\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#1B9E77',\\\n \t \t 1 '#D95F02',\\\n\t\t 2 '#7570B3',\\\n\t\t 3 '#E7298A',\\\n\t\t 4 '#66A61E',\\\n\t\t 5 '#E6AB02',\\\n\t\t 6 '#A6761D',\\\n\t\t 7 '#666666' )\n" }, + { "gnbu", "# line styles for ColorBrewer GnBu\n# for use with sequential data\n# provides 8 green-blue colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#F7FCF0' # very light green-blue\nset style line 2 lt 1 lc rgb '#E0F3DB' # \nset style line 3 lt 1 lc rgb '#CCEBC5' # \nset style line 4 lt 1 lc rgb '#A8DDB5' # light green-blue\nset style line 5 lt 1 lc rgb '#7BCCC4' # \nset style line 6 lt 1 lc rgb '#4EB3D3' # medium green-blue\nset style line 7 lt 1 lc rgb '#2B8CBE' #\nset style line 8 lt 1 lc rgb '#08589E' # dark green-blue\n\n# palette\nset palette defined ( 0 '#F7FCF0',\\\n \t \t 1 '#E0F3DB',\\\n\t\t 2 '#CCEBC5',\\\n\t\t 3 '#A8DDB5',\\\n\t\t 4 '#7BCCC4',\\\n\t\t 5 '#4EB3D3',\\\n\t\t 6 '#2B8CBE',\\\n\t\t 7 '#08589E' )\n" }, + { "gnpu", "# line styles\nset style line 1 lt 1 lc rgb '#396353' # green\nset style line 2 lt 1 lc rgb '#0db14b' # \nset style line 3 lt 1 lc rgb '#6dc067' # \nset style line 4 lt 1 lc rgb '#abd69b' #\nset style line 5 lt 1 lc rgb '#daeac1' # \nset style line 6 lt 1 lc rgb '#dfcce4' #\nset style line 7 lt 1 lc rgb '#c7b2d6' #\nset style line 8 lt 1 lc rgb '#9474b4' #\nset style line 9 lt 1 lc rgb '#754098' #\nset style line 10 lt 1 lc rgb '#504971' # purple\n\n# palette\nset palette defined ( \\\n 1 '#396353', \\\n 2 '#0db14b', \\\n 3 '#6dc067', \\\n 4 '#abd69b', \\\n 5 '#daeac1', \\\n 6 '#dfcce4', \\\n 7 '#c7b2d6', \\\n 8 '#9474b4', \\\n 9 '#754098', \\\n 10 '#504971')\n" }, + { "greens", "# line styles for ColorBrewer Greens\n# for use with sequential data\n# provides 8 green colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#F7FCF5' # very light green\nset style line 2 lt 1 lc rgb '#E5F5E0' # \nset style line 3 lt 1 lc rgb '#C7E9C0' # \nset style line 4 lt 1 lc rgb '#A1D99B' # light green\nset style line 5 lt 1 lc rgb '#74C476' # \nset style line 6 lt 1 lc rgb '#41AB5D' # medium green\nset style line 7 lt 1 lc rgb '#238B45' #\nset style line 8 lt 1 lc rgb '#005A32' # dark green\n\n# palette\nset palette defined ( 0 '#F7FCF5',\\\n \t \t 1 '#E5F5E0',\\\n\t\t 2 '#C7E9C0',\\\n\t\t 3 '#A1D99B',\\\n\t\t 4 '#74C476',\\\n\t\t 5 '#41AB5D',\\\n\t\t 6 '#238B45',\\\n\t\t 7 '#005A32' )\n" }, + { "greys", "# line styles for ColorBrewer Greys\n# for use with sequential data\n# provides 8 grey colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFFFFF' # white\nset style line 2 lt 1 lc rgb '#F0F0F0' # \nset style line 3 lt 1 lc rgb '#D9D9D9' # \nset style line 4 lt 1 lc rgb '#BDBDBD' # light grey\nset style line 5 lt 1 lc rgb '#969696' # \nset style line 6 lt 1 lc rgb '#737373' # medium grey\nset style line 7 lt 1 lc rgb '#525252' #\nset style line 8 lt 1 lc rgb '#252525' # dark grey\n\n# palette\nset palette defined ( 0 '#FFFFFF',\\\n \t \t 1 '#F0F0F0',\\\n\t\t 2 '#D9D9D9',\\\n\t\t 3 '#BDBDBD',\\\n\t\t 4 '#969696',\\\n\t\t 5 '#737373',\\\n\t\t 6 '#525252',\\\n\t\t 7 '#252525' )\n" }, + { "inferno", "# New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,\n# and (in the case of viridis) Eric Firing.\n#\n# This file and the colormaps in it are released under the CC0 license /\n# public domain dedication. We would appreciate credit if you use or\n# redistribute these colormaps, but do not impose any legal restrictions.\n#\n# To the extent possible under law, the persons who associated CC0 with\n# mpl-colormaps have waived all copyright and related or neighboring rights\n# to mpl-colormaps.\n#\n# You should have received a copy of the CC0 legalcode along with this\n# work. If not, see .\n\n#https://github.com/BIDS/colormap/blob/master/colormaps.py\n\n\n# line styles\nset style line 1 lt 1 lc rgb '#000004' # black\nset style line 2 lt 1 lc rgb '#1f0c48' # dark purple\nset style line 3 lt 1 lc rgb '#550f6d' # dark purple\nset style line 4 lt 1 lc rgb '#88226a' # purple\nset style line 5 lt 1 lc rgb '#a83655' # red-magenta\nset style line 6 lt 1 lc rgb '#e35933' # red\nset style line 7 lt 1 lc rgb '#f9950a' # orange\nset style line 8 lt 1 lc rgb '#f8c932' # yellow-orange\nset style line 9 lt 1 lc rgb '#fcffa4' # light yellow\n\n\n# palette\nset palette defined (\\\n0 0.001462 0.000466 0.013866,\\\n1 0.002267 0.001270 0.018570,\\\n2 0.003299 0.002249 0.024239,\\\n3 0.004547 0.003392 0.030909,\\\n4 0.006006 0.004692 0.038558,\\\n5 0.007676 0.006136 0.046836,\\\n6 0.009561 0.007713 0.055143,\\\n7 0.011663 0.009417 0.063460,\\\n8 0.013995 0.011225 0.071862,\\\n9 0.016561 0.013136 0.080282,\\\n10 0.019373 0.015133 0.088767,\\\n11 0.022447 0.017199 0.097327,\\\n12 0.025793 0.019331 0.105930,\\\n13 0.029432 0.021503 0.114621,\\\n14 0.033385 0.023702 0.123397,\\\n15 0.037668 0.025921 0.132232,\\\n16 0.042253 0.028139 0.141141,\\\n17 0.046915 0.030324 0.150164,\\\n18 0.051644 0.032474 0.159254,\\\n19 0.056449 0.034569 0.168414,\\\n20 0.061340 0.036590 0.177642,\\\n21 0.066331 0.038504 0.186962,\\\n22 0.071429 0.040294 0.196354,\\\n23 0.076637 0.041905 0.205799,\\\n24 0.081962 0.043328 0.215289,\\\n25 0.087411 0.044556 0.224813,\\\n26 0.092990 0.045583 0.234358,\\\n27 0.098702 0.046402 0.243904,\\\n28 0.104551 0.047008 0.253430,\\\n29 0.110536 0.047399 0.262912,\\\n30 0.116656 0.047574 0.272321,\\\n31 0.122908 0.047536 0.281624,\\\n32 0.129285 0.047293 0.290788,\\\n33 0.135778 0.046856 0.299776,\\\n34 0.142378 0.046242 0.308553,\\\n35 0.149073 0.045468 0.317085,\\\n36 0.155850 0.044559 0.325338,\\\n37 0.162689 0.043554 0.333277,\\\n38 0.169575 0.042489 0.340874,\\\n39 0.176493 0.041402 0.348111,\\\n40 0.183429 0.040329 0.354971,\\\n41 0.190367 0.039309 0.361447,\\\n42 0.197297 0.038400 0.367535,\\\n43 0.204209 0.037632 0.373238,\\\n44 0.211095 0.037030 0.378563,\\\n45 0.217949 0.036615 0.383522,\\\n46 0.224763 0.036405 0.388129,\\\n47 0.231538 0.036405 0.392400,\\\n48 0.238273 0.036621 0.396353,\\\n49 0.244967 0.037055 0.400007,\\\n50 0.251620 0.037705 0.403378,\\\n51 0.258234 0.038571 0.406485,\\\n52 0.264810 0.039647 0.409345,\\\n53 0.271347 0.040922 0.411976,\\\n54 0.277850 0.042353 0.414392,\\\n55 0.284321 0.043933 0.416608,\\\n56 0.290763 0.045644 0.418637,\\\n57 0.297178 0.047470 0.420491,\\\n58 0.303568 0.049396 0.422182,\\\n59 0.309935 0.051407 0.423721,\\\n60 0.316282 0.053490 0.425116,\\\n61 0.322610 0.055634 0.426377,\\\n62 0.328921 0.057827 0.427511,\\\n63 0.335217 0.060060 0.428524,\\\n64 0.341500 0.062325 0.429425,\\\n65 0.347771 0.064616 0.430217,\\\n66 0.354032 0.066925 0.430906,\\\n67 0.360284 0.069247 0.431497,\\\n68 0.366529 0.071579 0.431994,\\\n69 0.372768 0.073915 0.432400,\\\n70 0.379001 0.076253 0.432719,\\\n71 0.385228 0.078591 0.432955,\\\n72 0.391453 0.080927 0.433109,\\\n73 0.397674 0.083257 0.433183,\\\n74 0.403894 0.085580 0.433179,\\\n75 0.410113 0.087896 0.433098,\\\n76 0.416331 0.090203 0.432943,\\\n77 0.422549 0.092501 0.432714,\\\n78 0.428768 0.094790 0.432412,\\\n79 0.434987 0.097069 0.432039,\\\n80 0.441207 0.099338 0.431594,\\\n81 0.447428 0.101597 0.431080,\\\n82 0.453651 0.103848 0.430498,\\\n83 0.459875 0.106089 0.429846,\\\n84 0.466100 0.108322 0.429125,\\\n85 0.472328 0.110547 0.428334,\\\n86 0.478558 0.112764 0.427475,\\\n87 0.484789 0.114974 0.426548,\\\n88 0.491022 0.117179 0.425552,\\\n89 0.497257 0.119379 0.424488,\\\n90 0.503493 0.121575 0.423356,\\\n91 0.509730 0.123769 0.422156,\\\n92 0.515967 0.125960 0.420887,\\\n93 0.522206 0.128150 0.419549,\\\n94 0.528444 0.130341 0.418142,\\\n95 0.534683 0.132534 0.416667,\\\n96 0.540920 0.134729 0.415123,\\\n97 0.547157 0.136929 0.413511,\\\n98 0.553392 0.139134 0.411829,\\\n99 0.559624 0.141346 0.410078,\\\n100 0.565854 0.143567 0.408258,\\\n101 0.572081 0.145797 0.406369,\\\n102 0.578304 0.148039 0.404411,\\\n103 0.584521 0.150294 0.402385,\\\n104 0.590734 0.152563 0.400290,\\\n105 0.596940 0.154848 0.398125,\\\n106 0.603139 0.157151 0.395891,\\\n107 0.609330 0.159474 0.393589,\\\n108 0.615513 0.161817 0.391219,\\\n109 0.621685 0.164184 0.388781,\\\n110 0.627847 0.166575 0.386276,\\\n111 0.633998 0.168992 0.383704,\\\n112 0.640135 0.171438 0.381065,\\\n113 0.646260 0.173914 0.378359,\\\n114 0.652369 0.176421 0.375586,\\\n115 0.658463 0.178962 0.372748,\\\n116 0.664540 0.181539 0.369846,\\\n117 0.670599 0.184153 0.366879,\\\n118 0.676638 0.186807 0.363849,\\\n119 0.682656 0.189501 0.360757,\\\n120 0.688653 0.192239 0.357603,\\\n121 0.694627 0.195021 0.354388,\\\n122 0.700576 0.197851 0.351113,\\\n123 0.706500 0.200728 0.347777,\\\n124 0.712396 0.203656 0.344383,\\\n125 0.718264 0.206636 0.340931,\\\n126 0.724103 0.209670 0.337424,\\\n127 0.729909 0.212759 0.333861,\\\n128 0.735683 0.215906 0.330245,\\\n129 0.741423 0.219112 0.326576,\\\n130 0.747127 0.222378 0.322856,\\\n131 0.752794 0.225706 0.319085,\\\n132 0.758422 0.229097 0.315266,\\\n133 0.764010 0.232554 0.311399,\\\n134 0.769556 0.236077 0.307485,\\\n135 0.775059 0.239667 0.303526,\\\n136 0.780517 0.243327 0.299523,\\\n137 0.785929 0.247056 0.295477,\\\n138 0.791293 0.250856 0.291390,\\\n139 0.796607 0.254728 0.287264,\\\n140 0.801871 0.258674 0.283099,\\\n141 0.807082 0.262692 0.278898,\\\n142 0.812239 0.266786 0.274661,\\\n143 0.817341 0.270954 0.270390,\\\n144 0.822386 0.275197 0.266085,\\\n145 0.827372 0.279517 0.261750,\\\n146 0.832299 0.283913 0.257383,\\\n147 0.837165 0.288385 0.252988,\\\n148 0.841969 0.292933 0.248564,\\\n149 0.846709 0.297559 0.244113,\\\n150 0.851384 0.302260 0.239636,\\\n151 0.855992 0.307038 0.235133,\\\n152 0.860533 0.311892 0.230606,\\\n153 0.865006 0.316822 0.226055,\\\n154 0.869409 0.321827 0.221482,\\\n155 0.873741 0.326906 0.216886,\\\n156 0.878001 0.332060 0.212268,\\\n157 0.882188 0.337287 0.207628,\\\n158 0.886302 0.342586 0.202968,\\\n159 0.890341 0.347957 0.198286,\\\n160 0.894305 0.353399 0.193584,\\\n161 0.898192 0.358911 0.188860,\\\n162 0.902003 0.364492 0.184116,\\\n163 0.905735 0.370140 0.179350,\\\n164 0.909390 0.375856 0.174563,\\\n165 0.912966 0.381636 0.169755,\\\n166 0.916462 0.387481 0.164924,\\\n167 0.919879 0.393389 0.160070,\\\n168 0.923215 0.399359 0.155193,\\\n169 0.926470 0.405389 0.150292,\\\n170 0.929644 0.411479 0.145367,\\\n171 0.932737 0.417627 0.140417,\\\n172 0.935747 0.423831 0.135440,\\\n173 0.938675 0.430091 0.130438,\\\n174 0.941521 0.436405 0.125409,\\\n175 0.944285 0.442772 0.120354,\\\n176 0.946965 0.449191 0.115272,\\\n177 0.949562 0.455660 0.110164,\\\n178 0.952075 0.462178 0.105031,\\\n179 0.954506 0.468744 0.099874,\\\n180 0.956852 0.475356 0.094695,\\\n181 0.959114 0.482014 0.089499,\\\n182 0.961293 0.488716 0.084289,\\\n183 0.963387 0.495462 0.079073,\\\n184 0.965397 0.502249 0.073859,\\\n185 0.967322 0.509078 0.068659,\\\n186 0.969163 0.515946 0.063488,\\\n187 0.970919 0.522853 0.058367,\\\n188 0.972590 0.529798 0.053324,\\\n189 0.974176 0.536780 0.048392,\\\n190 0.975677 0.543798 0.043618,\\\n191 0.977092 0.550850 0.039050,\\\n192 0.978422 0.557937 0.034931,\\\n193 0.979666 0.565057 0.031409,\\\n194 0.980824 0.572209 0.028508,\\\n195 0.981895 0.579392 0.026250,\\\n196 0.982881 0.586606 0.024661,\\\n197 0.983779 0.593849 0.023770,\\\n198 0.984591 0.601122 0.023606,\\\n199 0.985315 0.608422 0.024202,\\\n200 0.985952 0.615750 0.025592,\\\n201 0.986502 0.623105 0.027814,\\\n202 0.986964 0.630485 0.030908,\\\n203 0.987337 0.637890 0.034916,\\\n204 0.987622 0.645320 0.039886,\\\n205 0.987819 0.652773 0.045581,\\\n206 0.987926 0.660250 0.051750,\\\n207 0.987945 0.667748 0.058329,\\\n208 0.987874 0.675267 0.065257,\\\n209 0.987714 0.682807 0.072489,\\\n210 0.987464 0.690366 0.079990,\\\n211 0.987124 0.697944 0.087731,\\\n212 0.986694 0.705540 0.095694,\\\n213 0.986175 0.713153 0.103863,\\\n214 0.985566 0.720782 0.112229,\\\n215 0.984865 0.728427 0.120785,\\\n216 0.984075 0.736087 0.129527,\\\n217 0.983196 0.743758 0.138453,\\\n218 0.982228 0.751442 0.147565,\\\n219 0.981173 0.759135 0.156863,\\\n220 0.980032 0.766837 0.166353,\\\n221 0.978806 0.774545 0.176037,\\\n222 0.977497 0.782258 0.185923,\\\n223 0.976108 0.789974 0.196018,\\\n224 0.974638 0.797692 0.206332,\\\n225 0.973088 0.805409 0.216877,\\\n226 0.971468 0.813122 0.227658,\\\n227 0.969783 0.820825 0.238686,\\\n228 0.968041 0.828515 0.249972,\\\n229 0.966243 0.836191 0.261534,\\\n230 0.964394 0.843848 0.273391,\\\n231 0.962517 0.851476 0.285546,\\\n232 0.960626 0.859069 0.298010,\\\n233 0.958720 0.866624 0.310820,\\\n234 0.956834 0.874129 0.323974,\\\n235 0.954997 0.881569 0.337475,\\\n236 0.953215 0.888942 0.351369,\\\n237 0.951546 0.896226 0.365627,\\\n238 0.950018 0.903409 0.380271,\\\n239 0.948683 0.910473 0.395289,\\\n240 0.947594 0.917399 0.410665,\\\n241 0.946809 0.924168 0.426373,\\\n242 0.946392 0.930761 0.442367,\\\n243 0.946403 0.937159 0.458592,\\\n244 0.946903 0.943348 0.474970,\\\n245 0.947937 0.949318 0.491426,\\\n246 0.949545 0.955063 0.507860,\\\n247 0.951740 0.960587 0.524203,\\\n248 0.954529 0.965896 0.540361,\\\n249 0.957896 0.971003 0.556275,\\\n250 0.961812 0.975924 0.571925,\\\n251 0.966249 0.980678 0.587206,\\\n252 0.971162 0.985282 0.602154,\\\n253 0.976511 0.989753 0.616760,\\\n254 0.982257 0.994109 0.631017,\\\n255 0.988362 0.998364 0.644924)\n" }, + { "jet", "# MATLAB jet color pallete\n\n# line styles\nset style line 1 lt 1 lc rgb '#000080' #\nset style line 2 lt 1 lc rgb '#0000ff' #\nset style line 3 lt 1 lc rgb '#0080ff' #\nset style line 4 lt 1 lc rgb '#00ffff' #\nset style line 5 lt 1 lc rgb '#80ff80' #\nset style line 6 lt 1 lc rgb '#ffff00' #\nset style line 7 lt 1 lc rgb '#ff8000' #\nset style line 8 lt 1 lc rgb '#ff0000' #\nset style line 9 lt 1 lc rgb '#800000' #\n# line style used together with jet (<2014b)\nset style line 11 lt 1 lc rgb '#0000ff' # blue\nset style line 12 lt 1 lc rgb '#007f00' # green\nset style line 13 lt 1 lc rgb '#ff0000' # red\nset style line 14 lt 1 lc rgb '#00bfbf' # cyan\nset style line 15 lt 1 lc rgb '#bf00bf' # pink\nset style line 16 lt 1 lc rgb '#bfbf00' # yellow\nset style line 17 lt 1 lc rgb '#3f3f3f' # black\n\n# palette\nset palette defined (0 0.0 0.0 0.5, \\\n 1 0.0 0.0 1.0, \\\n 2 0.0 0.5 1.0, \\\n 3 0.0 1.0 1.0, \\\n 4 0.5 1.0 0.5, \\\n 5 1.0 1.0 0.0, \\\n 6 1.0 0.5 0.0, \\\n 7 1.0 0.0 0.0, \\\n 8 0.5 0.0 0.0 )\n\n" }, + { "magma", "\n# New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,\n# and (in the case of viridis) Eric Firing.\n#\n# This file and the colormaps in it are released under the CC0 license /\n# public domain dedication. We would appreciate credit if you use or\n# redistribute these colormaps, but do not impose any legal restrictions.\n#\n# To the extent possible under law, the persons who associated CC0 with\n# mpl-colormaps have waived all copyright and related or neighboring rights\n# to mpl-colormaps.\n#\n# You should have received a copy of the CC0 legalcode along with this\n# work. If not, see .\n\n#https://github.com/BIDS/colormap/blob/master/colormaps.py\n\n\n# line styles\nset style line 1 lt 1 lc rgb '#000004' # black\nset style line 2 lt 1 lc rgb '#1c1044' # dark blue\nset style line 3 lt 1 lc rgb '#4f127b' # dark purple\nset style line 4 lt 1 lc rgb '#812581' # purple\nset style line 5 lt 1 lc rgb '#b5367a' # magenta\nset style line 6 lt 1 lc rgb '#e55964' # light red\nset style line 7 lt 1 lc rgb '#fb8761' # orange\nset style line 8 lt 1 lc rgb '#fec287' # light orange\nset style line 9 lt 1 lc rgb '#fbfdbf' # light yellow\n\n\n# palette\nset palette defined (\\\n0 0.001462 0.000466 0.013866,\\\n1 0.002258 0.001295 0.018331,\\\n2 0.003279 0.002305 0.023708,\\\n3 0.004512 0.003490 0.029965,\\\n4 0.005950 0.004843 0.037130,\\\n5 0.007588 0.006356 0.044973,\\\n6 0.009426 0.008022 0.052844,\\\n7 0.011465 0.009828 0.060750,\\\n8 0.013708 0.011771 0.068667,\\\n9 0.016156 0.013840 0.076603,\\\n10 0.018815 0.016026 0.084584,\\\n11 0.021692 0.018320 0.092610,\\\n12 0.024792 0.020715 0.100676,\\\n13 0.028123 0.023201 0.108787,\\\n14 0.031696 0.025765 0.116965,\\\n15 0.035520 0.028397 0.125209,\\\n16 0.039608 0.031090 0.133515,\\\n17 0.043830 0.033830 0.141886,\\\n18 0.048062 0.036607 0.150327,\\\n19 0.052320 0.039407 0.158841,\\\n20 0.056615 0.042160 0.167446,\\\n21 0.060949 0.044794 0.176129,\\\n22 0.065330 0.047318 0.184892,\\\n23 0.069764 0.049726 0.193735,\\\n24 0.074257 0.052017 0.202660,\\\n25 0.078815 0.054184 0.211667,\\\n26 0.083446 0.056225 0.220755,\\\n27 0.088155 0.058133 0.229922,\\\n28 0.092949 0.059904 0.239164,\\\n29 0.097833 0.061531 0.248477,\\\n30 0.102815 0.063010 0.257854,\\\n31 0.107899 0.064335 0.267289,\\\n32 0.113094 0.065492 0.276784,\\\n33 0.118405 0.066479 0.286321,\\\n34 0.123833 0.067295 0.295879,\\\n35 0.129380 0.067935 0.305443,\\\n36 0.135053 0.068391 0.315000,\\\n37 0.140858 0.068654 0.324538,\\\n38 0.146785 0.068738 0.334011,\\\n39 0.152839 0.068637 0.343404,\\\n40 0.159018 0.068354 0.352688,\\\n41 0.165308 0.067911 0.361816,\\\n42 0.171713 0.067305 0.370771,\\\n43 0.178212 0.066576 0.379497,\\\n44 0.184801 0.065732 0.387973,\\\n45 0.191460 0.064818 0.396152,\\\n46 0.198177 0.063862 0.404009,\\\n47 0.204935 0.062907 0.411514,\\\n48 0.211718 0.061992 0.418647,\\\n49 0.218512 0.061158 0.425392,\\\n50 0.225302 0.060445 0.431742,\\\n51 0.232077 0.059889 0.437695,\\\n52 0.238826 0.059517 0.443256,\\\n53 0.245543 0.059352 0.448436,\\\n54 0.252220 0.059415 0.453248,\\\n55 0.258857 0.059706 0.457710,\\\n56 0.265447 0.060237 0.461840,\\\n57 0.271994 0.060994 0.465660,\\\n58 0.278493 0.061978 0.469190,\\\n59 0.284951 0.063168 0.472451,\\\n60 0.291366 0.064553 0.475462,\\\n61 0.297740 0.066117 0.478243,\\\n62 0.304081 0.067835 0.480812,\\\n63 0.310382 0.069702 0.483186,\\\n64 0.316654 0.071690 0.485380,\\\n65 0.322899 0.073782 0.487408,\\\n66 0.329114 0.075972 0.489287,\\\n67 0.335308 0.078236 0.491024,\\\n68 0.341482 0.080564 0.492631,\\\n69 0.347636 0.082946 0.494121,\\\n70 0.353773 0.085373 0.495501,\\\n71 0.359898 0.087831 0.496778,\\\n72 0.366012 0.090314 0.497960,\\\n73 0.372116 0.092816 0.499053,\\\n74 0.378211 0.095332 0.500067,\\\n75 0.384299 0.097855 0.501002,\\\n76 0.390384 0.100379 0.501864,\\\n77 0.396467 0.102902 0.502658,\\\n78 0.402548 0.105420 0.503386,\\\n79 0.408629 0.107930 0.504052,\\\n80 0.414709 0.110431 0.504662,\\\n81 0.420791 0.112920 0.505215,\\\n82 0.426877 0.115395 0.505714,\\\n83 0.432967 0.117855 0.506160,\\\n84 0.439062 0.120298 0.506555,\\\n85 0.445163 0.122724 0.506901,\\\n86 0.451271 0.125132 0.507198,\\\n87 0.457386 0.127522 0.507448,\\\n88 0.463508 0.129893 0.507652,\\\n89 0.469640 0.132245 0.507809,\\\n90 0.475780 0.134577 0.507921,\\\n91 0.481929 0.136891 0.507989,\\\n92 0.488088 0.139186 0.508011,\\\n93 0.494258 0.141462 0.507988,\\\n94 0.500438 0.143719 0.507920,\\\n95 0.506629 0.145958 0.507806,\\\n96 0.512831 0.148179 0.507648,\\\n97 0.519045 0.150383 0.507443,\\\n98 0.525270 0.152569 0.507192,\\\n99 0.531507 0.154739 0.506895,\\\n100 0.537755 0.156894 0.506551,\\\n101 0.544015 0.159033 0.506159,\\\n102 0.550287 0.161158 0.505719,\\\n103 0.556571 0.163269 0.505230,\\\n104 0.562866 0.165368 0.504692,\\\n105 0.569172 0.167454 0.504105,\\\n106 0.575490 0.169530 0.503466,\\\n107 0.581819 0.171596 0.502777,\\\n108 0.588158 0.173652 0.502035,\\\n109 0.594508 0.175701 0.501241,\\\n110 0.600868 0.177743 0.500394,\\\n111 0.607238 0.179779 0.499492,\\\n112 0.613617 0.181811 0.498536,\\\n113 0.620005 0.183840 0.497524,\\\n114 0.626401 0.185867 0.496456,\\\n115 0.632805 0.187893 0.495332,\\\n116 0.639216 0.189921 0.494150,\\\n117 0.645633 0.191952 0.492910,\\\n118 0.652056 0.193986 0.491611,\\\n119 0.658483 0.196027 0.490253,\\\n120 0.664915 0.198075 0.488836,\\\n121 0.671349 0.200133 0.487358,\\\n122 0.677786 0.202203 0.485819,\\\n123 0.684224 0.204286 0.484219,\\\n124 0.690661 0.206384 0.482558,\\\n125 0.697098 0.208501 0.480835,\\\n126 0.703532 0.210638 0.479049,\\\n127 0.709962 0.212797 0.477201,\\\n128 0.716387 0.214982 0.475290,\\\n129 0.722805 0.217194 0.473316,\\\n130 0.729216 0.219437 0.471279,\\\n131 0.735616 0.221713 0.469180,\\\n132 0.742004 0.224025 0.467018,\\\n133 0.748378 0.226377 0.464794,\\\n134 0.754737 0.228772 0.462509,\\\n135 0.761077 0.231214 0.460162,\\\n136 0.767398 0.233705 0.457755,\\\n137 0.773695 0.236249 0.455289,\\\n138 0.779968 0.238851 0.452765,\\\n139 0.786212 0.241514 0.450184,\\\n140 0.792427 0.244242 0.447543,\\\n141 0.798608 0.247040 0.444848,\\\n142 0.804752 0.249911 0.442102,\\\n143 0.810855 0.252861 0.439305,\\\n144 0.816914 0.255895 0.436461,\\\n145 0.822926 0.259016 0.433573,\\\n146 0.828886 0.262229 0.430644,\\\n147 0.834791 0.265540 0.427671,\\\n148 0.840636 0.268953 0.424666,\\\n149 0.846416 0.272473 0.421631,\\\n150 0.852126 0.276106 0.418573,\\\n151 0.857763 0.279857 0.415496,\\\n152 0.863320 0.283729 0.412403,\\\n153 0.868793 0.287728 0.409303,\\\n154 0.874176 0.291859 0.406205,\\\n155 0.879464 0.296125 0.403118,\\\n156 0.884651 0.300530 0.400047,\\\n157 0.889731 0.305079 0.397002,\\\n158 0.894700 0.309773 0.393995,\\\n159 0.899552 0.314616 0.391037,\\\n160 0.904281 0.319610 0.388137,\\\n161 0.908884 0.324755 0.385308,\\\n162 0.913354 0.330052 0.382563,\\\n163 0.917689 0.335500 0.379915,\\\n164 0.921884 0.341098 0.377376,\\\n165 0.925937 0.346844 0.374959,\\\n166 0.929845 0.352734 0.372677,\\\n167 0.933606 0.358764 0.370541,\\\n168 0.937221 0.364929 0.368567,\\\n169 0.940687 0.371224 0.366762,\\\n170 0.944006 0.377643 0.365136,\\\n171 0.947180 0.384178 0.363701,\\\n172 0.950210 0.390820 0.362468,\\\n173 0.953099 0.397563 0.361438,\\\n174 0.955849 0.404400 0.360619,\\\n175 0.958464 0.411324 0.360014,\\\n176 0.960949 0.418323 0.359630,\\\n177 0.963310 0.425390 0.359469,\\\n178 0.965549 0.432519 0.359529,\\\n179 0.967671 0.439703 0.359810,\\\n180 0.969680 0.446936 0.360311,\\\n181 0.971582 0.454210 0.361030,\\\n182 0.973381 0.461520 0.361965,\\\n183 0.975082 0.468861 0.363111,\\\n184 0.976690 0.476226 0.364466,\\\n185 0.978210 0.483612 0.366025,\\\n186 0.979645 0.491014 0.367783,\\\n187 0.981000 0.498428 0.369734,\\\n188 0.982279 0.505851 0.371874,\\\n189 0.983485 0.513280 0.374198,\\\n190 0.984622 0.520713 0.376698,\\\n191 0.985693 0.528148 0.379371,\\\n192 0.986700 0.535582 0.382210,\\\n193 0.987646 0.543015 0.385210,\\\n194 0.988533 0.550446 0.388365,\\\n195 0.989363 0.557873 0.391671,\\\n196 0.990138 0.565296 0.395122,\\\n197 0.990871 0.572706 0.398714,\\\n198 0.991558 0.580107 0.402441,\\\n199 0.992196 0.587502 0.406299,\\\n200 0.992785 0.594891 0.410283,\\\n201 0.993326 0.602275 0.414390,\\\n202 0.993834 0.609644 0.418613,\\\n203 0.994309 0.616999 0.422950,\\\n204 0.994738 0.624350 0.427397,\\\n205 0.995122 0.631696 0.431951,\\\n206 0.995480 0.639027 0.436607,\\\n207 0.995810 0.646344 0.441361,\\\n208 0.996096 0.653659 0.446213,\\\n209 0.996341 0.660969 0.451160,\\\n210 0.996580 0.668256 0.456192,\\\n211 0.996775 0.675541 0.461314,\\\n212 0.996925 0.682828 0.466526,\\\n213 0.997077 0.690088 0.471811,\\\n214 0.997186 0.697349 0.477182,\\\n215 0.997254 0.704611 0.482635,\\\n216 0.997325 0.711848 0.488154,\\\n217 0.997351 0.719089 0.493755,\\\n218 0.997351 0.726324 0.499428,\\\n219 0.997341 0.733545 0.505167,\\\n220 0.997285 0.740772 0.510983,\\\n221 0.997228 0.747981 0.516859,\\\n222 0.997138 0.755190 0.522806,\\\n223 0.997019 0.762398 0.528821,\\\n224 0.996898 0.769591 0.534892,\\\n225 0.996727 0.776795 0.541039,\\\n226 0.996571 0.783977 0.547233,\\\n227 0.996369 0.791167 0.553499,\\\n228 0.996162 0.798348 0.559820,\\\n229 0.995932 0.805527 0.566202,\\\n230 0.995680 0.812706 0.572645,\\\n231 0.995424 0.819875 0.579140,\\\n232 0.995131 0.827052 0.585701,\\\n233 0.994851 0.834213 0.592307,\\\n234 0.994524 0.841387 0.598983,\\\n235 0.994222 0.848540 0.605696,\\\n236 0.993866 0.855711 0.612482,\\\n237 0.993545 0.862859 0.619299,\\\n238 0.993170 0.870024 0.626189,\\\n239 0.992831 0.877168 0.633109,\\\n240 0.992440 0.884330 0.640099,\\\n241 0.992089 0.891470 0.647116,\\\n242 0.991688 0.898627 0.654202,\\\n243 0.991332 0.905763 0.661309,\\\n244 0.990930 0.912915 0.668481,\\\n245 0.990570 0.920049 0.675675,\\\n246 0.990175 0.927196 0.682926,\\\n247 0.989815 0.934329 0.690198,\\\n248 0.989434 0.941470 0.697519,\\\n249 0.989077 0.948604 0.704863,\\\n250 0.988717 0.955742 0.712242,\\\n251 0.988367 0.962878 0.719649,\\\n252 0.988033 0.970012 0.727077,\\\n253 0.987691 0.977154 0.734536,\\\n254 0.987387 0.984288 0.742002,\\\n255 0.987053 0.991438 0.749504)\n" }, + { "matlab", "# Matlab color map parula, see:\n# http://www.mathworks.de/products/matlab/matlab-graphics/#new_look_for_matlab_graphics\n\n# New default Matlab line colors, introduced together with parula (2014b)\nset style line 1 lt 1 lc rgb '#0072bd' # blue\nset style line 2 lt 1 lc rgb '#d95319' # orange\nset style line 3 lt 1 lc rgb '#edb120' # yellow\nset style line 4 lt 1 lc rgb '#7e2f8e' # purple\nset style line 5 lt 1 lc rgb '#77ac30' # green\nset style line 6 lt 1 lc rgb '#4dbeee' # light-blue\nset style line 7 lt 1 lc rgb '#a2142f' # red\n\n# palette\nset palette defined (\\\n 0 0.2081 0.1663 0.5292,\\\n 1 0.2116 0.1898 0.5777,\\\n 2 0.2123 0.2138 0.6270,\\\n 3 0.2081 0.2386 0.6771,\\\n 4 0.1959 0.2645 0.7279,\\\n 5 0.1707 0.2919 0.7792,\\\n 6 0.1253 0.3242 0.8303,\\\n 7 0.0591 0.3598 0.8683,\\\n 8 0.0117 0.3875 0.8820,\\\n 9 0.0060 0.4086 0.8828,\\\n10 0.0165 0.4266 0.8786,\\\n11 0.0329 0.4430 0.8720,\\\n12 0.0498 0.4586 0.8641,\\\n13 0.0629 0.4737 0.8554,\\\n14 0.0723 0.4887 0.8467,\\\n15 0.0779 0.5040 0.8384,\\\n16 0.0793 0.5200 0.8312,\\\n17 0.0749 0.5375 0.8263,\\\n18 0.0641 0.5570 0.8240,\\\n19 0.0488 0.5772 0.8228,\\\n20 0.0343 0.5966 0.8199,\\\n21 0.0265 0.6137 0.8135,\\\n22 0.0239 0.6287 0.8038,\\\n23 0.0231 0.6418 0.7913,\\\n24 0.0228 0.6535 0.7768,\\\n25 0.0267 0.6642 0.7607,\\\n26 0.0384 0.6743 0.7436,\\\n27 0.0590 0.6838 0.7254,\\\n28 0.0843 0.6928 0.7062,\\\n29 0.1133 0.7015 0.6859,\\\n30 0.1453 0.7098 0.6646,\\\n31 0.1801 0.7177 0.6424,\\\n32 0.2178 0.7250 0.6193,\\\n33 0.2586 0.7317 0.5954,\\\n34 0.3022 0.7376 0.5712,\\\n35 0.3482 0.7424 0.5473,\\\n36 0.3953 0.7459 0.5244,\\\n37 0.4420 0.7481 0.5033,\\\n38 0.4871 0.7491 0.4840,\\\n39 0.5300 0.7491 0.4661,\\\n40 0.5709 0.7485 0.4494,\\\n41 0.6099 0.7473 0.4337,\\\n42 0.6473 0.7456 0.4188,\\\n43 0.6834 0.7435 0.4044,\\\n44 0.7184 0.7411 0.3905,\\\n45 0.7525 0.7384 0.3768,\\\n46 0.7858 0.7356 0.3633,\\\n47 0.8185 0.7327 0.3498,\\\n48 0.8507 0.7299 0.3360,\\\n49 0.8824 0.7274 0.3217,\\\n50 0.9139 0.7258 0.3063,\\\n51 0.9450 0.7261 0.2886,\\\n52 0.9739 0.7314 0.2666,\\\n53 0.9938 0.7455 0.2403,\\\n54 0.9990 0.7653 0.2164,\\\n55 0.9955 0.7861 0.1967,\\\n56 0.9880 0.8066 0.1794,\\\n57 0.9789 0.8271 0.1633,\\\n58 0.9697 0.8481 0.1475,\\\n59 0.9626 0.8705 0.1309,\\\n60 0.9589 0.8949 0.1132,\\\n61 0.9598 0.9218 0.0948,\\\n62 0.9661 0.9514 0.0755,\\\n63 0.9763 0.9831 0.0538)" }, + { "moreland", "# Blue/Red color pallete after Moreland (2009)\n# http://www.sandia.gov/~kmorel/documents/ColorMaps/\n# http://bastian.rieck.ru/blog/posts/2012/gnuplot_better_colour_palettes/\n\n# line styles\nset style line 1 lt 1 lc rgb '#3b4cc0' #\nset style line 2 lt 1 lc rgb '#688aef' #\nset style line 3 lt 1 lc rgb '#99baff' #\nset style line 4 lt 1 lc rgb '#c9d8ef' #\nset style line 5 lt 1 lc rgb '#edd1c2' #\nset style line 6 lt 1 lc rgb '#f7a789' #\nset style line 7 lt 1 lc rgb '#e36a53' #\nset style line 8 lt 1 lc rgb '#b40426' #\n\n# palette\n# TODO: check if the short version gives the same results\nset palette defined (\\\n0 0.2298057 0.298717966 0.753683153,\\\n0.00390625 0.234299935 0.305559204 0.759874796,\\\n0.0078125 0.238810063 0.312388385 0.766005866,\\\n0.01171875 0.243336663 0.319205292 0.772075394,\\\n0.015625 0.247880265 0.326009656 0.778082421,\\\n0.01953125 0.25244136 0.332801165 0.784026001,\\\n0.0234375 0.257020396 0.339579464 0.789905199,\\\n0.02734375 0.261617779 0.346344164 0.79571909,\\\n0.03125 0.26623388 0.353094838 0.801466763,\\\n0.03515625 0.270869029 0.359831032 0.807147315,\\\n0.0390625 0.275523523 0.36655226 0.812759858,\\\n0.04296875 0.28019762 0.373258014 0.818303516,\\\n0.046875 0.284891546 0.379947761 0.823777422,\\\n0.05078125 0.289605495 0.386620945 0.829180725,\\\n0.0546875 0.294339624 0.393276993 0.834512584,\\\n0.05859375 0.299094064 0.399915313 0.839772171,\\\n0.0625 0.30386891 0.406535296 0.84495867,\\\n0.06640625 0.308664231 0.413136319 0.850071279,\\\n0.0703125 0.313480065 0.419717745 0.855109207,\\\n0.07421875 0.318316422 0.426278924 0.860071679,\\\n0.078125 0.323173283 0.432819194 0.864957929,\\\n0.08203125 0.328050603 0.439337884 0.869767207,\\\n0.0859375 0.332948312 0.445834313 0.874498775,\\\n0.08984375 0.337866311 0.45230779 0.87915191,\\\n0.09375 0.342804478 0.458757618 0.883725899,\\\n0.09765625 0.347762667 0.465183092 0.888220047,\\\n0.1015625 0.352740705 0.471583499 0.892633669,\\\n0.10546875 0.357738399 0.477958123 0.896966095,\\\n0.109375 0.362755532 0.484306241 0.90121667,\\\n0.11328125 0.367791863 0.490627125 0.905384751,\\\n0.1171875 0.372847134 0.496920043 0.909469711,\\\n0.12109375 0.37792106 0.503184261 0.913470934,\\\n0.125 0.38301334 0.50941904 0.917387822,\\\n0.12890625 0.38812365 0.515623638 0.921219788,\\\n0.1328125 0.39325165 0.521797312 0.924966262,\\\n0.13671875 0.398396976 0.527939316 0.928626686,\\\n0.140625 0.40355925 0.534048902 0.932200518,\\\n0.14453125 0.408738074 0.540125323 0.93568723,\\\n0.1484375 0.413933033 0.546167829 0.939086309,\\\n0.15234375 0.419143694 0.552175668 0.942397257,\\\n0.15625 0.424369608 0.558148092 0.945619588,\\\n0.16015625 0.429610311 0.564084349 0.948752835,\\\n0.1640625 0.434865321 0.56998369 0.951796543,\\\n0.16796875 0.440134144 0.575845364 0.954750272,\\\n0.171875 0.445416268 0.581668623 0.957613599,\\\n0.17578125 0.450711169 0.587452719 0.960386113,\\\n0.1796875 0.456018308 0.593196905 0.96306742,\\\n0.18359375 0.461337134 0.598900436 0.96565714,\\\n0.1875 0.46666708 0.604562568 0.968154911,\\\n0.19140625 0.472007569 0.61018256 0.970560381,\\\n0.1953125 0.477358011 0.615759672 0.972873218,\\\n0.19921875 0.482717804 0.621293167 0.975093102,\\\n0.203125 0.488086336 0.626782311 0.97721973,\\\n0.20703125 0.493462982 0.632226371 0.979252813,\\\n0.2109375 0.498847107 0.637624618 0.981192078,\\\n0.21484375 0.504238066 0.642976326 0.983037268,\\\n0.21875 0.509635204 0.648280772 0.98478814,\\\n0.22265625 0.515037856 0.653537236 0.986444467,\\\n0.2265625 0.520445349 0.658745003 0.988006036,\\\n0.23046875 0.525857 0.66390336 0.989472652,\\\n0.234375 0.531272118 0.669011598 0.990844132,\\\n0.23828125 0.536690004 0.674069012 0.99212031,\\\n0.2421875 0.542109949 0.679074903 0.993301037,\\\n0.24609375 0.54753124 0.684028574 0.994386177,\\\n0.25 0.552953156 0.688929332 0.995375608,\\\n0.25390625 0.558374965 0.693776492 0.996269227,\\\n0.2578125 0.563795935 0.698569369 0.997066945,\\\n0.26171875 0.569215322 0.703307287 0.997768685,\\\n0.265625 0.574632379 0.707989572 0.99837439,\\\n0.26953125 0.580046354 0.712615557 0.998884016,\\\n0.2734375 0.585456486 0.717184578 0.999297533,\\\n0.27734375 0.590862011 0.721695979 0.999614929,\\\n0.28125 0.596262162 0.726149107 0.999836203,\\\n0.28515625 0.601656165 0.730543315 0.999961374,\\\n0.2890625 0.607043242 0.734877964 0.999990472,\\\n0.29296875 0.61242261 0.739152418 0.999923544,\\\n0.296875 0.617793485 0.743366047 0.999760652,\\\n0.30078125 0.623155076 0.747518228 0.999501871,\\\n0.3046875 0.628506592 0.751608345 0.999147293,\\\n0.30859375 0.633847237 0.755635786 0.998697024,\\\n0.3125 0.639176211 0.759599947 0.998151185,\\\n0.31640625 0.644492714 0.763500228 0.99750991,\\\n0.3203125 0.649795942 0.767336039 0.996773351,\\\n0.32421875 0.655085089 0.771106793 0.995941671,\\\n0.328125 0.660359348 0.774811913 0.995015049,\\\n0.33203125 0.665617908 0.778450826 0.993993679,\\\n0.3359375 0.670859959 0.782022968 0.992877768,\\\n0.33984375 0.676084688 0.78552778 0.991667539,\\\n0.34375 0.681291281 0.788964712 0.990363227,\\\n0.34765625 0.686478925 0.792333219 0.988965083,\\\n0.3515625 0.691646803 0.795632765 0.987473371,\\\n0.35546875 0.696794099 0.798862821 0.985888369,\\\n0.359375 0.701919999 0.802022864 0.984210369,\\\n0.36328125 0.707023684 0.805112381 0.982439677,\\\n0.3671875 0.712104339 0.808130864 0.980576612,\\\n0.37109375 0.717161148 0.811077814 0.978621507,\\\n0.375 0.722193294 0.813952739 0.976574709,\\\n0.37890625 0.727199962 0.816755156 0.974436577,\\\n0.3828125 0.732180337 0.81948459 0.972207484,\\\n0.38671875 0.737133606 0.82214057 0.969887816,\\\n0.390625 0.742058956 0.824722639 0.967477972,\\\n0.39453125 0.746955574 0.827230344 0.964978364,\\\n0.3984375 0.751822652 0.829663241 0.962389418,\\\n0.40234375 0.756659379 0.832020895 0.959711569,\\\n0.40625 0.761464949 0.834302879 0.956945269,\\\n0.41015625 0.766238556 0.836508774 0.95409098,\\\n0.4140625 0.770979397 0.838638169 0.951149176,\\\n0.41796875 0.775686671 0.840690662 0.948120345,\\\n0.421875 0.780359577 0.842665861 0.945004985,\\\n0.42578125 0.78499732 0.84456338 0.941803607,\\\n0.4296875 0.789599105 0.846382843 0.938516733,\\\n0.43359375 0.79416414 0.848123884 0.935144898,\\\n0.4375 0.798691636 0.849786142 0.931688648,\\\n0.44140625 0.803180808 0.85136927 0.928148539,\\\n0.4453125 0.807630872 0.852872925 0.92452514,\\\n0.44921875 0.812041048 0.854296776 0.92081903,\\\n0.453125 0.81641056 0.855640499 0.917030798,\\\n0.45703125 0.820738635 0.856903782 0.913161047,\\\n0.4609375 0.825024503 0.85808632 0.909210387,\\\n0.46484375 0.829267397 0.859187816 0.90517944,\\\n0.46875 0.833466556 0.860207984 0.901068838,\\\n0.47265625 0.837621221 0.861146547 0.896879224,\\\n0.4765625 0.841730637 0.862003236 0.892611249,\\\n0.48046875 0.845794055 0.862777795 0.888265576,\\\n0.484375 0.849810727 0.863469972 0.883842876,\\\n0.48828125 0.853779913 0.864079527 0.87934383,\\\n0.4921875 0.857700874 0.864606232 0.874769128,\\\n0.49609375 0.861572878 0.865049863 0.870119469,\\\n0.5 0.865395197 0.86541021 0.865395561,\\\n0.50390625 0.86977749 0.863633958 0.859948576,\\\n0.5078125 0.874064226 0.861776352 0.854466231,\\\n0.51171875 0.878255583 0.859837644 0.848949435,\\\n0.515625 0.882351728 0.857818097 0.843399101,\\\n0.51953125 0.886352818 0.85571798 0.837816138,\\\n0.5234375 0.890259 0.853537573 0.832201453,\\\n0.52734375 0.89407041 0.851277164 0.826555954,\\\n0.53125 0.897787179 0.848937047 0.820880546,\\\n0.53515625 0.901409427 0.846517528 0.815176131,\\\n0.5390625 0.904937269 0.844018919 0.809443611,\\\n0.54296875 0.908370816 0.841441541 0.803683885,\\\n0.546875 0.911710171 0.838785722 0.79789785,\\\n0.55078125 0.914955433 0.836051799 0.792086401,\\\n0.5546875 0.918106696 0.833240115 0.786250429,\\\n0.55859375 0.921164054 0.830351023 0.780390824,\\\n0.5625 0.924127593 0.827384882 0.774508472,\\\n0.56640625 0.926997401 0.824342058 0.768604257,\\\n0.5703125 0.929773562 0.821222926 0.76267906,\\\n0.57421875 0.932456159 0.818027865 0.756733758,\\\n0.578125 0.935045272 0.814757264 0.750769226,\\\n0.58203125 0.937540984 0.811411517 0.744786333,\\\n0.5859375 0.939943375 0.807991025 0.738785947,\\\n0.58984375 0.942252526 0.804496196 0.732768931,\\\n0.59375 0.944468518 0.800927443 0.726736146,\\\n0.59765625 0.946591434 0.797285187 0.720688446,\\\n0.6015625 0.948621357 0.793569853 0.714626683,\\\n0.60546875 0.950558373 0.789781872 0.708551706,\\\n0.609375 0.952402567 0.785921682 0.702464356,\\\n0.61328125 0.954154029 0.781989725 0.696365473,\\\n0.6171875 0.955812849 0.777986449 0.690255891,\\\n0.62109375 0.957379123 0.773912305 0.68413644,\\\n0.625 0.958852946 0.769767752 0.678007945,\\\n0.62890625 0.960234418 0.765553251 0.671871226,\\\n0.6328125 0.961523642 0.761269267 0.665727098,\\\n0.63671875 0.962720725 0.756916272 0.659576372,\\\n0.640625 0.963825777 0.752494738 0.653419853,\\\n0.64453125 0.964838913 0.748005143 0.647258341,\\\n0.6484375 0.965760251 0.743447967 0.64109263,\\\n0.65234375 0.966589914 0.738823693 0.634923509,\\\n0.65625 0.96732803 0.734132809 0.628751763,\\\n0.66015625 0.967974729 0.729375802 0.62257817,\\\n0.6640625 0.96853015 0.724553162 0.616403502,\\\n0.66796875 0.968994435 0.719665383 0.610228525,\\\n0.671875 0.969367729 0.714712956 0.604054002,\\\n0.67578125 0.969650186 0.709696378 0.597880686,\\\n0.6796875 0.969841963 0.704616143 0.591709328,\\\n0.68359375 0.969943224 0.699472746 0.585540669,\\\n0.6875 0.969954137 0.694266682 0.579375448,\\\n0.69140625 0.969874878 0.688998447 0.573214394,\\\n0.6953125 0.969705626 0.683668532 0.567058232,\\\n0.69921875 0.96944657 0.678277431 0.560907681,\\\n0.703125 0.969097901 0.672825633 0.554763452,\\\n0.70703125 0.968659818 0.667313624 0.54862625,\\\n0.7109375 0.968132528 0.661741889 0.542496774,\\\n0.71484375 0.967516241 0.656110908 0.536375716,\\\n0.71875 0.966811177 0.650421156 0.530263762,\\\n0.72265625 0.966017559 0.644673104 0.524161591,\\\n0.7265625 0.965135621 0.638867216 0.518069875,\\\n0.73046875 0.964165599 0.63300395 0.511989279,\\\n0.734375 0.963107739 0.627083758 0.505920462,\\\n0.73828125 0.961962293 0.621107082 0.499864075,\\\n0.7421875 0.960729521 0.615074355 0.493820764,\\\n0.74609375 0.959409687 0.608986 0.487791167,\\\n0.75 0.958003065 0.602842431 0.481775914,\\\n0.75390625 0.956509936 0.596644046 0.475775629,\\\n0.7578125 0.954930586 0.590391232 0.46979093,\\\n0.76171875 0.95326531 0.584084361 0.463822426,\\\n0.765625 0.951514411 0.57772379 0.457870719,\\\n0.76953125 0.949678196 0.571309856 0.451936407,\\\n0.7734375 0.947756983 0.564842879 0.446020077,\\\n0.77734375 0.945751096 0.558323158 0.440122312,\\\n0.78125 0.943660866 0.551750968 0.434243684,\\\n0.78515625 0.941486631 0.545126562 0.428384763,\\\n0.7890625 0.939228739 0.538450165 0.422546107,\\\n0.79296875 0.936887543 0.531721972 0.41672827,\\\n0.796875 0.934463404 0.524942147 0.410931798,\\\n0.80078125 0.931956691 0.518110821 0.40515723,\\\n0.8046875 0.929367782 0.511228087 0.399405096,\\\n0.80859375 0.92669706 0.504293997 0.393675922,\\\n0.8125 0.923944917 0.49730856 0.387970225,\\\n0.81640625 0.921111753 0.490271735 0.382288516,\\\n0.8203125 0.918197974 0.483183431 0.376631297,\\\n0.82421875 0.915203996 0.476043498 0.370999065,\\\n0.828125 0.912130241 0.468851724 0.36539231,\\\n0.83203125 0.908977139 0.461607831 0.359811513,\\\n0.8359375 0.905745128 0.454311462 0.354257151,\\\n0.83984375 0.902434654 0.446962183 0.348729691,\\\n0.84375 0.89904617 0.439559467 0.343229596,\\\n0.84765625 0.895580136 0.43210269 0.33775732,\\\n0.8515625 0.892037022 0.424591118 0.332313313,\\\n0.85546875 0.888417303 0.417023898 0.326898016,\\\n0.859375 0.884721464 0.409400045 0.321511863,\\\n0.86328125 0.880949996 0.401718425 0.316155284,\\\n0.8671875 0.877103399 0.393977745 0.310828702,\\\n0.87109375 0.873182178 0.386176527 0.305532531,\\\n0.875 0.869186849 0.378313092 0.300267182,\\\n0.87890625 0.865117934 0.370385535 0.295033059,\\\n0.8828125 0.860975962 0.362391695 0.289830559,\\\n0.88671875 0.85676147 0.354329127 0.284660075,\\\n0.890625 0.852475004 0.346195061 0.279521991,\\\n0.89453125 0.848117114 0.337986361 0.27441669,\\\n0.8984375 0.843688361 0.329699471 0.269344545,\\\n0.90234375 0.839189312 0.32133036 0.264305927,\\\n0.90625 0.834620542 0.312874446 0.259301199,\\\n0.91015625 0.829982631 0.304326513 0.254330723,\\\n0.9140625 0.82527617 0.295680611 0.249394851,\\\n0.91796875 0.820501754 0.286929926 0.244493934,\\\n0.921875 0.815659988 0.278066636 0.239628318,\\\n0.92578125 0.810751482 0.269081721 0.234798343,\\\n0.9296875 0.805776855 0.259964733 0.230004348,\\\n0.93359375 0.800736732 0.250703507 0.225246666,\\\n0.9375 0.795631745 0.24128379 0.220525627,\\\n0.94140625 0.790462533 0.231688768 0.215841558,\\\n0.9453125 0.785229744 0.221898442 0.211194782,\\\n0.94921875 0.779934029 0.211888813 0.20658562,\\\n0.953125 0.774576051 0.201630762 0.202014392,\\\n0.95703125 0.769156474 0.191088518 0.197481414,\\\n0.9609375 0.763675975 0.180217488 0.192987001,\\\n0.96484375 0.758135232 0.168961101 0.188531467,\\\n0.96875 0.752534934 0.157246067 0.184115123,\\\n0.97265625 0.746875773 0.144974956 0.179738284,\\\n0.9765625 0.741158452 0.132014017 0.175401259,\\\n0.98046875 0.735383675 0.1181719 0.171104363,\\\n0.984375 0.729552157 0.103159409 0.166847907,\\\n0.98828125 0.723664618 0.086504694 0.162632207,\\\n0.9921875 0.717721782 0.067344036 0.158457578,\\\n0.99609375 0.711724383 0.043755173 0.154324339,\\\n1 0.705673158 0.01555616 0.150232812)\n" }, + { "oranges", "# line styles for ColorBrewer Oranges\n# for use with sequential data\n# provides 8 orange colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFF5EB' # very light orange\nset style line 2 lt 1 lc rgb '#FEE6CE' # \nset style line 3 lt 1 lc rgb '#FDD0A2' # \nset style line 4 lt 1 lc rgb '#FDAE6B' # light orange\nset style line 5 lt 1 lc rgb '#FD8D3C' # \nset style line 6 lt 1 lc rgb '#F16913' # medium orange\nset style line 7 lt 1 lc rgb '#D94801' #\nset style line 8 lt 1 lc rgb '#8C2D04' # dark orange\n\n# palette\nset palette defined ( 0 '#FFF5EB',\\\n \t \t 1 '#FEE6CE',\\\n\t\t 2 '#FDD0A2',\\\n\t\t 3 '#FDAE6B',\\\n\t\t 4 '#FD8D3C',\\\n\t\t 5 '#F16913',\\\n\t\t 6 '#D94801',\\\n\t\t 7 '#8C2D04' )\n" }, + { "orrd", "# line styles for ColorBrewer OrRd\n# for use with sequential data\n# provides 8 orange-red colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFF7EC' # very light orange-red\nset style line 2 lt 1 lc rgb '#FEE8C8' # \nset style line 3 lt 1 lc rgb '#FDD49E' # \nset style line 4 lt 1 lc rgb '#FDBB84' # light orange-red\nset style line 5 lt 1 lc rgb '#FC8D59' # \nset style line 6 lt 1 lc rgb '#EF6548' # medium orange-red\nset style line 7 lt 1 lc rgb '#D7301F' #\nset style line 8 lt 1 lc rgb '#990000' # dark orange-red\n\n# palette\nset palette defined ( 0 '#FFF7EC',\\\n \t \t 1 '#FEE8C8',\\\n\t\t 2 '#FDD49E',\\\n\t\t 3 '#FDBB84',\\\n\t\t 4 '#FC8D59',\\\n\t\t 5 '#EF6548',\\\n\t\t 6 '#D7301F',\\\n\t\t 7 '#990000' )\n" }, + { "paired", "# line styles for ColorBrewer Paired\n# for use with qualitative/categorical data\n# provides 8 colors in 4 pairs\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#A6CEE3' # light blue\nset style line 2 lt 1 lc rgb '#1F78B4' # dark blue\nset style line 3 lt 1 lc rgb '#B2DF8A' # light green\nset style line 4 lt 1 lc rgb '#33A02C' # dark green\nset style line 5 lt 1 lc rgb '#FB9A99' # light red\nset style line 6 lt 1 lc rgb '#E31A1C' # dark red\nset style line 7 lt 1 lc rgb '#FDBF6F' # light orange\nset style line 8 lt 1 lc rgb '#FF7F00' # dark orange\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#A6CEE3',\\\n \t \t 1 '#1F78B4',\\\n\t\t 2 '#B2DF8A',\\\n\t\t 3 '#33A02C',\\\n\t\t 4 '#FB9A99',\\\n\t\t 5 '#E31A1C',\\\n\t\t 6 '#FDBF6F',\\\n\t\t 7 '#FF7F00' )\n" }, + { "parula", "# Colormap similar to Matlab parula, see:\n# http://www.mathworks.de/products/matlab/matlab-graphics/#new_look_for_matlab_graphics\n\n# line styles\nset style line 1 lt 1 lc rgb '#352a87' # blue\nset style line 2 lt 1 lc rgb '#0f5cdd' # blue\nset style line 3 lt 1 lc rgb '#1481d6' # blue\nset style line 4 lt 1 lc rgb '#06a4ca' # cyan\nset style line 5 lt 1 lc rgb '#2eb7a4' # green\nset style line 6 lt 1 lc rgb '#87bf77' # green\nset style line 7 lt 1 lc rgb '#d1bb59' # orange\nset style line 8 lt 1 lc rgb '#fec832' # orange\nset style line 9 lt 1 lc rgb '#f9fb0e' # yellow\n\n# New default Matlab line colors, introduced together with parula (2014b)\nset style line 11 lt 1 lc rgb '#0072bd' # blue\nset style line 12 lt 1 lc rgb '#d95319' # orange\nset style line 13 lt 1 lc rgb '#edb120' # yellow\nset style line 14 lt 1 lc rgb '#7e2f8e' # purple\nset style line 15 lt 1 lc rgb '#77ac30' # green\nset style line 16 lt 1 lc rgb '#4dbeee' # light-blue\nset style line 17 lt 1 lc rgb '#a2142f' # red\n\n# palette\nset palette defined (\\\n0 '#352a87',\\\n1 '#0363e1',\\\n2 '#1485d4',\\\n3 '#06a7c6',\\\n4 '#38b99e',\\\n5 '#92bf73',\\\n6 '#d9ba56',\\\n7 '#fcce2e',\\\n8 '#f9fb0e')\n" }, + { "pastel1", "# line styles for ColorBrewer Pastel1\n# for use with qualitative/categorical data\n# provides 8 pale colors based on Set1\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FBB4AE' # pale red\nset style line 2 lt 1 lc rgb '#B3CDE3' # pale blue\nset style line 3 lt 1 lc rgb '#CCEBC5' # pale green\nset style line 4 lt 1 lc rgb '#DECBE4' # pale purple\nset style line 5 lt 1 lc rgb '#FED9A6' # pale orange\nset style line 6 lt 1 lc rgb '#FFFFCC' # pale yellow\nset style line 7 lt 1 lc rgb '#E5D8BD' # pale brown\nset style line 8 lt 1 lc rgb '#FDDAEC' # pale pink\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#FBB4AE',\\\n \t \t 1 '#B3CDE3',\\\n\t\t 2 '#CCEBC5',\\\n\t\t 3 '#DECBE4',\\\n\t\t 4 '#FED9A6',\\\n\t\t 5 '#FFFFCC',\\\n\t\t 6 '#E5D8BD',\\\n\t\t 7 '#FDDAEC' )\n" }, + { "pastel2", "# line styles for ColorBrewer Pastel2\n# for use with qualitative/categorical data\n# provides 8 pale colors based on Set2\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#B3E2CD' # pale teal\nset style line 2 lt 1 lc rgb '#FDCDAC' # pale orange\nset style line 3 lt 1 lc rgb '#CDB5E8' # pale lilac\nset style line 4 lt 1 lc rgb '#F4CAE4' # pale magenta\nset style line 5 lt 1 lc rgb '#D6F5C9' # pale lime green\nset style line 6 lt 1 lc rgb '#FFF2AE' # pale banana\nset style line 7 lt 1 lc rgb '#F1E2CC' # pale tan\nset style line 8 lt 1 lc rgb '#CCCCCC' # pale grey\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#B3E2CD',\\\n \t \t 1 '#FDCDAC',\\\n\t\t 2 '#CDB5E8',\\\n\t\t 3 '#F4CAE4',\\\n\t\t 4 '#D6F5C9',\\\n\t\t 5 '#FFF2AE',\\\n\t\t 6 '#F1E2CC',\\\n\t\t 7 '#CCCCCC' )\n" }, + { "piyg", "# line styles for ColorBrewer PiYG\n# for use with divering data\n# provides 8 colors with pink low, white middle, and yellow-green high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#C51B7D' # dark pink\nset style line 2 lt 1 lc rgb '#DE77AE' # medium pink\nset style line 3 lt 1 lc rgb '#F1B6DA' # \nset style line 4 lt 1 lc rgb '#FDE0EF' # pale pink\nset style line 5 lt 1 lc rgb '#E6F5D0' # pale yellow-green\nset style line 6 lt 1 lc rgb '#B8E186' # \nset style line 7 lt 1 lc rgb '#7FBC41' # medium yellow-green\nset style line 8 lt 1 lc rgb '#4D9221' # dark yellow-green\n\n# palette\nset palette defined ( 0 '#C51B7D',\\\n \t \t 1 '#DE77AE',\\\n\t\t 2 '#F1B6DA',\\\n\t\t 3 '#FDE0EF',\\\n\t\t 4 '#E6F5D0',\\\n\t\t 5 '#B8E186',\\\n\t\t 6 '#7FBC41',\\\n\t\t 7 '#4D9221' )\n" }, + { "plasma", "# New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,\n# and (in the case of viridis) Eric Firing.\n#\n# This file and the colormaps in it are released under the CC0 license /\n# public domain dedication. We would appreciate credit if you use or\n# redistribute these colormaps, but do not impose any legal restrictions.\n#\n# To the extent possible under law, the persons who associated CC0 with\n# mpl-colormaps have waived all copyright and related or neighboring rights\n# to mpl-colormaps.\n#\n# You should have received a copy of the CC0 legalcode along with this\n# work. If not, see .\n\n#https://github.com/BIDS/colormap/blob/master/colormaps.py\n\n\n# line styles\nset style line 1 lt 1 lc rgb '#0c0887' # blue\nset style line 2 lt 1 lc rgb '#4b03a1' # purple-blue\nset style line 3 lt 1 lc rgb '#7d03a8' # purple\nset style line 4 lt 1 lc rgb '#a82296' # purple\nset style line 5 lt 1 lc rgb '#cb4679' # magenta\nset style line 6 lt 1 lc rgb '#e56b5d' # red\nset style line 7 lt 1 lc rgb '#f89441' # orange\nset style line 8 lt 1 lc rgb '#fdc328' # orange\nset style line 9 lt 1 lc rgb '#f0f921' # yellow\n\n\n# palette\nset palette defined (\\\n0 0.050383 0.029803 0.527975,\\\n1 0.063536 0.028426 0.533124,\\\n2 0.075353 0.027206 0.538007,\\\n3 0.086222 0.026125 0.542658,\\\n4 0.096379 0.025165 0.547103,\\\n5 0.105980 0.024309 0.551368,\\\n6 0.115124 0.023556 0.555468,\\\n7 0.123903 0.022878 0.559423,\\\n8 0.132381 0.022258 0.563250,\\\n9 0.140603 0.021687 0.566959,\\\n10 0.148607 0.021154 0.570562,\\\n11 0.156421 0.020651 0.574065,\\\n12 0.164070 0.020171 0.577478,\\\n13 0.171574 0.019706 0.580806,\\\n14 0.178950 0.019252 0.584054,\\\n15 0.186213 0.018803 0.587228,\\\n16 0.193374 0.018354 0.590330,\\\n17 0.200445 0.017902 0.593364,\\\n18 0.207435 0.017442 0.596333,\\\n19 0.214350 0.016973 0.599239,\\\n20 0.221197 0.016497 0.602083,\\\n21 0.227983 0.016007 0.604867,\\\n22 0.234715 0.015502 0.607592,\\\n23 0.241396 0.014979 0.610259,\\\n24 0.248032 0.014439 0.612868,\\\n25 0.254627 0.013882 0.615419,\\\n26 0.261183 0.013308 0.617911,\\\n27 0.267703 0.012716 0.620346,\\\n28 0.274191 0.012109 0.622722,\\\n29 0.280648 0.011488 0.625038,\\\n30 0.287076 0.010855 0.627295,\\\n31 0.293478 0.010213 0.629490,\\\n32 0.299855 0.009561 0.631624,\\\n33 0.306210 0.008902 0.633694,\\\n34 0.312543 0.008239 0.635700,\\\n35 0.318856 0.007576 0.637640,\\\n36 0.325150 0.006915 0.639512,\\\n37 0.331426 0.006261 0.641316,\\\n38 0.337683 0.005618 0.643049,\\\n39 0.343925 0.004991 0.644710,\\\n40 0.350150 0.004382 0.646298,\\\n41 0.356359 0.003798 0.647810,\\\n42 0.362553 0.003243 0.649245,\\\n43 0.368733 0.002724 0.650601,\\\n44 0.374897 0.002245 0.651876,\\\n45 0.381047 0.001814 0.653068,\\\n46 0.387183 0.001434 0.654177,\\\n47 0.393304 0.001114 0.655199,\\\n48 0.399411 0.000859 0.656133,\\\n49 0.405503 0.000678 0.656977,\\\n50 0.411580 0.000577 0.657730,\\\n51 0.417642 0.000564 0.658390,\\\n52 0.423689 0.000646 0.658956,\\\n53 0.429719 0.000831 0.659425,\\\n54 0.435734 0.001127 0.659797,\\\n55 0.441732 0.001540 0.660069,\\\n56 0.447714 0.002080 0.660240,\\\n57 0.453677 0.002755 0.660310,\\\n58 0.459623 0.003574 0.660277,\\\n59 0.465550 0.004545 0.660139,\\\n60 0.471457 0.005678 0.659897,\\\n61 0.477344 0.006980 0.659549,\\\n62 0.483210 0.008460 0.659095,\\\n63 0.489055 0.010127 0.658534,\\\n64 0.494877 0.011990 0.657865,\\\n65 0.500678 0.014055 0.657088,\\\n66 0.506454 0.016333 0.656202,\\\n67 0.512206 0.018833 0.655209,\\\n68 0.517933 0.021563 0.654109,\\\n69 0.523633 0.024532 0.652901,\\\n70 0.529306 0.027747 0.651586,\\\n71 0.534952 0.031217 0.650165,\\\n72 0.540570 0.034950 0.648640,\\\n73 0.546157 0.038954 0.647010,\\\n74 0.551715 0.043136 0.645277,\\\n75 0.557243 0.047331 0.643443,\\\n76 0.562738 0.051545 0.641509,\\\n77 0.568201 0.055778 0.639477,\\\n78 0.573632 0.060028 0.637349,\\\n79 0.579029 0.064296 0.635126,\\\n80 0.584391 0.068579 0.632812,\\\n81 0.589719 0.072878 0.630408,\\\n82 0.595011 0.077190 0.627917,\\\n83 0.600266 0.081516 0.625342,\\\n84 0.605485 0.085854 0.622686,\\\n85 0.610667 0.090204 0.619951,\\\n86 0.615812 0.094564 0.617140,\\\n87 0.620919 0.098934 0.614257,\\\n88 0.625987 0.103312 0.611305,\\\n89 0.631017 0.107699 0.608287,\\\n90 0.636008 0.112092 0.605205,\\\n91 0.640959 0.116492 0.602065,\\\n92 0.645872 0.120898 0.598867,\\\n93 0.650746 0.125309 0.595617,\\\n94 0.655580 0.129725 0.592317,\\\n95 0.660374 0.134144 0.588971,\\\n96 0.665129 0.138566 0.585582,\\\n97 0.669845 0.142992 0.582154,\\\n98 0.674522 0.147419 0.578688,\\\n99 0.679160 0.151848 0.575189,\\\n100 0.683758 0.156278 0.571660,\\\n101 0.688318 0.160709 0.568103,\\\n102 0.692840 0.165141 0.564522,\\\n103 0.697324 0.169573 0.560919,\\\n104 0.701769 0.174005 0.557296,\\\n105 0.706178 0.178437 0.553657,\\\n106 0.710549 0.182868 0.550004,\\\n107 0.714883 0.187299 0.546338,\\\n108 0.719181 0.191729 0.542663,\\\n109 0.723444 0.196158 0.538981,\\\n110 0.727670 0.200586 0.535293,\\\n111 0.731862 0.205013 0.531601,\\\n112 0.736019 0.209439 0.527908,\\\n113 0.740143 0.213864 0.524216,\\\n114 0.744232 0.218288 0.520524,\\\n115 0.748289 0.222711 0.516834,\\\n116 0.752312 0.227133 0.513149,\\\n117 0.756304 0.231555 0.509468,\\\n118 0.760264 0.235976 0.505794,\\\n119 0.764193 0.240396 0.502126,\\\n120 0.768090 0.244817 0.498465,\\\n121 0.771958 0.249237 0.494813,\\\n122 0.775796 0.253658 0.491171,\\\n123 0.779604 0.258078 0.487539,\\\n124 0.783383 0.262500 0.483918,\\\n125 0.787133 0.266922 0.480307,\\\n126 0.790855 0.271345 0.476706,\\\n127 0.794549 0.275770 0.473117,\\\n128 0.798216 0.280197 0.469538,\\\n129 0.801855 0.284626 0.465971,\\\n130 0.805467 0.289057 0.462415,\\\n131 0.809052 0.293491 0.458870,\\\n132 0.812612 0.297928 0.455338,\\\n133 0.816144 0.302368 0.451816,\\\n134 0.819651 0.306812 0.448306,\\\n135 0.823132 0.311261 0.444806,\\\n136 0.826588 0.315714 0.441316,\\\n137 0.830018 0.320172 0.437836,\\\n138 0.833422 0.324635 0.434366,\\\n139 0.836801 0.329105 0.430905,\\\n140 0.840155 0.333580 0.427455,\\\n141 0.843484 0.338062 0.424013,\\\n142 0.846788 0.342551 0.420579,\\\n143 0.850066 0.347048 0.417153,\\\n144 0.853319 0.351553 0.413734,\\\n145 0.856547 0.356066 0.410322,\\\n146 0.859750 0.360588 0.406917,\\\n147 0.862927 0.365119 0.403519,\\\n148 0.866078 0.369660 0.400126,\\\n149 0.869203 0.374212 0.396738,\\\n150 0.872303 0.378774 0.393355,\\\n151 0.875376 0.383347 0.389976,\\\n152 0.878423 0.387932 0.386600,\\\n153 0.881443 0.392529 0.383229,\\\n154 0.884436 0.397139 0.379860,\\\n155 0.887402 0.401762 0.376494,\\\n156 0.890340 0.406398 0.373130,\\\n157 0.893250 0.411048 0.369768,\\\n158 0.896131 0.415712 0.366407,\\\n159 0.898984 0.420392 0.363047,\\\n160 0.901807 0.425087 0.359688,\\\n161 0.904601 0.429797 0.356329,\\\n162 0.907365 0.434524 0.352970,\\\n163 0.910098 0.439268 0.349610,\\\n164 0.912800 0.444029 0.346251,\\\n165 0.915471 0.448807 0.342890,\\\n166 0.918109 0.453603 0.339529,\\\n167 0.920714 0.458417 0.336166,\\\n168 0.923287 0.463251 0.332801,\\\n169 0.925825 0.468103 0.329435,\\\n170 0.928329 0.472975 0.326067,\\\n171 0.930798 0.477867 0.322697,\\\n172 0.933232 0.482780 0.319325,\\\n173 0.935630 0.487712 0.315952,\\\n174 0.937990 0.492667 0.312575,\\\n175 0.940313 0.497642 0.309197,\\\n176 0.942598 0.502639 0.305816,\\\n177 0.944844 0.507658 0.302433,\\\n178 0.947051 0.512699 0.299049,\\\n179 0.949217 0.517763 0.295662,\\\n180 0.951344 0.522850 0.292275,\\\n181 0.953428 0.527960 0.288883,\\\n182 0.955470 0.533093 0.285490,\\\n183 0.957469 0.538250 0.282096,\\\n184 0.959424 0.543431 0.278701,\\\n185 0.961336 0.548636 0.275305,\\\n186 0.963203 0.553865 0.271909,\\\n187 0.965024 0.559118 0.268513,\\\n188 0.966798 0.564396 0.265118,\\\n189 0.968526 0.569700 0.261721,\\\n190 0.970205 0.575028 0.258325,\\\n191 0.971835 0.580382 0.254931,\\\n192 0.973416 0.585761 0.251540,\\\n193 0.974947 0.591165 0.248151,\\\n194 0.976428 0.596595 0.244767,\\\n195 0.977856 0.602051 0.241387,\\\n196 0.979233 0.607532 0.238013,\\\n197 0.980556 0.613039 0.234646,\\\n198 0.981826 0.618572 0.231287,\\\n199 0.983041 0.624131 0.227937,\\\n200 0.984199 0.629718 0.224595,\\\n201 0.985301 0.635330 0.221265,\\\n202 0.986345 0.640969 0.217948,\\\n203 0.987332 0.646633 0.214648,\\\n204 0.988260 0.652325 0.211364,\\\n205 0.989128 0.658043 0.208100,\\\n206 0.989935 0.663787 0.204859,\\\n207 0.990681 0.669558 0.201642,\\\n208 0.991365 0.675355 0.198453,\\\n209 0.991985 0.681179 0.195295,\\\n210 0.992541 0.687030 0.192170,\\\n211 0.993032 0.692907 0.189084,\\\n212 0.993456 0.698810 0.186041,\\\n213 0.993814 0.704741 0.183043,\\\n214 0.994103 0.710698 0.180097,\\\n215 0.994324 0.716681 0.177208,\\\n216 0.994474 0.722691 0.174381,\\\n217 0.994553 0.728728 0.171622,\\\n218 0.994561 0.734791 0.168938,\\\n219 0.994495 0.740880 0.166335,\\\n220 0.994355 0.746995 0.163821,\\\n221 0.994141 0.753137 0.161404,\\\n222 0.993851 0.759304 0.159092,\\\n223 0.993482 0.765499 0.156891,\\\n224 0.993033 0.771720 0.154808,\\\n225 0.992505 0.777967 0.152855,\\\n226 0.991897 0.784239 0.151042,\\\n227 0.991209 0.790537 0.149377,\\\n228 0.990439 0.796859 0.147870,\\\n229 0.989587 0.803205 0.146529,\\\n230 0.988648 0.809579 0.145357,\\\n231 0.987621 0.815978 0.144363,\\\n232 0.986509 0.822401 0.143557,\\\n233 0.985314 0.828846 0.142945,\\\n234 0.984031 0.835315 0.142528,\\\n235 0.982653 0.841812 0.142303,\\\n236 0.981190 0.848329 0.142279,\\\n237 0.979644 0.854866 0.142453,\\\n238 0.977995 0.861432 0.142808,\\\n239 0.976265 0.868016 0.143351,\\\n240 0.974443 0.874622 0.144061,\\\n241 0.972530 0.881250 0.144923,\\\n242 0.970533 0.887896 0.145919,\\\n243 0.968443 0.894564 0.147014,\\\n244 0.966271 0.901249 0.148180,\\\n245 0.964021 0.907950 0.149370,\\\n246 0.961681 0.914672 0.150520,\\\n247 0.959276 0.921407 0.151566,\\\n248 0.956808 0.928152 0.152409,\\\n249 0.954287 0.934908 0.152921,\\\n250 0.951726 0.941671 0.152925,\\\n251 0.949151 0.948435 0.152178,\\\n252 0.946602 0.955190 0.150328,\\\n253 0.944152 0.961916 0.146861,\\\n254 0.941896 0.968590 0.140956,\\\n255 0.940015 0.975158 0.131326)\n" }, + { "prgn", "# line styles for ColorBrewer PRGn (aka PuGn)\n# for use with divering data\n# provides 8 colors with purple low, white middle, and green high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#762A83' # dark purple\nset style line 2 lt 1 lc rgb '#9970AB' # medium purple\nset style line 3 lt 1 lc rgb '#C2A5CF' # \nset style line 4 lt 1 lc rgb '#E7D4E8' # pale purple\nset style line 5 lt 1 lc rgb '#D9F0D3' # pale green\nset style line 6 lt 1 lc rgb '#A6DBA0' # \nset style line 7 lt 1 lc rgb '#5AAE61' # medium green\nset style line 8 lt 1 lc rgb '#1B7837' # dark green\n\n# palette\nset palette defined ( 0 '#762A83',\\\n \t \t 1 '#9970AB',\\\n\t\t 2 '#C2A5CF',\\\n\t\t 3 '#E7D4E8',\\\n\t\t 4 '#D9F0D3',\\\n\t\t 5 '#A6DBA0',\\\n\t\t 6 '#5AAE61',\\\n\t\t 7 '#1B7837' )\n" }, + { "pubu", "# line styles for ColorBrewer PuBu\n# for use with sequential data\n# provides 8 purple-blue colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFF7FB' # very light purple-blue\nset style line 2 lt 1 lc rgb '#ECE7F2' # \nset style line 3 lt 1 lc rgb '#D0D1E6' # \nset style line 4 lt 1 lc rgb '#A6BDDB' # light purple-blue\nset style line 5 lt 1 lc rgb '#74A9CF' # \nset style line 6 lt 1 lc rgb '#3690C0' # medium purple-blue\nset style line 7 lt 1 lc rgb '#0570B0' #\nset style line 8 lt 1 lc rgb '#034E7B' # dark purple-blue\n\n# palette\nset palette defined ( 0 '#FFF7FB',\\\n \t \t 1 '#ECE7F2',\\\n\t\t 2 '#D0D1E6',\\\n\t\t 3 '#A6BDDB',\\\n\t\t 4 '#74A9CF',\\\n\t\t 5 '#3690C0',\\\n\t\t 6 '#0570B0',\\\n\t\t 7 '#034E7B' )\n" }, + { "pubugn", "# line styles for ColorBrewer PuBuGn\n# for use with sequential data\n# provides 8 purple-blue-green colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFF7FB' # very light purple-blue-green\nset style line 2 lt 1 lc rgb '#ECE2F0' # \nset style line 3 lt 1 lc rgb '#D0D1E6' # \nset style line 4 lt 1 lc rgb '#A6BDDB' # light purple-blue-green\nset style line 5 lt 1 lc rgb '#67A9CF' # \nset style line 6 lt 1 lc rgb '#3690C0' # medium purple-blue-green\nset style line 7 lt 1 lc rgb '#02818A' #\nset style line 8 lt 1 lc rgb '#016540' # dark purple-blue-green\n\n# palette\nset palette defined ( 0 '#FFF7FB',\\\n \t \t 1 '#ECE7F0',\\\n\t\t 2 '#D0D1E6',\\\n\t\t 3 '#A6BDDB',\\\n\t\t 4 '#67A9CF',\\\n\t\t 5 '#3690C0',\\\n\t\t 6 '#02818A',\\\n\t\t 7 '#016540' )\n" }, + { "puor", "# line styles for ColorBrewer PuOr\n# for use with divering data\n# provides 8 colors with orange low, white middle, and purple high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#B35806' # dark orange\nset style line 2 lt 1 lc rgb '#E08214' # medium orange\nset style line 3 lt 1 lc rgb '#FDB863' # \nset style line 4 lt 1 lc rgb '#FEE0B6' # pale orange\nset style line 5 lt 1 lc rgb '#D8DAEB' # pale purple\nset style line 6 lt 1 lc rgb '#B2ABD2' # \nset style line 7 lt 1 lc rgb '#8073AC' # medium purple\nset style line 8 lt 1 lc rgb '#542788' # dark purple\n\n# palette\nset palette defined ( 0 '#B35806',\\\n \t \t 1 '#E08214',\\\n\t\t 2 '#FDB863',\\\n\t\t 3 '#FEE0B6',\\\n\t\t 4 '#D8DAEB',\\\n\t\t 5 '#B2ABD2',\\\n\t\t 6 '#8073AC',\\\n\t\t 7 '#542788' )\n" }, + { "purd", "# line styles for ColorBrewer PuRd\n# for use with sequential data\n# provides 8 purple-red colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#F7F4F9' # very light purple-red\nset style line 2 lt 1 lc rgb '#E7E1EF' # \nset style line 3 lt 1 lc rgb '#D4B9DA' # \nset style line 4 lt 1 lc rgb '#C994C7' # light purple-red\nset style line 5 lt 1 lc rgb '#DF65B0' # \nset style line 6 lt 1 lc rgb '#E7298A' # medium purple-red\nset style line 7 lt 1 lc rgb '#CE1256' #\nset style line 8 lt 1 lc rgb '#91003F' # dark purple-red\n\n# palette\nset palette defined ( 0 '#F7F4F9',\\\n \t \t 1 '#E7E1EF',\\\n\t\t 2 '#D4B9DA',\\\n\t\t 3 '#C994C7',\\\n\t\t 4 '#DF65B0',\\\n\t\t 5 '#E7298A',\\\n\t\t 6 '#CE1256',\\\n\t\t 7 '#91003F' )\n" }, + { "purples", "# line styles for ColorBrewer Purples\n# for use with sequential data\n# provides 8 purple colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FCFBFD' # very light purple\nset style line 2 lt 1 lc rgb '#EFEDF5' # \nset style line 3 lt 1 lc rgb '#DADAEB' # \nset style line 4 lt 1 lc rgb '#BCBDDC' # light purple\nset style line 5 lt 1 lc rgb '#9E9AC8' # \nset style line 6 lt 1 lc rgb '#807DBA' # medium purple\nset style line 7 lt 1 lc rgb '#6A51A3' #\nset style line 8 lt 1 lc rgb '#4A1486' # dark purple\n\n# palette\nset palette defined ( 0 '#FCFBFD',\\\n \t \t 1 '#EFEDF5',\\\n\t\t 2 '#DADAEB',\\\n\t\t 3 '#BCBDDC',\\\n\t\t 4 '#9E9AC8',\\\n\t\t 5 '#807DBA',\\\n\t\t 6 '#6A51A3',\\\n\t\t 7 '#4A1486' )\n" }, + { "rdbu", "# line styles for ColorBrewer RdBu\n# for use with divering data\n# provides 8 colors with red low, white middle, and blue high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#B2182B' # red\nset style line 2 lt 1 lc rgb '#D6604D' # red-orange\nset style line 3 lt 1 lc rgb '#F4A582' # \nset style line 4 lt 1 lc rgb '#FDDBC7' # pale orange\nset style line 5 lt 1 lc rgb '#D1E5F0' # pale blue\nset style line 6 lt 1 lc rgb '#92C5DE' # \nset style line 7 lt 1 lc rgb '#4393C3' # medium blue\nset style line 8 lt 1 lc rgb '#2166AC' # dark blue\n\n# palette\nset palette defined ( 0 '#B2182B',\\\n \t \t 1 '#D6604D',\\\n\t\t 2 '#F4A582',\\\n\t\t 3 '#FDDBC7',\\\n\t\t 4 '#D1E5F0',\\\n\t\t 5 '#92C5DE',\\\n\t\t 6 '#4393C3',\\\n\t\t 7 '#2166AC' )\n" }, + { "rdgy", "# line styles for ColorBrewer RdGy\n# for use with divering data\n# provides 8 colors with red low, white middle, and grey high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#B2182B' # red\nset style line 2 lt 1 lc rgb '#D6604D' # red-orange\nset style line 3 lt 1 lc rgb '#F4A582' # \nset style line 4 lt 1 lc rgb '#FDDBC7' # pale orange\nset style line 5 lt 1 lc rgb '#E0E0E0' # pale grey\nset style line 6 lt 1 lc rgb '#BABABA' # \nset style line 7 lt 1 lc rgb '#878787' # medium grey\nset style line 8 lt 1 lc rgb '#4D4D4D' # dark grey\n\n# palette\nset palette defined ( 0 '#B2182B',\\\n \t \t 1 '#D6604D',\\\n\t\t 2 '#F4A582',\\\n\t\t 3 '#FDDBC7',\\\n\t\t 4 '#E0E0E0',\\\n\t\t 5 '#BABABA',\\\n\t\t 6 '#878787',\\\n\t\t 7 '#4D4D4D' )\n" }, + { "rdpu", "# line styles for ColorBrewer PuRd\n# for use with sequential data\n# provides 8 red-purple colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFF7F3' # very light red-purple\nset style line 2 lt 1 lc rgb '#FDE0DD' # \nset style line 3 lt 1 lc rgb '#FCC5C0' # \nset style line 4 lt 1 lc rgb '#FA9FB5' # light red-purple\nset style line 5 lt 1 lc rgb '#F768A1' # \nset style line 6 lt 1 lc rgb '#DD3497' # medium red-purple\nset style line 7 lt 1 lc rgb '#AE017E' #\nset style line 8 lt 1 lc rgb '#7A0177' # dark red-purple\n\n# palette\nset palette defined ( 0 '#FFF7F3',\\\n \t \t 1 '#FDE0DD',\\\n\t\t 2 '#FCC5C0',\\\n\t\t 3 '#FA9FB5',\\\n\t\t 4 '#F768A1',\\\n\t\t 5 '#DD3497',\\\n\t\t 6 '#AE017E',\\\n\t\t 7 '#7A0177' )\n" }, + { "rdylbu", "# line styles for ColorBrewer RdYlBu\n# for use with divering data\n# provides 8 colors with red low, pale yellow middle, and blue high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#D73027' # red\nset style line 2 lt 1 lc rgb '#F46D43' # orange\nset style line 3 lt 1 lc rgb '#FDAE61' # \nset style line 4 lt 1 lc rgb '#FEE090' # pale orange\nset style line 5 lt 1 lc rgb '#E0F3F8' # pale blue\nset style line 6 lt 1 lc rgb '#ABD9E9' # \nset style line 7 lt 1 lc rgb '#74ADD1' # medium blue\nset style line 8 lt 1 lc rgb '#4575B4' # blue\n\n# palette\nset palette defined ( 0 '#D73027',\\\n \t \t 1 '#F46D43',\\\n\t\t 2 '#FDAE61',\\\n\t\t 3 '#FEE090',\\\n\t\t 4 '#E0F3F8',\\\n\t\t 5 '#ABD9E9',\\\n\t\t 6 '#74ADD1',\\\n\t\t 7 '#4575B4' )\n" }, + { "rdylgn", "# line styles for ColorBrewer RdYlGn\n# for use with divering data\n# provides 8 colors with red low, pale yellow middle, and green high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#D73027' # red\nset style line 2 lt 1 lc rgb '#F46D43' # orange\nset style line 3 lt 1 lc rgb '#FDAE61' # pale orange\nset style line 4 lt 1 lc rgb '#FEE08B' # pale yellow-orange\nset style line 5 lt 1 lc rgb '#D9EF8B' # pale yellow-green\nset style line 6 lt 1 lc rgb '#A6D96A' # pale green\nset style line 7 lt 1 lc rgb '#66BD63' # medium green\nset style line 8 lt 1 lc rgb '#1A9850' # green\n\n# palette\nset palette defined ( 0 '#D73027',\\\n \t \t 1 '#F46D43',\\\n\t\t 2 '#FDAE61',\\\n\t\t 3 '#FEE08B',\\\n\t\t 4 '#D9EF8B',\\\n\t\t 5 '#A6D96A',\\\n\t\t 6 '#66BD63',\\\n\t\t 7 '#1A9850' )\n" }, + { "reds", "# line styles for ColorBrewer Reds\n# for use with sequential data\n# provides 8 red colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFF5F0' # very light red\nset style line 2 lt 1 lc rgb '#FEE0D2' # \nset style line 3 lt 1 lc rgb '#FCBBA1' # \nset style line 4 lt 1 lc rgb '#FC9272' # light red\nset style line 5 lt 1 lc rgb '#FB6A4A' # \nset style line 6 lt 1 lc rgb '#EF3B2C' # medium red\nset style line 7 lt 1 lc rgb '#CB181D' #\nset style line 8 lt 1 lc rgb '#99000D' # dark red\n\n# palette\nset palette defined ( 0 '#FFF5F0',\\\n \t \t 1 '#FEE0D2',\\\n\t\t 2 '#FCBBA1',\\\n\t\t 3 '#FC9272',\\\n\t\t 4 '#FB6A4A',\\\n\t\t 5 '#EF3B2C',\\\n\t\t 6 '#CB181D',\\\n\t\t 7 '#99000D' )\n" }, + { "sand", "# Sequential palette in sand colors\n# From G. N. Peterson, Cartographer's toolkit, PertersonGIS, 2012\n\n# line styles\nset style line 1 lt 1 lc rgb '#604860' # dark brown\nset style line 2 lt 1 lc rgb '#784860' # brown\nset style line 3 lt 1 lc rgb '#a86060' # brown\nset style line 4 lt 1 lc rgb '#c07860' # light brown\nset style line 5 lt 1 lc rgb '#f0a848' # orange\nset style line 6 lt 1 lc rgb '#f8ca8c' # orange\nset style line 7 lt 1 lc rgb '#feecae' # yellow\nset style line 8 lt 1 lc rgb '#fff4c2' # yellow\nset style line 9 lt 1 lc rgb '#fff7db' # light yellow\nset style line 10 lt 1 lc rgb '#fffcf6' # white\n\n# palette\nset palette defined (\\\n0 '#604860',\\\n1 '#784860',\\\n2 '#a86060',\\\n3 '#c07860',\\\n4 '#f0a848',\\\n5 '#f8ca8c',\\\n6 '#feecae',\\\n7 '#fff4c2',\\\n8 '#fff7db',\\\n9 '#fffcf6')\n" }, + { "set1", "# line styles for ColorBrewer Set1\n# for use with qualitative/categorical data\n# provides 8 easy-to-name colors\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#E41A1C' # red\nset style line 2 lt 1 lc rgb '#377EB8' # blue\nset style line 3 lt 1 lc rgb '#4DAF4A' # green\nset style line 4 lt 1 lc rgb '#984EA3' # purple\nset style line 5 lt 1 lc rgb '#FF7F00' # orange\nset style line 6 lt 1 lc rgb '#FFFF33' # yellow\nset style line 7 lt 1 lc rgb '#A65628' # brown\nset style line 8 lt 1 lc rgb '#F781BF' # pink\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#E41A1C',\\\n \t \t 1 '#377EB8',\\\n\t\t 2 '#4DAF4A',\\\n\t\t 3 '#984EA3',\\\n\t\t 4 '#FF7F00',\\\n\t\t 5 '#FFFF33',\\\n\t\t 6 '#A65628',\\\n\t\t 7 '#F781BF' )\n" }, + { "set2", "# line styles for ColorBrewer Set3\n# for use with qualitative/categorical data\n# provides 8 hard-to-name colors\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#66C2A5' # teal\nset style line 2 lt 1 lc rgb '#FC8D62' # orange\nset style line 3 lt 1 lc rgb '#8DA0CB' # lilac\nset style line 4 lt 1 lc rgb '#E78AC3' # magentat\nset style line 5 lt 1 lc rgb '#A6D854' # lime green\nset style line 6 lt 1 lc rgb '#FFD92F' # banana\nset style line 7 lt 1 lc rgb '#E5C494' # tan\nset style line 8 lt 1 lc rgb '#B3B3B3' # grey\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#66C2A5',\\\n \t \t 1 '#FC8D62',\\\n\t\t 2 '#8DA0CB',\\\n\t\t 3 '#E78AC3',\\\n\t\t 4 '#A6D854',\\\n\t\t 5 '#FFD92F',\\\n\t\t 6 '#E5C494',\\\n\t\t 7 '#B3B3B3' )\n" }, + { "set3", "# line styles for ColorBrewer Set3\n# for use with qualitative/categorical data\n# provides 8 colors that are more saturated than the Pastels but less so than Set2\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#8DD3C7' # teal\nset style line 2 lt 1 lc rgb '#FFFFB3' # banana\nset style line 3 lt 1 lc rgb '#BEBADA' # lilac\nset style line 4 lt 1 lc rgb '#FB8072' # red\nset style line 5 lt 1 lc rgb '#80B1D3' # steel blue\nset style line 6 lt 1 lc rgb '#FDB462' # adobe orange\nset style line 7 lt 1 lc rgb '#B3DE69' # lime green\nset style line 8 lt 1 lc rgb '#FCCDE5' # mauve\n\n# palette\nset palette maxcolors 8\nset palette defined ( 0 '#8DD3C7',\\\n \t \t 1 '#FFFFB3',\\\n\t\t 2 '#BEBADA',\\\n\t\t 3 '#FB8072',\\\n\t\t 4 '#80B1D3',\\\n\t\t 5 '#FDB462',\\\n\t\t 6 '#B3DE69',\\\n\t\t 7 '#FCCDE5' )\n" }, + { "spectral", "# line styles for ColorBrewer Spectral\n# for use with divering data\n# provides 8 rainbow colors with red low, pale yellow middle, and blue high\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#D53E4F' # red\nset style line 2 lt 1 lc rgb '#F46D43' # orange\nset style line 3 lt 1 lc rgb '#FDAE61' # pale orange\nset style line 4 lt 1 lc rgb '#FEE08B' # pale yellow-orange\nset style line 5 lt 1 lc rgb '#E6F598' # pale yellow-green\nset style line 6 lt 1 lc rgb '#ABDDA4' # pale green\nset style line 7 lt 1 lc rgb '#66C2A5' # green\nset style line 8 lt 1 lc rgb '#3288BD' # blue\n\n# palette\nset palette defined ( 0 '#D53E4F',\\\n \t \t 1 '#F46D43',\\\n\t\t 2 '#FDAE61',\\\n\t\t 3 '#FEE08B',\\\n\t\t 4 '#E6F598',\\\n\t\t 5 '#ABDDA4',\\\n\t\t 6 '#66C2A5',\\\n\t\t 7 '#3288BD' )\n" }, + { "viridis", "# New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,\n# and (in the case of viridis) Eric Firing.\n#\n# This file and the colormaps in it are released under the CC0 license /\n# public domain dedication. We would appreciate credit if you use or\n# redistribute these colormaps, but do not impose any legal restrictions.\n#\n# To the extent possible under law, the persons who associated CC0 with\n# mpl-colormaps have waived all copyright and related or neighboring rights\n# to mpl-colormaps.\n#\n# You should have received a copy of the CC0 legalcode along with this\n# work. If not, see .\n\n#https://github.com/BIDS/colormap/blob/master/colormaps.py\n\n\n# line styles\nset style line 1 lt 1 lc rgb '#440154' # dark purple\nset style line 2 lt 1 lc rgb '#472c7a' # purple\nset style line 3 lt 1 lc rgb '#3b518b' # blue\nset style line 4 lt 1 lc rgb '#2c718e' # blue\nset style line 5 lt 1 lc rgb '#21908d' # blue-green\nset style line 6 lt 1 lc rgb '#27ad81' # green\nset style line 7 lt 1 lc rgb '#5cc863' # green\nset style line 8 lt 1 lc rgb '#aadc32' # lime green\nset style line 9 lt 1 lc rgb '#fde725' # yellow\n\n\n# palette\nset palette defined (\\\n0 0.267004 0.004874 0.329415,\\\n1 0.268510 0.009605 0.335427,\\\n2 0.269944 0.014625 0.341379,\\\n3 0.271305 0.019942 0.347269,\\\n4 0.272594 0.025563 0.353093,\\\n5 0.273809 0.031497 0.358853,\\\n6 0.274952 0.037752 0.364543,\\\n7 0.276022 0.044167 0.370164,\\\n8 0.277018 0.050344 0.375715,\\\n9 0.277941 0.056324 0.381191,\\\n10 0.278791 0.062145 0.386592,\\\n11 0.279566 0.067836 0.391917,\\\n12 0.280267 0.073417 0.397163,\\\n13 0.280894 0.078907 0.402329,\\\n14 0.281446 0.084320 0.407414,\\\n15 0.281924 0.089666 0.412415,\\\n16 0.282327 0.094955 0.417331,\\\n17 0.282656 0.100196 0.422160,\\\n18 0.282910 0.105393 0.426902,\\\n19 0.283091 0.110553 0.431554,\\\n20 0.283197 0.115680 0.436115,\\\n21 0.283229 0.120777 0.440584,\\\n22 0.283187 0.125848 0.444960,\\\n23 0.283072 0.130895 0.449241,\\\n24 0.282884 0.135920 0.453427,\\\n25 0.282623 0.140926 0.457517,\\\n26 0.282290 0.145912 0.461510,\\\n27 0.281887 0.150881 0.465405,\\\n28 0.281412 0.155834 0.469201,\\\n29 0.280868 0.160771 0.472899,\\\n30 0.280255 0.165693 0.476498,\\\n31 0.279574 0.170599 0.479997,\\\n32 0.278826 0.175490 0.483397,\\\n33 0.278012 0.180367 0.486697,\\\n34 0.277134 0.185228 0.489898,\\\n35 0.276194 0.190074 0.493001,\\\n36 0.275191 0.194905 0.496005,\\\n37 0.274128 0.199721 0.498911,\\\n38 0.273006 0.204520 0.501721,\\\n39 0.271828 0.209303 0.504434,\\\n40 0.270595 0.214069 0.507052,\\\n41 0.269308 0.218818 0.509577,\\\n42 0.267968 0.223549 0.512008,\\\n43 0.266580 0.228262 0.514349,\\\n44 0.265145 0.232956 0.516599,\\\n45 0.263663 0.237631 0.518762,\\\n46 0.262138 0.242286 0.520837,\\\n47 0.260571 0.246922 0.522828,\\\n48 0.258965 0.251537 0.524736,\\\n49 0.257322 0.256130 0.526563,\\\n50 0.255645 0.260703 0.528312,\\\n51 0.253935 0.265254 0.529983,\\\n52 0.252194 0.269783 0.531579,\\\n53 0.250425 0.274290 0.533103,\\\n54 0.248629 0.278775 0.534556,\\\n55 0.246811 0.283237 0.535941,\\\n56 0.244972 0.287675 0.537260,\\\n57 0.243113 0.292092 0.538516,\\\n58 0.241237 0.296485 0.539709,\\\n59 0.239346 0.300855 0.540844,\\\n60 0.237441 0.305202 0.541921,\\\n61 0.235526 0.309527 0.542944,\\\n62 0.233603 0.313828 0.543914,\\\n63 0.231674 0.318106 0.544834,\\\n64 0.229739 0.322361 0.545706,\\\n65 0.227802 0.326594 0.546532,\\\n66 0.225863 0.330805 0.547314,\\\n67 0.223925 0.334994 0.548053,\\\n68 0.221989 0.339161 0.548752,\\\n69 0.220057 0.343307 0.549413,\\\n70 0.218130 0.347432 0.550038,\\\n71 0.216210 0.351535 0.550627,\\\n72 0.214298 0.355619 0.551184,\\\n73 0.212395 0.359683 0.551710,\\\n74 0.210503 0.363727 0.552206,\\\n75 0.208623 0.367752 0.552675,\\\n76 0.206756 0.371758 0.553117,\\\n77 0.204903 0.375746 0.553533,\\\n78 0.203063 0.379716 0.553925,\\\n79 0.201239 0.383670 0.554294,\\\n80 0.199430 0.387607 0.554642,\\\n81 0.197636 0.391528 0.554969,\\\n82 0.195860 0.395433 0.555276,\\\n83 0.194100 0.399323 0.555565,\\\n84 0.192357 0.403199 0.555836,\\\n85 0.190631 0.407061 0.556089,\\\n86 0.188923 0.410910 0.556326,\\\n87 0.187231 0.414746 0.556547,\\\n88 0.185556 0.418570 0.556753,\\\n89 0.183898 0.422383 0.556944,\\\n90 0.182256 0.426184 0.557120,\\\n91 0.180629 0.429975 0.557282,\\\n92 0.179019 0.433756 0.557430,\\\n93 0.177423 0.437527 0.557565,\\\n94 0.175841 0.441290 0.557685,\\\n95 0.174274 0.445044 0.557792,\\\n96 0.172719 0.448791 0.557885,\\\n97 0.171176 0.452530 0.557965,\\\n98 0.169646 0.456262 0.558030,\\\n99 0.168126 0.459988 0.558082,\\\n100 0.166617 0.463708 0.558119,\\\n101 0.165117 0.467423 0.558141,\\\n102 0.163625 0.471133 0.558148,\\\n103 0.162142 0.474838 0.558140,\\\n104 0.160665 0.478540 0.558115,\\\n105 0.159194 0.482237 0.558073,\\\n106 0.157729 0.485932 0.558013,\\\n107 0.156270 0.489624 0.557936,\\\n108 0.154815 0.493313 0.557840,\\\n109 0.153364 0.497000 0.557724,\\\n110 0.151918 0.500685 0.557587,\\\n111 0.150476 0.504369 0.557430,\\\n112 0.149039 0.508051 0.557250,\\\n113 0.147607 0.511733 0.557049,\\\n114 0.146180 0.515413 0.556823,\\\n115 0.144759 0.519093 0.556572,\\\n116 0.143343 0.522773 0.556295,\\\n117 0.141935 0.526453 0.555991,\\\n118 0.140536 0.530132 0.555659,\\\n119 0.139147 0.533812 0.555298,\\\n120 0.137770 0.537492 0.554906,\\\n121 0.136408 0.541173 0.554483,\\\n122 0.135066 0.544853 0.554029,\\\n123 0.133743 0.548535 0.553541,\\\n124 0.132444 0.552216 0.553018,\\\n125 0.131172 0.555899 0.552459,\\\n126 0.129933 0.559582 0.551864,\\\n127 0.128729 0.563265 0.551229,\\\n128 0.127568 0.566949 0.550556,\\\n129 0.126453 0.570633 0.549841,\\\n130 0.125394 0.574318 0.549086,\\\n131 0.124395 0.578002 0.548287,\\\n132 0.123463 0.581687 0.547445,\\\n133 0.122606 0.585371 0.546557,\\\n134 0.121831 0.589055 0.545623,\\\n135 0.121148 0.592739 0.544641,\\\n136 0.120565 0.596422 0.543611,\\\n137 0.120092 0.600104 0.542530,\\\n138 0.119738 0.603785 0.541400,\\\n139 0.119512 0.607464 0.540218,\\\n140 0.119423 0.611141 0.538982,\\\n141 0.119483 0.614817 0.537692,\\\n142 0.119699 0.618490 0.536347,\\\n143 0.120081 0.622161 0.534946,\\\n144 0.120638 0.625828 0.533488,\\\n145 0.121380 0.629492 0.531973,\\\n146 0.122312 0.633153 0.530398,\\\n147 0.123444 0.636809 0.528763,\\\n148 0.124780 0.640461 0.527068,\\\n149 0.126326 0.644107 0.525311,\\\n150 0.128087 0.647749 0.523491,\\\n151 0.130067 0.651384 0.521608,\\\n152 0.132268 0.655014 0.519661,\\\n153 0.134692 0.658636 0.517649,\\\n154 0.137339 0.662252 0.515571,\\\n155 0.140210 0.665859 0.513427,\\\n156 0.143303 0.669459 0.511215,\\\n157 0.146616 0.673050 0.508936,\\\n158 0.150148 0.676631 0.506589,\\\n159 0.153894 0.680203 0.504172,\\\n160 0.157851 0.683765 0.501686,\\\n161 0.162016 0.687316 0.499129,\\\n162 0.166383 0.690856 0.496502,\\\n163 0.170948 0.694384 0.493803,\\\n164 0.175707 0.697900 0.491033,\\\n165 0.180653 0.701402 0.488189,\\\n166 0.185783 0.704891 0.485273,\\\n167 0.191090 0.708366 0.482284,\\\n168 0.196571 0.711827 0.479221,\\\n169 0.202219 0.715272 0.476084,\\\n170 0.208030 0.718701 0.472873,\\\n171 0.214000 0.722114 0.469588,\\\n172 0.220124 0.725509 0.466226,\\\n173 0.226397 0.728888 0.462789,\\\n174 0.232815 0.732247 0.459277,\\\n175 0.239374 0.735588 0.455688,\\\n176 0.246070 0.738910 0.452024,\\\n177 0.252899 0.742211 0.448284,\\\n178 0.259857 0.745492 0.444467,\\\n179 0.266941 0.748751 0.440573,\\\n180 0.274149 0.751988 0.436601,\\\n181 0.281477 0.755203 0.432552,\\\n182 0.288921 0.758394 0.428426,\\\n183 0.296479 0.761561 0.424223,\\\n184 0.304148 0.764704 0.419943,\\\n185 0.311925 0.767822 0.415586,\\\n186 0.319809 0.770914 0.411152,\\\n187 0.327796 0.773980 0.406640,\\\n188 0.335885 0.777018 0.402049,\\\n189 0.344074 0.780029 0.397381,\\\n190 0.352360 0.783011 0.392636,\\\n191 0.360741 0.785964 0.387814,\\\n192 0.369214 0.788888 0.382914,\\\n193 0.377779 0.791781 0.377939,\\\n194 0.386433 0.794644 0.372886,\\\n195 0.395174 0.797475 0.367757,\\\n196 0.404001 0.800275 0.362552,\\\n197 0.412913 0.803041 0.357269,\\\n198 0.421908 0.805774 0.351910,\\\n199 0.430983 0.808473 0.346476,\\\n200 0.440137 0.811138 0.340967,\\\n201 0.449368 0.813768 0.335384,\\\n202 0.458674 0.816363 0.329727,\\\n203 0.468053 0.818921 0.323998,\\\n204 0.477504 0.821444 0.318195,\\\n205 0.487026 0.823929 0.312321,\\\n206 0.496615 0.826376 0.306377,\\\n207 0.506271 0.828786 0.300362,\\\n208 0.515992 0.831158 0.294279,\\\n209 0.525776 0.833491 0.288127,\\\n210 0.535621 0.835785 0.281908,\\\n211 0.545524 0.838039 0.275626,\\\n212 0.555484 0.840254 0.269281,\\\n213 0.565498 0.842430 0.262877,\\\n214 0.575563 0.844566 0.256415,\\\n215 0.585678 0.846661 0.249897,\\\n216 0.595839 0.848717 0.243329,\\\n217 0.606045 0.850733 0.236712,\\\n218 0.616293 0.852709 0.230052,\\\n219 0.626579 0.854645 0.223353,\\\n220 0.636902 0.856542 0.216620,\\\n221 0.647257 0.858400 0.209861,\\\n222 0.657642 0.860219 0.203082,\\\n223 0.668054 0.861999 0.196293,\\\n224 0.678489 0.863742 0.189503,\\\n225 0.688944 0.865448 0.182725,\\\n226 0.699415 0.867117 0.175971,\\\n227 0.709898 0.868751 0.169257,\\\n228 0.720391 0.870350 0.162603,\\\n229 0.730889 0.871916 0.156029,\\\n230 0.741388 0.873449 0.149561,\\\n231 0.751884 0.874951 0.143228,\\\n232 0.762373 0.876424 0.137064,\\\n233 0.772852 0.877868 0.131109,\\\n234 0.783315 0.879285 0.125405,\\\n235 0.793760 0.880678 0.120005,\\\n236 0.804182 0.882046 0.114965,\\\n237 0.814576 0.883393 0.110347,\\\n238 0.824940 0.884720 0.106217,\\\n239 0.835270 0.886029 0.102646,\\\n240 0.845561 0.887322 0.099702,\\\n241 0.855810 0.888601 0.097452,\\\n242 0.866013 0.889868 0.095953,\\\n243 0.876168 0.891125 0.095250,\\\n244 0.886271 0.892374 0.095374,\\\n245 0.896320 0.893616 0.096335,\\\n246 0.906311 0.894855 0.098125,\\\n247 0.916242 0.896091 0.100717,\\\n248 0.926106 0.897330 0.104071,\\\n249 0.935904 0.898570 0.108131,\\\n250 0.945636 0.899815 0.112838,\\\n251 0.955300 0.901065 0.118128,\\\n252 0.964894 0.902323 0.123941,\\\n253 0.974417 0.903590 0.130215,\\\n254 0.983868 0.904867 0.136897,\\\n255 0.993248 0.906157 0.143936)\n" }, + { "whylrd", "# line styles\nset style line 1 lt 1 lc rgb '#ffffff' # white\nset style line 2 lt 1 lc rgb '#ffee00' # \nset style line 3 lt 1 lc rgb '#ff7000' # yellow\nset style line 4 lt 1 lc rgb '#ee0000' #\nset style line 5 lt 1 lc rgb '#7f0000' # red\n\n# palette\nset palette defined ( \\\n 0 '#ffffff', \\\n 1 '#ffee00', \\\n 2 '#ff7000', \\\n 3 '#ee0000', \\\n 4 '#7f0000')\n" }, + { "ylgn", "# line styles for ColorBrewer YlGn\n# for use with sequential data\n# provides 8 yellow-green colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFFFE5' # very light yellow-green\nset style line 2 lt 1 lc rgb '#F7FCB9' # \nset style line 3 lt 1 lc rgb '#D9F0A3' # \nset style line 4 lt 1 lc rgb '#ADDD8E' # light yellow-green\nset style line 5 lt 1 lc rgb '#78C679' # \nset style line 6 lt 1 lc rgb '#41AB5D' # medium yellow-green\nset style line 7 lt 1 lc rgb '#238443' #\nset style line 8 lt 1 lc rgb '#005A32' # dark yellow-green\n\n# palette\nset palette defined ( 0 '#FFFFE5',\\\n \t \t 1 '#F7FCB9',\\\n\t\t 2 '#D9F0A3',\\\n\t\t 3 '#ADDD8E',\\\n\t\t 4 '#78C679',\\\n\t\t 5 '#41AB5D',\\\n\t\t 6 '#238443',\\\n\t\t 7 '#005A32' )\n" }, + { "ylgnbu", "# line styles for ColorBrewer YlGnBu\n# for use with sequential data\n# provides 8 yellow-green-blue colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFFFD9' # very light yellow-green-blue\nset style line 2 lt 1 lc rgb '#EDF8B1' # \nset style line 3 lt 1 lc rgb '#C7E9B4' # \nset style line 4 lt 1 lc rgb '#7FCDBB' # light yellow-green-blue\nset style line 5 lt 1 lc rgb '#41B6C4' # \nset style line 6 lt 1 lc rgb '#1D91C0' # medium yellow-green-blue\nset style line 7 lt 1 lc rgb '#225EA8' #\nset style line 8 lt 1 lc rgb '#0C2C84' # dark yellow-green-blue\n\n# palette\nset palette defined ( 0 '#FFFFD9',\\\n \t \t 1 '#EDF8B1',\\\n\t\t 2 '#C7E9B4',\\\n\t\t 3 '#7FCDBB',\\\n\t\t 4 '#41B6C4',\\\n\t\t 5 '#1D91C0',\\\n\t\t 6 '#225EA8',\\\n\t\t 7 '#0C2C84' )\n" }, + { "ylorbr", "# line styles for ColorBrewer YlOrBr\n# for use with sequential data\n# provides 8 yellow-orange-brown colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFFFE5' # very light yellow-orange-brown\nset style line 2 lt 1 lc rgb '#FFF7BC' # \nset style line 3 lt 1 lc rgb '#FEE391' # \nset style line 4 lt 1 lc rgb '#FEC44F' # light yellow-orange-brown\nset style line 5 lt 1 lc rgb '#FE9929' # \nset style line 6 lt 1 lc rgb '#EC7014' # medium yellow-orange-brown\nset style line 7 lt 1 lc rgb '#CC4C02' #\nset style line 8 lt 1 lc rgb '#CC4C02' # dark yellow-orange-brown\n\n# palette\nset palette defined ( 0 '#FFFFE5',\\\n \t \t 1 '#FFF7BC',\\\n\t\t 2 '#FEE391',\\\n\t\t 3 '#FEC44F',\\\n\t\t 4 '#FE9929',\\\n\t\t 5 '#EC7014',\\\n\t\t 6 '#CC4C02',\\\n\t\t 7 '#8C2D04' )\n" }, + { "ylorrd", "# line styles for ColorBrewer YlOrRd\n# for use with sequential data\n# provides 8 yellow-orange-red colors of increasing saturation\n# compatible with gnuplot >=4.2\n# author: Anna Schneider\n\n# line styles\nset style line 1 lt 1 lc rgb '#FFFFCC' # very light yellow-orange-red\nset style line 2 lt 1 lc rgb '#FFEDA0' # \nset style line 3 lt 1 lc rgb '#FED976' # light yellow-orange-red\nset style line 4 lt 1 lc rgb '#FEB24C' # \nset style line 5 lt 1 lc rgb '#FD8D3C' # \nset style line 6 lt 1 lc rgb '#FC4E2A' # medium yellow-orange-red\nset style line 7 lt 1 lc rgb '#E31A1C' #\nset style line 8 lt 1 lc rgb '#B10026' # dark yellow-orange-red\n\n# palette\nset palette defined ( 0 '#FFFFCC',\\\n \t \t 1 '#FFEDA0',\\\n\t\t 2 '#FED976',\\\n\t\t 3 '#FEB24C',\\\n\t\t 4 '#FD8D3C',\\\n\t\t 5 '#FC4E2A',\\\n\t\t 6 '#E31A1C',\\\n\t\t 7 '#B10026' )\n" }, + { "ylrd", "# line styles\nset style line 1 lt 1 lc rgb '#ffee00' # yellow \nset style line 2 lt 1 lc rgb '#ff7000' #\nset style line 3 lt 1 lc rgb '#ee0000' #\nset style line 4 lt 1 lc rgb '#7f0000' # red\n\n# palette\nset palette defined ( \\\n 0 '#ffee00', \\\n 1 '#ff7000', \\\n 2 '#ee0000', \\\n 3 '#7f0000')\n" }, +}; + +} // namespace sciplot + diff --git a/src/cpp/3rdparty/sciplot/Plot.hpp b/src/cpp/3rdparty/sciplot/Plot.hpp new file mode 100755 index 000000000..9a768b8e4 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Plot.hpp @@ -0,0 +1,396 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2022 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include + +// sciplot includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sciplot +{ + +/// The class used to create a plot containing graphical elements. +class Plot +{ + public: + /// Construct a default Plot object + Plot(); + + int column = 0; + /// Virtual destructor to avoid memory leaks + virtual ~Plot() = default; + + /// Set the palette of colors for the plot. + /// @param name Any palette name displayed in https://github.com/Gnuplotting/gnuplot-palettes, such as "viridis", "parula", "jet". + auto palette(const std::string& name) -> Plot&; + + /// Set the size of the plot (in unit of points, with 1 inch = 72 points). + auto size(std::size_t width, std::size_t height) -> Plot&; + + /// Set the font name for the plot (e.g., Helvetica, Georgia, Times). + auto fontName(const std::string& name) -> Plot&; + + /// Set the font size for the plot (e.g., 10, 12, 16). + auto fontSize(std::size_t size) -> Plot&; + + /// Set the border of the plot and return a reference to the corresponding specs object. + auto border() -> BorderSpecs& { return m_border; } + + /// Set the grid of the plot and return a reference to the corresponding specs object. + auto grid() -> GridSpecs& { return m_grid; } + + /// Set the label of the x-axis and return a reference to the corresponding specs object. + auto xlabel(const std::string& label) -> AxisLabelSpecs&; + + /// Set the label of the y-axis and return a reference to the corresponding specs object. + auto ylabel(const std::string& label) -> AxisLabelSpecs&; + + /// Set the x-range of the plot (also possible with empty values or autoscale options (e.g. "", "*")). + auto xrange(const StringOrDouble& min, const StringOrDouble& max) -> Plot&; + + /// Set the y-range of the plot (also possible with empty values or autoscale options (e.g. "", "*")). + auto yrange(const StringOrDouble& min, const StringOrDouble& max) -> Plot&; + + /// Set the default width of boxes in plots containing boxes (in absolute mode). + /// In absolute mode, a unit width is equivalent to one unit of length along the *x* axis. + auto boxWidthAbsolute(double val) -> Plot&; + + /// Set the default width of boxes in plots containing boxes (in relative mode). + /// In relative mode, a unit width is equivalent to setting the boxes side by side. + auto boxWidthRelative(double val) -> Plot&; + + //====================================================================== + // METHODS FOR CUSTOMIZATION OF TICS + //====================================================================== + + /// Set the tics of the plot and return a reference to the corresponding specs object. + auto tics() -> TicsSpecs& { return m_tics; } + + /// Return the specifications of the grid lines along major xtics on the bottom axis. + auto xtics() -> TicsSpecsMajor& { return xticsMajorBottom(); } + + /// Return the specifications of the grid lines along major ytics on the left axis. + auto ytics() -> TicsSpecsMajor& { return yticsMajorLeft(); } + + /// Return the specifications of the grid lines along major ztics. + auto ztics() -> TicsSpecsMajor& { return zticsMajor(); } + + /// Return the specifications of the grid lines along major rtics. + auto rtics() -> TicsSpecsMajor& { return rticsMajor(); } + + /// Return the specifications of the grid lines along major xtics on the bottom axis. + auto xticsMajorBottom() -> TicsSpecsMajor& { return m_xtics_major_bottom; } + + /// Return the specifications of the grid lines along major xtics on the top axis. + auto xticsMajorTop() -> TicsSpecsMajor& { return m_xtics_major_top; } + + /// Return the specifications of the grid lines along minor xtics on the bottom axis. + auto xticsMinorBottom() -> TicsSpecsMinor& { return m_xtics_minor_bottom; } + + /// Return the specifications of the grid lines along minor xtics on the top axis. + auto xticsMinorTop() -> TicsSpecsMinor& { return m_xtics_minor_top; } + + /// Return the specifications of the grid lines along major ytics on the left axis. + auto yticsMajorLeft() -> TicsSpecsMajor& { return m_ytics_major_left; } + + /// Return the specifications of the grid lines along major ytics on the right axis. + auto yticsMajorRight() -> TicsSpecsMajor& { return m_ytics_major_right; } + + /// Return the specifications of the grid lines along minor ytics on the left axis. + auto yticsMinorLeft() -> TicsSpecsMinor& { return m_ytics_minor_left; } + + /// Return the specifications of the grid lines along minor ytics on the right axis. + auto yticsMinorRight() -> TicsSpecsMinor& { return m_ytics_minor_right; } + + /// Return the specifications of the grid lines along major ztics. + auto zticsMajor() -> TicsSpecsMajor& { return m_ztics_major; } + + /// Return the specifications of the grid lines along minor ztics. + auto zticsMinor() -> TicsSpecsMinor& { return m_ztics_minor; } + + /// Return the specifications of the grid lines along minor rtics. + auto rticsMajor() -> TicsSpecsMajor& { return m_rtics_major; } + + /// Return the specifications of the grid lines along minor rtics. + auto rticsMinor() -> TicsSpecsMinor& { return m_rtics_minor; } + + //====================================================================== + // METHODS FOR CUSTOMIZATION OF STYLES + //====================================================================== + + /// Return an object that permits fill style to be customized. + auto styleFill() -> FillStyleSpecs& { return m_style_fill; } + + /// Return an object that permits histogram style to be customized. + auto styleHistogram() -> HistogramStyleSpecs& { return m_style_histogram; } + + //====================================================================== + // METHODS FOR DRAWING PLOT ELEMENTS + //====================================================================== + + /// Draw plot object with given `what`, `using` and `with` expressions (e.g., `plot.draw("sin(x)*cos(x)", "", "linespoints")`, (e.g., `plot.draw("file.dat", "1:2", "points")`)). + auto draw(const std::string& what, const std::string& use, const std::string& with) -> DrawSpecs&; + + //====================================================================== + // MISCElLANEOUS METHODS + //====================================================================== + + /// Set the legend of the plot and return a reference to the corresponding specs object. + auto legend() -> LegendSpecs&; + + /// Set the number of sample points for analytical plots. + auto samples(std::size_t value) -> void; + + /// Use this method to provide gnuplot commands to be executed before the plotting calls. + auto gnuplot(const std::string& command) -> void; + + /// Write the current plot data to the data file. + auto savePlotData() const -> void; + + /// Toggle automatic cleaning of temporary files (enabled by default). Pass false if you want to keep your script / data files. + /// Call cleanup() to remove those files manually. + auto autoclean(bool enable = true) -> void; + + /// Delete all files used to store plot data or scripts. + auto cleanup() const -> void; + + /// Clear all draw and gnuplot commands. + /// @note This method leaves all other plot properties untouched. + auto clear() -> void; + + /// Convert this plot object into a gnuplot formatted string. + virtual auto repr() const -> std::string = 0; + + protected: + static std::size_t m_counter; ///< Counter of how many plot / singleplot objects have been instanciated in the application + std::size_t m_id = 0; ///< The Plot id derived from m_counter upon construction (must be the first member due to constructor initialization order!) + bool m_autoclean = true; ///< Toggle automatic cleaning of temporary files (enabled by default) + std::string m_palette; ///< The name of the gnuplot palette to be used + std::size_t m_width = 0; ///< The size of the plot in x + std::size_t m_height = 0; ///< The size of the plot in y + std::string m_datafilename; ///< The multi data set file where data given to plot (e.g., vectors) are saved + std::string m_data; ///< The current plot data as a string + std::size_t m_numdatasets = 0; ///< The current number of data sets in the data file + FontSpecs m_font; ///< The font name and size in the plot + BorderSpecs m_border; ///< The border style of the plot + GridSpecs m_grid; ///< The vector of grid specs for the major and minor grid lines in the plot (for xtics, ytics, mxtics, etc.). + std::string m_xrange; ///< The x-range of the plot as a gnuplot formatted string (e.g., "set xrange [0:1]") + std::string m_yrange; ///< The y-range of the plot as a gnuplot formatted string (e.g., "set yrange [0:1]") + HistogramStyleSpecs m_style_histogram; ///< The specs for the histogram style of the plot. + TicsSpecs m_tics; ///< The specs of the tics of the plot + TicsSpecsMajor m_xtics_major_bottom; ///< The specs for the major xtics at the bottom. + TicsSpecsMajor m_xtics_major_top; ///< The specs for the major xtics at the top. + TicsSpecsMinor m_xtics_minor_bottom; ///< The specs for the minor xtics at the bottom. + TicsSpecsMinor m_xtics_minor_top; ///< The specs for the minor xtics at the top. + TicsSpecsMajor m_ytics_major_left; ///< The specs for the major ytics at the left. + TicsSpecsMajor m_ytics_major_right; ///< The specs for the major ytics at the right. + TicsSpecsMinor m_ytics_minor_left; ///< The specs for the minor ytics at the left. + TicsSpecsMinor m_ytics_minor_right; ///< The specs for the minor ytics at the right. + TicsSpecsMajor m_ztics_major; ///< The specs for the major ztics. + TicsSpecsMinor m_ztics_minor; ///< The specs for the minor ztics. + TicsSpecsMajor m_rtics_major; ///< The specs for the major rtics. + TicsSpecsMinor m_rtics_minor; ///< The specs for the minor rtics. + AxisLabelSpecs m_xlabel; ///< The label of the x-axis + AxisLabelSpecs m_ylabel; ///< The label of the y-axis + AxisLabelSpecs m_rlabel; ///< The label of the r-axis + std::string m_boxwidth; ///< The default width of boxes in plots containing boxes without given widths. + FillStyleSpecs m_style_fill; ///< The specs for the fill style of the plot elements in the plot that can be painted. + std::string m_samples; ///< The number of sample points for functions + LegendSpecs m_legend; ///< The legend specs of the plot + std::vector m_drawspecs; ///< The plot specs for each call to gnuplot plot function + std::vector m_customcmds; ///< The strings containing gnuplot custom commands +}; + +// Initialize the counter of plot objects +inline std::size_t Plot::m_counter = 0; + +inline Plot::Plot() + : m_id(m_counter++), m_datafilename("plot" + internal::str(m_id) + ".dat"), m_xtics_major_bottom("x"), m_xtics_major_top("x2"), m_xtics_minor_bottom("x"), m_xtics_minor_top("x2"), m_ytics_major_left("y"), m_ytics_major_right("y2"), m_ytics_minor_left("y"), m_ytics_minor_right("y2"), m_ztics_major("z"), m_ztics_minor("z"), m_rtics_major("r"), m_rtics_minor("r"), m_xlabel("x"), m_ylabel("y"), m_rlabel("r") +{ + // Show only major and minor xtics and ytics + xticsMajorBottom().show(); + xticsMinorBottom().show(); + yticsMajorLeft().show(); + yticsMinorLeft().show(); + // Hide all other tics + xticsMajorTop().hide(); + xticsMinorTop().hide(); + yticsMajorRight().hide(); + yticsMinorRight().hide(); + zticsMajor().hide(); + zticsMinor().hide(); + rticsMajor().hide(); + rticsMinor().hide(); + // Default options for fill style + styleFill().solid(); + styleFill().borderHide(); + // Set all other default options + boxWidthRelative(internal::DEFAULT_FIGURE_BOXWIDTH_RELATIVE); + // This is needed because of how drawHistogram works. Using `with histograms` don't work as well. + gnuplot("set style data histogram"); +} + +inline auto Plot::palette(const std::string& name) -> Plot& +{ + m_palette = name; + return *this; +} + +inline auto Plot::size(std::size_t width, std::size_t height) -> Plot& +{ + m_width = width; + m_height = height; + return *this; +} + +inline auto Plot::fontName(const std::string& name) -> Plot& +{ + m_font.fontName(name); + m_legend.fontName(name); + return *this; +} + +inline auto Plot::fontSize(std::size_t size) -> Plot& +{ + m_font.fontSize(size); + m_legend.fontSize(size); + return *this; +} + +inline auto Plot::xlabel(const std::string& label) -> AxisLabelSpecs& +{ + m_xlabel.text(label); + return m_xlabel; +} + +inline auto Plot::ylabel(const std::string& label) -> AxisLabelSpecs& +{ + m_ylabel.text(label); + return m_ylabel; +} + +inline auto Plot::xrange(const StringOrDouble& min, const StringOrDouble& max) -> Plot& +{ + m_xrange = "[" + min.value + ":" + max.value + "]"; + return *this; +} + +inline auto Plot::yrange(const StringOrDouble& min, const StringOrDouble& max) -> Plot& +{ + m_yrange = "[" + min.value + ":" + max.value + "]"; + return *this; +} + +inline auto Plot::boxWidthAbsolute(double val) -> Plot& +{ + m_boxwidth = internal::str(val) + " absolute"; + return *this; +} + +inline auto Plot::boxWidthRelative(double val) -> Plot& +{ + m_boxwidth = internal::str(val) + " relative"; + return *this; +} + +//====================================================================== +// METHODS FOR DRAWING PLOT ELEMENTS +//====================================================================== + +inline auto Plot::draw(const std::string& what, const std::string& use, const std::string& with) -> DrawSpecs& +{ + // Save the draw arguments for this x,y data + m_drawspecs.emplace_back(what, use, with); + // Return the just created drawing object in case the user wants to customize it + return m_drawspecs.back(); +} + +//====================================================================== +// MISCELLANEOUS METHODS +//====================================================================== + +inline auto Plot::legend() -> LegendSpecs& +{ + return m_legend; +} + +inline auto Plot::samples(std::size_t value) -> void +{ + m_samples = internal::str(value); +} + +inline auto Plot::gnuplot(const std::string& command) -> void +{ + m_customcmds.push_back(command); +} + +inline auto Plot::savePlotData() const -> void +{ + // Open data file, truncate it and write all current plot data to it + if (!m_data.empty()) + { + std::ofstream data(m_datafilename); + data << m_data; + } +} + +inline auto Plot::autoclean(bool enable) -> void +{ + m_autoclean = enable; +} + +inline auto Plot::cleanup() const -> void +{ + std::remove(m_datafilename.c_str()); +} + +inline auto Plot::clear() -> void +{ + m_drawspecs.clear(); + m_customcmds.clear(); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Plot2D.hpp b/src/cpp/3rdparty/sciplot/Plot2D.hpp new file mode 100755 index 000000000..6c9be9a9b --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Plot2D.hpp @@ -0,0 +1,770 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2022 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include + +// sciplot includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sciplot +{ + +/// The class used to create a plot containing graphical elements. +class Plot2D : public Plot +{ + public: + /// Construct a default Plot object + Plot2D(); + + bool timed = false; + //====================================================================== + // METHODS FOR DRAWING PLOT ELEMENTS + //====================================================================== + /// Draw plot object with given style and given vectors (e.g., `plot.draw("lines", x, y)`). + template + auto drawWithVecs(const std::string& with, const X&, const Vecs&... vecs) -> DrawSpecs&; + + /// Draw plot object with given style and given vectors (e.g., `plot.draw("lines", x, y)`) that may contain NaN values. + template + auto drawWithVecsContainingNaN(std::string with, const X&, const Vecs&... vecs) -> DrawSpecs&; + + /// Draw a curve with given @p x and @p y vectors. + template + auto drawCurve(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw a curve with points with given @p x and @p y vectors. + template + auto drawCurveWithPoints(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* with given @p x, @p y, and @p xdelta vectors. + template + auto drawCurveWithErrorBarsX(const X& x, const Y& y, const XD& xdelta) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* with given @p x, @p y, @p xlow, and @p xhigh vectors. + template + auto drawCurveWithErrorBarsX(const X& x, const Y& y, const XL& xlow, const XH& xhigh) -> DrawSpecs&; + + /// Draw a curve with error bars along *y* with given @p x, @p y, and @p ydelta vectors. + template + auto drawCurveWithErrorBarsY(const X& x, const Y& y, const YD& ydelta) -> DrawSpecs&; + + /// Draw a curve with error bars along *y* with given @p x, @p y, @p ylow, and @p yhigh vectors. + template + auto drawCurveWithErrorBarsY(const X& x, const Y& y, const YL& ylow, const YH& yhigh) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* and *y* with given @p x, @p y, @p xdelta, and @p ydelta vectors. + template + auto drawCurveWithErrorBarsXY(const X& x, const Y& y, const XD& xdelta, const YD& ydelta) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* and *y* with given @p x, @p y, @p xlow, @p xhigh, @p ylow, and @p yhigh vectors. + template + auto drawCurveWithErrorBarsXY(const X& x, const Y& y, const XL& xlow, const XH& xhigh, const YL& ylow, const YH& yhigh) -> DrawSpecs&; + + /// Draw a curve with given @p x and @p y vectors, breaking this curve whenever NaN is found in @p x or @p y. + template + auto drawBrokenCurve(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw a curve with points with given @p x and @p y vectors, breaking this curve whenever NaN is found in @p x or @p y. + template + auto drawBrokenCurveWithPoints(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw curves with given @p x and @p y vectors with filled areas above / below axes. + template + auto drawCurveFilled(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw curves with given @p x, @p y1 and @p y2 vectors with filled areas above / below / between curves. + template + auto drawCurvesFilled(const X& x, const Y1& y1, const Y2& y2) -> DrawSpecs&; + + /// Draw boxes with given @p x and @p y vectors. + template + auto drawBoxes(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw boxes with given @p x and @p y vectors as well as the box widths @p xwidth. + template + auto drawBoxes(const X& x, const Y& y, const XW& xwidth) -> DrawSpecs&; + + /// Draw boxes with error bars along *y* with given @p x, @p y, @p ydelta vectors. + template + auto drawBoxesWithErrorBarsY(const X& x, const Y& y, const Y& ydelta) -> DrawSpecs&; + + /// Draw boxes with error bars along *y* with given @p x, @p y, @p ylow, and @p yhigh vectors. + template + auto drawBoxesWithErrorBarsY(const X& x, const Y& y, const YL& ylow, const YH& yhigh) -> DrawSpecs&; + + /// Draw error bars along *x* with given @p x, @p y, and @p xdelta vectors. + template + auto drawErrorBarsX(const X& x, const Y& y, const XD& xdelta) -> DrawSpecs&; + + /// Draw error bars along *x* with given @p x, @p y, @p xlow, and @p xhigh vectors. + template + auto drawErrorBarsX(const X& x, const Y& y, const XL& xlow, const XH& xhigh) -> DrawSpecs&; + + /// Draw error bars along *y* with given @p x, @p y, and @p ydelta vectors. + template + auto drawErrorBarsY(const X& x, const Y& y, const YD& ydelta) -> DrawSpecs&; + + /// Draw error bars along *y* with given @p x, @p y, @p ylow, and @p yhigh vectors. + template + auto drawErrorBarsY(const X& x, const Y& y, const YL& ylow, const YH& yhigh) -> DrawSpecs&; + + /// Draw error bars along *x* and *y* with given @p x, @p y, @p xdelta, and @p ydelta vectors. + template + auto drawErrorBarsXY(const X& x, const Y& y, const XD& xdelta, const YD& ydelta) -> DrawSpecs&; + + /// Draw error bars along *x* and *y* with given @p x, @p y, @p xlow, @p xhigh, @p ylow, and @p yhigh vectors. + template + auto drawErrorBarsXY(const X& x, const Y& y, const XL& xlow, const XH& xhigh, const YL& ylow, const YH& yhigh) -> DrawSpecs&; + + /// Draw steps with given @p x and @p y vectors. Identical to @ref drawStepsChangeFirstX. + template + auto drawSteps(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw steps with given @p x and @p y vectors with steps along *x* changes first. + template + auto drawStepsChangeFirstX(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw steps with given @p x and @p y vectors with steps along *y* changes first. + template + auto drawStepsChangeFirstY(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw steps with given @p x and @p y vectors in a histogram style + template + auto drawStepsHistogram(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw steps with given @p x and @p y vectors with filled area below steps. + template + auto drawStepsFilled(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw dots with given @p x and @p y vectors. + template + auto drawDots(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw points with given @p x and @p y vectors. + template + auto drawPoints(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw impulses with given @p x and @p y vectors. + template + auto drawImpulses(const X& x, const Y& y) -> DrawSpecs&; + + /// Draw a histogram for the given @p y vector. + template + auto drawHistogram(const Y& y) -> DrawSpecs&; + + //====================================================================== + // METHODS FOR DRAWING PLOT ELEMENTS USING DATA FROM LOCAL FILES + //====================================================================== + + /// Draw plot object with given style and given vectors (e.g., `plot.draw("lines", x, y)`). + auto drawWithCols(const std::string& fname, const std::string& with, const std::vector& cols) -> DrawSpecs&; + + /// Draw a curve with given values at @p xcol and @p ycol columns in file @p fname. + auto drawCurve(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw a curve with points with given values at @p xcol and @p ycol columns in file @p fname. + auto drawCurveWithPoints(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* with given values at @p xcol, @p ycol, and @p xdeltacol columns in file @p fname. + auto drawCurveWithErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* with given values at @p xcol, @p ycol, @p xlowcol, and @p xhighcol columns in file @p fname. + auto drawCurveWithErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol) -> DrawSpecs&; + + /// Draw a curve with error bars along *y* with given values at @p xcol, @p ycol, and @p ydeltacol columns in file @p fname. + auto drawCurveWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ydeltacol) -> DrawSpecs&; + + /// Draw a curve with error bars along *y* with given values at @p xcol, @p ycol, @p ylowcol, and @p yhighcol columns in file @p fname. + auto drawCurveWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* and *y* with given values at @p xcol, @p ycol, @p xdeltacol, and @p ydeltacol columns in file @p fname. + auto drawCurveWithErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol, ColumnIndex ydeltacol) -> DrawSpecs&; + + /// Draw a curve with error bars along *x* and *y* with given values at @p xcol, @p ycol, @p xlowcol, @p xhighcol, @p ylowcol, and @p yhighcol columns in file @p fname. + auto drawCurveWithErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs&; + + /// Draw boxes with given values at @p xcol and @p ycol columns in file @p fname. + auto drawBoxes(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw boxes with given values at @p xcol and @p ycol columns in file @p fname as well as the box widths @p xwidthcol. + auto drawBoxes(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xwidthcol) -> DrawSpecs&; + + /// Draw boxes with error bars along *y* with given values at @p xcol, @p ycol, @p ydeltacol columns in file @p fname. + auto drawBoxesWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ydeltacol) -> DrawSpecs&; + + /// Draw boxes with error bars along *y* with given values at @p xcol, @p ycol, @p ylowcol, and @p yhighcol columns in file @p fname. + auto drawBoxesWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs&; + + /// Draw error bars along *x* with given values at @p xcol, @p ycol, and @p xdeltacol columns in file @p fname. + auto drawErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol) -> DrawSpecs&; + + /// Draw error bars along *x* with given values at @p xcol, @p ycol, @p xlowcol, and @p xhighcol columns in file @p fname. + auto drawErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol) -> DrawSpecs&; + + /// Draw error bars along *y* with given values at @p xcol, @p ycol, and @p ydeltacol columns in file @p fname. + auto drawErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ydeltacol) -> DrawSpecs&; + + /// Draw error bars along *y* with given values at @p xcol, @p ycol, @p ylowcol, and @p yhighcol columns in file @p fname. + auto drawErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs&; + + /// Draw error bars along *x* and *y* with given values at @p xcol, @p ycol, @p xdeltacol, and @p ydeltacol columns in file @p fname. + auto drawErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol, ColumnIndex ydeltacol) -> DrawSpecs&; + + /// Draw error bars along *x* and *y* with given values at @p xcol, @p ycol, @p xlowcol, @p xhighcol, @p ylowcol, and @p yhighcol columns in file @p fname. + auto drawErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs&; + + /// Draw steps with given values at @p xcol and @p ycol columns in file @p fname. Identical to @ref drawStepsChangeFirstX. + auto drawSteps(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw steps with given values at @p xcol and @p ycol columns in file @p fname with steps along *x* changes first. + auto drawStepsChangeFirstX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw steps with given values at @p xcol and @p ycol columns in file @p fname with steps along *y* changes first. + auto drawStepsChangeFirstY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw steps with given values at @p xcol and @p ycol columns in file @p fname in a histogram style + auto drawStepsHistogram(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw steps with given values at @p xcol and @p ycol columns in file @p fname with filled area below steps. + auto drawStepsFilled(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw dots with given values at @p xcol and @p ycol columns in file @p fname. + auto drawDots(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw points with given values at @p xcol and @p ycol columns in file @p fname. + auto drawPoints(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw impulses with given values at @p xcol and @p ycol columns in file @p fname. + auto drawImpulses(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw a histogram with given values at @p ycol column in file @p fname. + auto drawHistogram(std::string fname, ColumnIndex ycol) -> DrawSpecs&; + + //====================================================================== + // MISCElLANEOUS METHODS + //====================================================================== + + /// Convert this plot object into a gnuplot formatted string. + auto repr() const -> std::string override; +}; + +inline Plot2D::Plot2D() + : Plot() +{ +} + +//====================================================================== +// METHODS FOR DRAWING PLOT ELEMENTS +//====================================================================== + +template +inline auto Plot2D::drawWithVecs(const std::string& with, const X& x, const Vecs&... vecs) -> DrawSpecs& +{ + // Write the given vectors x and y as a new data set to the stream + std::ostringstream datastream; + gnuplot::writedataset(datastream, m_numdatasets, x, vecs...); + + // Set the using string to "" if X is not vector of strings. + // Otherwise, x contain xtics strings. Set the `using` string + // so that these are properly used as xtics. + std::string use; + if constexpr (internal::isStringVector) + { + const auto nvecs = sizeof...(Vecs); + use = "0:"; // here, column 0 means the pseudo column with numbers 0, 1, 2, 3... + for (auto i = 2; i <= nvecs + 1; ++i) + use += std::to_string(i) + ":"; // this constructs 0:2:3:4: + use += "xtic(1)"; // this terminates the string with 0:2:3:4:xtic(1), and thus column 1 is used for the xtics + } + + // Append new data set to existing data + m_data += datastream.str(); + + // Draw the data saved using a data set with index `m_numdatasets`. Increase number of data sets and set the line style specification (desired behavior is 1, 2, 3 (incrementing as new lines are plotted)). + return draw("'" + m_datafilename + "' " + (timed ? "using 1:3" : "") + " index " + internal::str(m_numdatasets++), use, with).lineStyle(static_cast(m_drawspecs.size())); +} + +template +inline auto Plot2D::drawWithVecsContainingNaN(std::string with, const X& x, const Vecs&... vecs) -> DrawSpecs& +{ + // Write the given vectors x and y as a new data set to the stream + std::ostringstream datastream; + gnuplot::writedataset(datastream, m_numdatasets, x, vecs...); + + std::string use; + const auto nvecs = sizeof...(Vecs); + use = "0:"; // here, column 0 means the pseudo column with numbers 0, 1, 2, 3... + for (auto i = 2; i <= nvecs + 1; ++i) + use += "($" + std::to_string(i) + "):"; // this constructs 0:$(2):$(3):$(4): + use += "xtic(1)"; // this terminates the string with 0:$(2):$(3):$(4):xtic(1), and thus column 1 is used for the xtics + + // Append new data set to existing data + m_data += datastream.str(); + + // Draw the data saved using a data set with index `m_numdatasets`. Increase number of data sets and set the line style specification (desired behavior is 1, 2, 3 (incrementing as new lines are plotted)). + return draw("'" + m_datafilename + "' index " + internal::str(m_numdatasets++), use, with).lineStyle(static_cast(m_drawspecs.size())); +} + +template +inline auto Plot2D::drawCurve(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("lines", x, y); +} + +template +inline auto Plot2D::drawCurveWithPoints(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("linespoints", x, y); +} + +template +inline auto Plot2D::drawCurveWithErrorBarsX(const X& x, const Y& y, const XD& xdelta) -> DrawSpecs& +{ + return drawWithVecs("xerrorlines", x, y, xdelta); +} + +template +inline auto Plot2D::drawCurveWithErrorBarsX(const X& x, const Y& y, const XL& xlow, const XH& xhigh) -> DrawSpecs& +{ + return drawWithVecs("xerrorlines", x, y, xlow, xhigh); +} + +template +inline auto Plot2D::drawCurveWithErrorBarsY(const X& x, const Y& y, const YD& ydelta) -> DrawSpecs& +{ + return drawWithVecs("yerrorlines", x, y, ydelta); +} + +template +inline auto Plot2D::drawCurveWithErrorBarsY(const X& x, const Y& y, const YL& ylow, const YH& yhigh) -> DrawSpecs& +{ + return drawWithVecs("yerrorlines", x, y, ylow, yhigh); +} + +template +inline auto Plot2D::drawCurveWithErrorBarsXY(const X& x, const Y& y, const XD& xdelta, const YD& ydelta) -> DrawSpecs& +{ + return drawWithVecs("xyerrorlines", x, y, xdelta, ydelta); +} + +template +inline auto Plot2D::drawCurveWithErrorBarsXY(const X& x, const Y& y, const XL& xlow, const XH& xhigh, const YL& ylow, const YH& yhigh) -> DrawSpecs& +{ + return drawWithVecs("xyerrorlines", x, y, xlow, xhigh, ylow, yhigh); +} + +template +inline auto Plot2D::drawBrokenCurve(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecsContainingNaN("lines", x, y); +} + +template +inline auto Plot2D::drawBrokenCurveWithPoints(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecsContainingNaN("linespoints", x, y); +} + +template +inline auto Plot2D::drawCurveFilled(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("filledcurves", x, y); +} + +template +inline auto Plot2D::drawCurvesFilled(const X& x, const Y1& y1, const Y2& y2) -> DrawSpecs& +{ + return drawWithVecs("filledcurves", x, y1, y2); +} + +template +inline auto Plot2D::drawBoxes(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("boxes", x, y); +} + +template +inline auto Plot2D::drawBoxes(const X& x, const Y& y, const XW& xwidth) -> DrawSpecs& +{ + return drawWithVecs("boxes", x, y, xwidth); +} + +template +inline auto Plot2D::drawBoxesWithErrorBarsY(const X& x, const Y& y, const Y& ydelta) -> DrawSpecs& +{ + return drawWithVecs("boxerrorbars", x, y, ydelta); +} + +template +inline auto Plot2D::drawBoxesWithErrorBarsY(const X& x, const Y& y, const YL& ylow, const YH& yhigh) -> DrawSpecs& +{ + return drawWithVecs("boxerrorbars", x, y, ylow, yhigh); +} + +template +inline auto Plot2D::drawErrorBarsX(const X& x, const Y& y, const XD& xdelta) -> DrawSpecs& +{ + return drawWithVecs("xerrorbars", x, y, xdelta); +} + +template +inline auto Plot2D::drawErrorBarsX(const X& x, const Y& y, const XL& xlow, const XH& xhigh) -> DrawSpecs& +{ + return drawWithVecs("xerrorbars", x, y, xlow, xhigh); +} + +template +inline auto Plot2D::drawErrorBarsY(const X& x, const Y& y, const YD& ydelta) -> DrawSpecs& +{ + return drawWithVecs("yerrorbars", x, y, ydelta); +} + +template +inline auto Plot2D::drawErrorBarsY(const X& x, const Y& y, const YL& ylow, const YH& yhigh) -> DrawSpecs& +{ + return drawWithVecs("yerrorbars", x, y, ylow, yhigh); +} + +template +inline auto Plot2D::drawErrorBarsXY(const X& x, const Y& y, const XD& xdelta, const YD& ydelta) -> DrawSpecs& +{ + return drawWithVecs("xyerrorbars", x, y, xdelta, ydelta); +} + +template +inline auto Plot2D::drawErrorBarsXY(const X& x, const Y& y, const XL& xlow, const XH& xhigh, const YL& ylow, const YH& yhigh) -> DrawSpecs& +{ + return drawWithVecs("xyerrorbars", x, y, xlow, xhigh, ylow, yhigh); +} + +template +inline auto Plot2D::drawSteps(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecsStepsChangeFirstX(x, y); +} + +template +inline auto Plot2D::drawStepsChangeFirstX(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("steps", x, y); +} + +template +inline auto Plot2D::drawStepsChangeFirstY(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("fsteps", x, y); +} + +template +inline auto Plot2D::drawStepsHistogram(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("histeps", x, y); +} + +template +inline auto Plot2D::drawStepsFilled(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("fillsteps", x, y); +} + +template +inline auto Plot2D::drawDots(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("dots", x, y); +} + +template +inline auto Plot2D::drawPoints(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("points", x, y); +} + +template +inline auto Plot2D::drawImpulses(const X& x, const Y& y) -> DrawSpecs& +{ + return drawWithVecs("impulses", x, y); +} + +template +inline auto Plot2D::drawHistogram(const Y& y) -> DrawSpecs& +{ + return drawWithVecs("", y); // empty string because we rely on `set style data histograms` since relying `with histograms` is not working very well (e.g., empty key/lenged appearing in columnstacked mode). +} + +//====================================================================== +// METHODS FOR DRAWING PLOT ELEMENTS USING DATA FROM LOCAL FILES +//====================================================================== + +inline auto Plot2D::drawWithCols(const std::string& fname, const std::string& with, const std::vector& cols) -> DrawSpecs& +{ + std::string use; + for (const auto& col : cols) + use += col.value + ":"; // e.g., "1:4:5:7:" (where 1 is x, 4 is y, 5 is ylow and 7 is yhigh for a yerrorlines plot) + use = internal::trimright(use, ':'); // e.g., "1:4:5:7:" => "1:4:5:7" + std::string what = "'" + fname + "'"; // e.g., "'myfile.dat'" + return draw(what, use, with).lineStyle(static_cast(m_drawspecs.size())); // e.g., draw(what="'myfile.dat'", use="1:2", with="lines"); +} + +inline auto Plot2D::drawCurve(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "lines", {xcol, ycol}); +} + +inline auto Plot2D::drawCurveWithPoints(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "linespoints", {xcol, ycol}); +} + +inline auto Plot2D::drawCurveWithErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol) -> DrawSpecs& +{ + return drawWithCols(fname, "xerrorlines", {xcol, ycol, xdeltacol}); +} + +inline auto Plot2D::drawCurveWithErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol) -> DrawSpecs& +{ + return drawWithCols(fname, "xerrorlines", {xcol, ycol, xlowcol, xhighcol}); +} + +inline auto Plot2D::drawCurveWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ydeltacol) -> DrawSpecs& +{ + return drawWithCols(fname, "yerrorlines", {xcol, ycol, ydeltacol}); +} + +inline auto Plot2D::drawCurveWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs& +{ + return drawWithCols(fname, "yerrorlines", {xcol, ycol, ylowcol, yhighcol}); +} + +inline auto Plot2D::drawCurveWithErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol, ColumnIndex ydeltacol) -> DrawSpecs& +{ + return drawWithCols(fname, "xyerrorlines", {xcol, ycol, xdeltacol, ydeltacol}); +} + +inline auto Plot2D::drawCurveWithErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs& +{ + return drawWithCols(fname, "xyerrorlines", {xcol, ycol, xlowcol, xhighcol, ylowcol, yhighcol}); +} + +inline auto Plot2D::drawBoxes(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "boxes", {xcol, ycol}); +} + +inline auto Plot2D::drawBoxes(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xwidthcol) -> DrawSpecs& +{ + return drawWithCols(fname, "boxes", {xcol, ycol, xwidthcol}); +} + +inline auto Plot2D::drawBoxesWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ydeltacol) -> DrawSpecs& +{ + return drawWithCols(fname, "boxerrorbars", {xcol, ycol, ydeltacol}); +} + +inline auto Plot2D::drawBoxesWithErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs& +{ + return drawWithCols(fname, "boxerrorbars", {xcol, ycol, ylowcol, yhighcol}); +} + +inline auto Plot2D::drawErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol) -> DrawSpecs& +{ + return drawWithCols(fname, "xerrorbars", {xcol, ycol, xdeltacol}); +} + +inline auto Plot2D::drawErrorBarsX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol) -> DrawSpecs& +{ + return drawWithCols(fname, "xerrorbars", {xcol, ycol, xlowcol, xhighcol}); +} + +inline auto Plot2D::drawErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ydeltacol) -> DrawSpecs& +{ + return drawWithCols(fname, "yerrorbars", {xcol, ycol, ydeltacol}); +} + +inline auto Plot2D::drawErrorBarsY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs& +{ + return drawWithCols(fname, "yerrorbars", {xcol, ycol, ylowcol, yhighcol}); +} + +inline auto Plot2D::drawErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xdeltacol, ColumnIndex ydeltacol) -> DrawSpecs& +{ + return drawWithCols(fname, "xyerrorbars", {xcol, ycol, xdeltacol, ydeltacol}); +} + +inline auto Plot2D::drawErrorBarsXY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol, ColumnIndex xlowcol, ColumnIndex xhighcol, ColumnIndex ylowcol, ColumnIndex yhighcol) -> DrawSpecs& +{ + return drawWithCols(fname, "xyerrorbars", {xcol, ycol, xlowcol, xhighcol, ylowcol, yhighcol}); +} + +inline auto Plot2D::drawSteps(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "steps", {xcol, ycol}); +} + +inline auto Plot2D::drawStepsChangeFirstX(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "steps", {xcol, ycol}); +} + +inline auto Plot2D::drawStepsChangeFirstY(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "fsteps", {xcol, ycol}); +} + +inline auto Plot2D::drawStepsHistogram(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "histeps", {xcol, ycol}); +} + +inline auto Plot2D::drawStepsFilled(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "fillsteps", {xcol, ycol}); +} + +inline auto Plot2D::drawDots(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "dots", {xcol, ycol}); +} + +inline auto Plot2D::drawPoints(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "points", {xcol, ycol}); +} + +inline auto Plot2D::drawImpulses(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "impulses", {xcol, ycol}); +} + +inline auto Plot2D::drawHistogram(std::string fname, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "", {ycol}); +} + +//====================================================================== +// MISCElLANEOUS METHODS +//====================================================================== + +inline auto Plot2D::repr() const -> std::string +{ + std::stringstream script; + // Add plot setup commands + script << "#==============================================================================" << std::endl; + script << "# SETUP COMMANDS" << std::endl; + script << "#==============================================================================" << std::endl; + // Add palette info if a palette was set + if (!m_palette.empty()) + { + gnuplot::palettecmd(script, m_palette); + } + if (timed) + { + script << gnuplot::cmdValueStr("set xdata time", " "); + script << gnuplot::cmdValueStr("set timefmt \"%Y-%m-%d %H:%M:%S\"", " "); + script << gnuplot::cmdValueStr("set format x \"%H:%M\"", " "); + } + script << gnuplot::cmdValueStr("set xrange", m_xrange); + script << gnuplot::cmdValueStr("set yrange", m_yrange); + script << m_xlabel << std::endl; + script << m_ylabel << std::endl; + script << m_rlabel << std::endl; + script << m_border << std::endl; + script << m_grid << std::endl; + script << m_style_fill << std::endl; + script << m_style_histogram << std::endl; + script << m_tics << std::endl; + script << m_xtics_major_bottom << std::endl; + script << m_xtics_major_top << std::endl; + script << m_xtics_minor_bottom << std::endl; + script << m_xtics_minor_top << std::endl; + script << m_ytics_major_left << std::endl; + script << m_ytics_major_right << std::endl; + script << m_ytics_minor_left << std::endl; + script << m_ytics_minor_right << std::endl; + script << m_ztics_major << std::endl; + script << m_ztics_minor << std::endl; + script << m_rtics_major << std::endl; + script << m_rtics_minor << std::endl; + script << m_legend << std::endl; + script << gnuplot::cmdValueStr("set boxwidth", m_boxwidth); + script << gnuplot::cmdValueStr("set samples", m_samples); + script << gnuplot::cmdValueStr("set datafile missing", MISSING_INDICATOR); + // Add custom gnuplot commands + if (!m_customcmds.empty()) + { + script << "#==============================================================================" << std::endl; + script << "# CUSTOM EXPLICIT GNUPLOT COMMANDS" << std::endl; + script << "#==============================================================================" << std::endl; + for (const auto& c : m_customcmds) + { + script << c << std::endl; + } + } + // Add the actual plot commands for all drawXYZ() calls + script << "#==============================================================================" << std::endl; + script << "# PLOT COMMANDS" << std::endl; + script << "#==============================================================================" << std::endl; + script << "plot \\\n"; // use `\` to have a plot command in each individual line! + // Write plot commands and style per plot + const auto n = m_drawspecs.size(); + for (std::size_t i = 0; i < n; ++i) + { + script << " " << m_drawspecs[i] << (i < n - 1 ? ", \\\n" : ""); // consider indentation with 4 spaces! + } + // Add an empty line after plots + script << std::endl; + // unset palette info if a palette was set + if (!m_palette.empty()) + { + gnuplot::unsetpalettecmd(script); + } + // Add an empty line at the end + script << "unset xdata" << std::endl; + script << std::endl; + return script.str(); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Plot3D.hpp b/src/cpp/3rdparty/sciplot/Plot3D.hpp new file mode 100755 index 000000000..e6a8a11cb --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Plot3D.hpp @@ -0,0 +1,342 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2022 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include + +// sciplot includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sciplot +{ + +/// The class used to create a plot containing graphical elements. +class Plot3D : public Plot +{ + public: + /// Construct a default Plot object + Plot3D(); + + /// Set the label of the z-axis and return a reference to the corresponding specs object. + auto zlabel(const std::string& label) -> AxisLabelSpecs&; + + /// Set the z-range of the plot (also possible with empty values or autoscale options (e.g. "", "*")). + auto zrange(StringOrDouble min, StringOrDouble max) -> void; + + //====================================================================== + // METHODS FOR DRAWING PLOT ELEMENTS + //====================================================================== + /// Draw plot object with given style and given vectors (e.g., `plot.draw("lines", x, y)`). + + template + auto drawWithVecs(const std::string& with, const X&, const Vecs&... vecs) -> DrawSpecs&; + + /// Draw a curve with given @p x and @p y vectors. + template + auto drawCurve(const X& x, const Y& y, const Z& z) -> DrawSpecs&; + + /// Draw a curve with points with given @p x and @p y vectors. + template + auto drawCurveWithPoints(const X& x, const Y& y, const Z& z) -> DrawSpecs&; + + /// Draw dots with given @p x and @p y vectors. + template + auto drawDots(const X& x, const Y& y, const Z& z) -> DrawSpecs&; + + /// Draw points with given @p x and @p y vectors. + template + auto drawPoints(const X& x, const Y& y, const Z& z) -> DrawSpecs&; + + /// Draw impulses with given @p x and @p y vectors. + template + auto drawImpulses(const X& x, const Y& y, const Z& z) -> DrawSpecs&; + + /// Draw a histogram for the given @p y vector. + template + auto drawHistogram(const Y& y) -> DrawSpecs&; + + //====================================================================== + // METHODS FOR DRAWING PLOT ELEMENTS USING DATA FROM LOCAL FILES + //====================================================================== + + /// Draw plot object with given style and given vectors (e.g., `plot.draw("lines", x, y)`). + auto drawWithCols(const std::string& fname, const std::string& with, const std::vector& cols) -> DrawSpecs&; + + /// Draw a curve with given values at @p xcol and @p ycol columns in file @p fname. + auto drawCurve(const std::string& fname, const ColumnIndex& col, const ColumnIndex& ycol) -> DrawSpecs&; + + /// Draw a curve with points with given values at @p xcol and @p ycol columns in file @p fname. + auto drawCurveWithPoints(const std::string& fname, const ColumnIndex& xcol, const ColumnIndex& ycol) -> DrawSpecs&; + + /// Draw dots with given values at @p xcol and @p ycol columns in file @p fname. + auto drawDots(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw points with given values at @p xcol and @p ycol columns in file @p fname. + auto drawPoints(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw impulses with given values at @p xcol and @p ycol columns in file @p fname. + auto drawImpulses(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs&; + + /// Draw a histogram with given values at @p ycol column in file @p fname. + auto drawHistogram(const std::string& fname, ColumnIndex ycol) -> DrawSpecs&; + + //====================================================================== + // MISCElLANEOUS METHODS + //====================================================================== + + /// Convert this plot object into a gnuplot formatted string. + auto repr() const -> std::string override; + + private: + std::string m_zrange; ///< The z-range of the plot as a gnuplot formatted string (e.g., "set yrange [0:1]") + AxisLabelSpecs m_zlabel; ///< The label of the z-axis +}; + +inline Plot3D::Plot3D() + : Plot(), m_zlabel("z") +{ +} + +inline auto Plot3D::zlabel(const std::string& label) -> AxisLabelSpecs& +{ + m_zlabel.text(label); + return m_zlabel; +} + +inline auto Plot3D::zrange(StringOrDouble min, StringOrDouble max) -> void +{ + m_zrange = "[" + min.value + ":" + max.value + "]"; +} + +//====================================================================== +// METHODS FOR DRAWING PLOT ELEMENTS +//====================================================================== + +template +inline auto Plot3D::drawWithVecs(const std::string& with, const X& x, const Vecs&... vecs) -> DrawSpecs& +{ + // Write the given vectors x and y as a new data set to the stream + std::ostringstream datastream; + gnuplot::writedataset(datastream, m_numdatasets, x, vecs...); + + // Set the using string to "" if X is not vector of strings. + // Otherwise, x contain xtics strings. Set the `using` string + // so that these are properly used as xtics. + std::string use; + if constexpr (internal::isStringVector) + { + const auto nvecs = sizeof...(Vecs); + use = "0:"; // here, column 0 means the pseudo column with numbers 0, 1, 2, 3... + for (auto i = 2; i <= nvecs + 1; ++i) + use += std::to_string(i) + ":"; // this constructs 0:2:3:4: + use += "xtic(1)"; // this terminates the string with 0:2:3:4:xtic(1), and thus column 1 is used for the xtics + } + + // Append new data set to existing data + m_data += datastream.str(); + + // Draw the data saved using a data set with index `m_numdatasets`. Increase number of data sets and set the line style specification (desired behavior is 1, 2, 3 (incrementing as new lines are plotted)). + return draw("'" + m_datafilename + "' index " + internal::str(m_numdatasets++), use, with).lineStyle(static_cast(m_drawspecs.size())); +} + +template +inline auto Plot3D::drawCurve(const X& x, const Y& y, const Z& z) -> DrawSpecs& +{ + return drawWithVecs("lines", x, y, z); +} + +template +inline auto Plot3D::drawCurveWithPoints(const X& x, const Y& y, const Z& z) -> DrawSpecs& +{ + + return drawWithVecs("linespoints", x, y, z); +} + +template +inline auto Plot3D::drawDots(const X& x, const Y& y, const Z& z) -> DrawSpecs& +{ + return drawWithVecs("dots", x, y, z); +} + +template +inline auto Plot3D::drawPoints(const X& x, const Y& y, const Z& z) -> DrawSpecs& +{ + return drawWithVecs("points", x, y, z); +} + +template +inline auto Plot3D::drawImpulses(const X& x, const Y& y, const Z& z) -> DrawSpecs& +{ + return drawWithVecs("impulses", x, y, z); +} + +template +inline auto Plot3D::drawHistogram(const Y& y) -> DrawSpecs& +{ + return drawWithVecs("", y); // empty string because we rely on `set style data histograms` since relying `with histograms` is not working very well (e.g., empty key/lenged appearing in columnstacked mode). +} + +//====================================================================== +// METHODS FOR DRAWING PLOT ELEMENTS USING DATA FROM LOCAL FILES +//====================================================================== + +inline auto Plot3D::drawWithCols(const std::string& fname, const std::string& with, const std::vector& cols) -> DrawSpecs& +{ + std::string use; + for (const auto& col : cols) + use += col.value + ":"; // e.g., "1:4:5:7:" (where 1 is x, 4 is y, 5 is ylow and 7 is yhigh for a yerrorlines plot) + use = internal::trimright(use, ':'); // e.g., "1:4:5:7:" => "1:4:5:7" + std::string what = "'" + fname + "'"; // e.g., "'myfile.dat'" + return draw(what, use, with).lineStyle(static_cast(m_drawspecs.size())); // e.g., draw(what="'myfile.dat'", use="1:2", with="lines"); +} + +inline auto Plot3D::drawCurve(const std::string& fname, const ColumnIndex& xcol, const ColumnIndex& ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "lines", {xcol, ycol}); +} + +inline auto Plot3D::drawCurveWithPoints(const std::string& fname, const ColumnIndex& xcol, const ColumnIndex& ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "linespoints", {xcol, ycol}); +} + +inline auto Plot3D::drawDots(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "dots", {xcol, ycol}); +} + +inline auto Plot3D::drawPoints(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "points", {xcol, ycol}); +} + +inline auto Plot3D::drawImpulses(const std::string& fname, ColumnIndex xcol, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "impulses", {xcol, ycol}); +} + +inline auto Plot3D::drawHistogram(const std::string& fname, ColumnIndex ycol) -> DrawSpecs& +{ + return drawWithCols(fname, "", {ycol}); +} + +//====================================================================== +// MISCElLANEOUS METHODS +//====================================================================== + +inline auto Plot3D::repr() const -> std::string +{ + std::stringstream script; + + // Add plot setup commands + script << "#==============================================================================" << std::endl; + script << "# SETUP COMMANDS" << std::endl; + script << "#==============================================================================" << std::endl; + // Add palette info if a palette was set + if (!m_palette.empty()) + { + gnuplot::palettecmd(script, m_palette); + } + script << gnuplot::cmdValueStr("set xrange", m_xrange); + script << gnuplot::cmdValueStr("set yrange", m_yrange); + script << gnuplot::cmdValueStr("set zrange", m_zrange); + script << m_xlabel << std::endl; + script << m_ylabel << std::endl; + script << m_zlabel << std::endl; + script << m_rlabel << std::endl; + script << m_border << std::endl; + script << m_grid << std::endl; + script << m_style_fill << std::endl; + script << m_style_histogram << std::endl; + script << m_tics << std::endl; + script << m_xtics_major_bottom << std::endl; + script << m_xtics_major_top << std::endl; + script << m_xtics_minor_bottom << std::endl; + script << m_xtics_minor_top << std::endl; + script << m_ytics_major_left << std::endl; + script << m_ytics_major_right << std::endl; + script << m_ytics_minor_left << std::endl; + script << m_ytics_minor_right << std::endl; + script << m_ztics_major << std::endl; + script << m_ztics_minor << std::endl; + script << m_rtics_major << std::endl; + script << m_rtics_minor << std::endl; + script << m_legend << std::endl; + script << gnuplot::cmdValueStr("set boxwidth", m_boxwidth); + script << gnuplot::cmdValueStr("set samples", m_samples); + // unset palette info if a palette was set + if (!m_palette.empty()) + { + gnuplot::unsetpalettecmd(script); + } + // Add custom gnuplot commands + if (!m_customcmds.empty()) + { + script << "#==============================================================================" << std::endl; + script << "# CUSTOM EXPLICIT GNUPLOT COMMANDS" << std::endl; + script << "#==============================================================================" << std::endl; + for (const auto& c : m_customcmds) + { + script << c << std::endl; + } + } + // Add the actual plot commands for all drawXYZ() calls + script << "#==============================================================================" << std::endl; + script << "# PLOT COMMANDS" << std::endl; + script << "#==============================================================================" << std::endl; + script << "splot \\\n"; // use `\` to have a plot command in each individual line! + // Write plot commands and style per plot + const auto n = m_drawspecs.size(); + for (std::size_t i = 0; i < n; ++i) + { + script << " " << m_drawspecs[i] << (i < n - 1 ? ", \\\n" : ""); // consider indentation with 4 spaces! + } + // Add an empty line at the end + script << std::endl; + return script.str(); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/StringOrDouble.hpp b/src/cpp/3rdparty/sciplot/StringOrDouble.hpp new file mode 100755 index 000000000..ec9ba7dcb --- /dev/null +++ b/src/cpp/3rdparty/sciplot/StringOrDouble.hpp @@ -0,0 +1,52 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include + +namespace sciplot { + +/// An auxiliary type used to store a string value, while the input can also be a double. +struct StringOrDouble +{ + /// Construct a default StringOrDouble object. + StringOrDouble() : StringOrDouble(0.0) {} + + /// Construct a StringOrDouble object with given double. + StringOrDouble(double val) : value(std::to_string(val)) {} // 1.0 => "1.0" + + /// Construct a StringOrDouble object with given string. + StringOrDouble(std::string val) : value(val) {} + + /// Construct a StringOrDouble object with given string. + StringOrDouble(const char* val) : StringOrDouble(std::string(val)) {} + + /// The stored value. + std::string value; +}; + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Utils.hpp b/src/cpp/3rdparty/sciplot/Utils.hpp new file mode 100755 index 000000000..bc56dccb0 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Utils.hpp @@ -0,0 +1,366 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// sciplot includes +#include +#include +#include + +namespace sciplot +{ +namespace internal +{ + +/// Return a string for a given value of a generic type. +template +auto str(const T& val) -> std::string +{ + std::stringstream ss; + ss << std::setprecision(15); + ss << val; + return ss.str(); // Note: This is different than std::to_string(i). For example, it works with custom types. Also, std::to_string(2.0) may produce "2.000000", difficulting string comparison in the tests. +} + +/// Return a string for a given char array +inline auto str(const char* word) -> std::string +{ + return word; +} + +/// Return an empty string +inline auto str() -> std::string +{ + return {}; +} + +/// Remove from the beginning of the string the given character (by default, space). +inline auto trimleft(std::string str, unsigned char character = ' ') -> std::string +{ + str.erase(str.begin(), std::find_if(str.begin(), str.end(), + [&](unsigned char ch) + { return ch != character; })); + return str; +} + +/// Remove from the end of the string the given character (by default, space). +inline auto trimright(std::string str, unsigned char character = ' ') -> std::string +{ + str.erase(std::find_if(str.rbegin(), str.rend(), + [&](unsigned char ch) + { return ch != character; }) + .base(), + str.end()); + return str; +} + +/// Trim the string from both ends +inline auto trim(std::string str, unsigned char character = ' ') -> std::string +{ + return trimleft(trimright(str, character), character); +} + +/// Remove extra spaces from a string (e.g., `"abc acb xy s "` becomes `"abc acb xy s "`). +inline auto collapseWhitespaces(std::string s) -> std::string +{ + s.erase(std::unique(std::begin(s), std::end(s), + [](unsigned char a, unsigned char b) + { return std::isspace(a) && std::isspace(b); }), + std::end(s)); + return s; +} + +/// Trim and collapse all spaces in a string (e.g., `" abc acb xy s "` becomes `"abc acb xy s"`). +inline auto removeExtraWhitespaces(std::string s) -> std::string +{ + return trim(collapseWhitespaces(s)); +} + +/// Auxiliary function that returns the size of the vector argument with least size (for a single vector case) +template +auto minsize(const VectorType& v) -> std::size_t +{ + return v.size(); +} + +/// Auxiliary function that returns the size of the vector argument with least size +template +auto minsize(const VectorType& v, const Args&... args) -> std::size_t +{ + return std::min(v.size(), minsize(args...)); +} + +/// Check if type @p T is `std::string`. +template +constexpr auto isString = std::is_same_v, std::string>; + +/// Check if type @p T is `std::string`. +template +constexpr auto isStringVector = isString()[0])>; + +/// Auxiliary function that returns `" + val + "` if `val` is string, otherwise `val` itself. +template +auto escapeIfNeeded(const T& val) +{ + if constexpr (isString) + return "\"" + val + "\""; // Due bug #102 we escape data using double quotes + else + return std::isfinite(static_cast(val)) ? internal::str(val) : MISSING_INDICATOR; // static_cast to avoid MSVC error C2668: 'fpclassify': ambiguous call to overloaded function +} + +/// Auxiliary function to write many vector arguments into a line of an ostream object +template +auto writeline(std::ostream& out, std::size_t i, const VectorType& v) -> std::ostream& +{ + out << escapeIfNeeded(v[i]) << '\n'; + return out; +} + +/// Auxiliary function to write many vector arguments into a line of an ostream object +template +auto writeline(std::ostream& out, std::size_t i, const VectorType& v, const Args&... args) -> std::ostream& +{ + out << escapeIfNeeded(v[i]) << " "; + writeline(out, i, args...); + return out; +} + +/// Auxiliary function to write many vector arguments into an ostream object +template +auto write(std::ostream& out, const Args&... args) -> std::ostream& +{ + const auto size = minsize(args...); + for (std::size_t i = 0; i < size; ++i) + writeline(out, i, args...); + return out; +} + +} // namespace internal + +namespace gnuplot +{ + +/// Return the formatted string for a plot title. +inline auto titlestr(std::string word) -> std::string +{ + return word == "columnheader" ? word : "'" + word + "'"; +} + +/// Return the formatted string for a `option` with a leading space (e.g., "enhanced ") +/// Note that if option is empty, then an empty string is returned. +inline auto optionStr(std::string option) -> std::string +{ + return option.size() ? (option + " ") : ""; +} + +/// Return the formatted string for a `option value` pair with a leading space (e.g., "size 400,300 ", "ls 2 ") +/// Note that if value is empty, then the option is not needed and an empty string is returned. +inline auto optionValueStr(std::string option, std::string value) -> std::string +{ + return value.size() ? (option + " " + value + " ") : ""; +} + +/// Return the formatted string for a `command value` pair (e.g. "cmd value" or "set ab de") +/// Note that if value is empty, then the command is not needed and an empty string is returned. +inline auto cmdValueStr(std::string cmd, std::string value) -> std::string +{ + return value.size() ? (cmd + " " + value + "\n") : ""; +} + +/// Return the formatted, escaped string for a `command value` pair (e.g. "cmd 'value'", or "set ab 'de'") +/// Note that if value is empty, then the command is not needed and an empty string is returned. +inline auto cmdValueEscapedStr(std::string cmd, std::string value) -> std::string +{ + return value.size() ? (cmd + " '" + value + "'\n") : ""; +} + +/// Return the formatted string for a size pair (x,y). +inline auto figureSizeStr(double sx, double sy) -> std::string +{ + return internal::str(sx) + "," + internal::str(sy); +} + +/// Return the formatted string for a size pair (x,y) in either as pixels or as inches (asinches == true). +inline auto canvasSizeStr(std::size_t width, std::size_t height, bool asinches) -> std::string +{ + return asinches ? (internal::str(width * POINT_TO_INCHES) + "in," + internal::str(height * POINT_TO_INCHES) + "in") : (internal::str(width) + "," + internal::str(height)); +} + +/// Return the correct gnuplot string command for given rgb color (e.g., "#FF00FF") +inline auto rgb(std::string color) -> std::string { return "rgb '" + color + "'"; } + +/// Return the correct gnuplot string command for given rgb color as hex number (e.g., 0xFF00FF) +inline auto rgb(int hexcolor) -> std::string { return "rgb " + internal::str(hexcolor); } + +/// The struct where static angle methods are defined. +struct angle +{ + /// Return the angle in degree units. + static auto deg(long val) -> std::string { return internal::str(val) + "deg"; } + + /// Return the angle in radian units. + static auto rad(double val) -> std::string { return internal::str(val); } + + /// Return the angle in radian units as a multiple of number pi. + static auto pi(double val) -> std::string { return internal::str(val) + "pi"; } +}; + +/// Auxiliary function to create a data set in an ostream object that is understood by gnuplot +template +auto writedataset(std::ostream& out, std::size_t index, const Args&... args) -> std::ostream& +{ + // Save the given vectors x and y in a new data set of the data file + out << "#==============================================================================" << std::endl; + out << "# DATASET #" << index << std::endl; + out << "#==============================================================================" << std::endl; + // Write the vector arguments to the ostream object + out << std::setprecision(15); + internal::write(out, args...); + // Ensure two blank lines are added here so that gnuplot understands a new data set has been added + out << "\n\n"; + return out; +} + +/// Auxiliary function to write palette data for a selected palette to start of plot script +inline auto palettecmd(std::ostream& out, std::string palette) -> std::ostream& +{ + out << "#==============================================================================" << std::endl; + out << "# GNUPLOT-palette (" << palette << ")" << std::endl; + out << "#------------------------------------------------------------------------------" << std::endl; + out << "# see more at https://github.com/Gnuplotting/gnuplot-palettes" << std::endl; + out << "#==============================================================================" << std::endl; + out << palettes.at(palette) << std::endl; + return out; +} + +/// Auxiliary function to unset palette in plot script +inline auto unsetpalettecmd(std::ostream& out) -> std::ostream& +{ + out << "do for [i=1:20] { unset style line i }" << std::endl; + return out; +} + +/// Auxiliary function to write terminal commands for showing a plot from a script file +inline auto showterminalcmd(std::ostream& out, std::string size, std::string font, std::string title) -> std::ostream& +{ + out << "#==============================================================================" << std::endl; + out << "# TERMINAL" << std::endl; + out << "#==============================================================================" << std::endl; + // We set a terminal here to make sure we can also set a size. This is necessary, because the + // canvas size can ONLY be set using "set terminal size W, H". + // See: http://www.bersch.net/gnuplot-doc/canvas-size.html#set-term-size + // The GNUTERM variable contains the default terminal, which we're using for the show command. + // See: http://www.bersch.net/gnuplot-doc/unset.html + out << "set termoption enhanced" << std::endl; + if (font.size()) out << "set termoption " << font << std::endl; + out << "set terminal GNUTERM size " << size << (!title.empty() ? " title '" + title + "' " : "") << std::endl; + out << "set encoding utf8" << std::endl; + return out; +} + +/// Auxiliary function to write terminal commands for saving a plot from a script file +inline auto saveterminalcmd(std::ostream& out, std::string extension, std::string size, std::string font) -> std::ostream& +{ + out << "#==============================================================================" << std::endl; + out << "# TERMINAL" << std::endl; + out << "#==============================================================================" << std::endl; + out << "set terminal " << extension << " size " << size << " enhanced rounded " << font << std::endl; + out << "set encoding utf8" << std::endl; + return out; +} + +/// Auxiliary function to set the output command to make GNUplot output plots to a file +inline auto outputcmd(std::ostream& out, std::string filename) -> std::ostream& +{ + out << "#==============================================================================" << std::endl; + out << "# OUTPUT" << std::endl; + out << "#==============================================================================" << std::endl; + out << "set output '" << filename << "'" << std::endl; + out << "set encoding utf8" << std::endl; + return out; +} + +/// Auxiliary function to write multiplot commands to a script file +inline auto multiplotcmd(std::ostream& out, std::size_t rows, std::size_t columns, std::string title) -> std::ostream& +{ + out << "#==============================================================================" << std::endl; + out << "# MULTIPLOT" << std::endl; + out << "#==============================================================================" << std::endl; + out << "set multiplot"; + if (rows != 0 || columns != 0) + { + out << " layout " << rows << "," << columns; + } + out << " " + << "rowsfirst"; + out << " " + << "downwards"; +// out << " margins 0.1,0.1,0.1,0.1"; + if (!title.empty()) + { + out << " title '" << title << "'"; + } + out << std::endl; + return out; +} + +/// Auxiliary function to run gnuplot to show or save a script file +// persistent == true: for show commands. show the file using GNUplot until the window is closed +// persistent == false: for save commands. close gnuplot immediately +inline auto runscript(std::string scriptfilename, bool persistent) -> bool +{ + std::string command = persistent ? "gnuplot -persistent " : "gnuplot "; + command += "\"" + scriptfilename + "\""; + return std::system(command.c_str()) == 0; +} + +/// Auxiliary function to escape a output path so it can be used for GNUplot. +/// Removes every character from invalidchars from the path. +inline auto cleanpath(std::string path) -> std::string +{ + const std::string invalidchars = ":*?!\"<>|"; + std::string result = path; + result.erase(std::remove_if(result.begin(), result.end(), [&invalidchars](char c) + { return (std::find(invalidchars.cbegin(), invalidchars.cend(), c) != invalidchars.cend()); }), + result.end()); + return result; +} + +} // namespace gnuplot + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/Vec.hpp b/src/cpp/3rdparty/sciplot/Vec.hpp new file mode 100755 index 000000000..105a3f867 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/Vec.hpp @@ -0,0 +1,64 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include +#include +#include +#include + +namespace sciplot { + +/// A convenient type alias for std::valarray +using Vec = std::valarray; + +/// A convenient type alias for std::vector +using Strings = std::vector; + +/// Return an array with uniform increments from a given initial value to a final one +template +auto linspace(T0 x0, T1 x1, std::size_t numintervals) -> std::valarray +{ + std::valarray result(numintervals + 1); + for(std::size_t i = 0; i <= numintervals; ++i) + result[i] = x0 + i * (x1 - x0) / static_cast(numintervals); + return result; +} + +/// Return an array with unit increment from a given initial value to a final one +template +auto range(int x0, int x1) -> Vec +{ + const auto incr = (x1 > x0) ? +1 : -1; + std::valarray result(x1 - x0 + 1); + for(std::size_t i = 0; i < result.size(); ++i) + result[i] = x0 + i * incr; + return result; +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/sciplot.hpp b/src/cpp/3rdparty/sciplot/sciplot.hpp new file mode 100755 index 000000000..767e882a3 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/sciplot.hpp @@ -0,0 +1,49 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2022 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// We check if windows.h. is already included, as this might break compilation. See: https://sciplot.github.io/known_issues/ +#ifdef _WINDOWS_ +#ifdef _MSC_VER +#pragma message(__FILE__ "(): warning: You might run into compiler errors if windows.h is included before sciplot.hpp! See: https://sciplot.github.io/known_issues/") +#else +#warning You might run into compiler errors if windows.h is included before sciplot.hpp! See: https://sciplot.github.io/known_issues/ +#endif // _MSC_VER +#endif // _WINDOWS_ + +// sciplot includes +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/src/cpp/3rdparty/sciplot/specs/AxisLabelSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/AxisLabelSpecs.hpp new file mode 100755 index 000000000..24cdf2984 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/AxisLabelSpecs.hpp @@ -0,0 +1,110 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot { + +/// The specifications for an axis label (e.g., xlabel, ylabel, etc.) +class AxisLabelSpecs : public TextSpecsOf +{ + public: + /// Construct a default AxisLabelSpecs instance. + AxisLabelSpecs(std::string axis); + + /// Set the text of the axis label. + auto text(std::string text) -> AxisLabelSpecs&; + + /// Specify that the axis label should be rotated by a given angle in degrees. + auto rotateBy(int degrees) -> AxisLabelSpecs&; + + /// Specify that the axis label should be rotated to be in parallel to the corresponding axis (for 3D plots). + auto rotateAxisParallel() -> AxisLabelSpecs&; + + /// Specify that the axis label should not be rotated. + auto rotateNone() -> AxisLabelSpecs&; + + /// Convert this AxisLabelSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The name of the axis (e.g., `"x"`, `"y"`, `"z"`) + std::string m_axis; + + /// The axis label text (e.g., "Distance (km)") + std::string m_text; + + /// The rotation command to rotate the label around. + std::string m_rotate; +}; + +inline AxisLabelSpecs::AxisLabelSpecs(std::string axis) +: m_axis(axis) +{ +} + +inline auto AxisLabelSpecs::text(std::string text) -> AxisLabelSpecs& +{ + m_text = "'" + text + "'"; + return *this; +} + +inline auto AxisLabelSpecs::rotateBy(int degrees) -> AxisLabelSpecs& +{ + m_rotate = "rotate by " + std::to_string(degrees); + return *this; +} + +inline auto AxisLabelSpecs::rotateAxisParallel() -> AxisLabelSpecs& +{ + m_rotate = "rotate parallel"; + return *this; +} + +inline auto AxisLabelSpecs::rotateNone() -> AxisLabelSpecs& +{ + m_rotate = "norotate"; + return *this; +} + +inline auto AxisLabelSpecs::repr() const -> std::string +{ + if(m_text.empty() && m_rotate.empty()) + return ""; + + std::stringstream ss; + ss << "set " + m_axis + "label "; + ss << m_text << " "; + ss << TextSpecsOf::repr() + " "; + ss << gnuplot::optionStr(m_rotate); + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/BorderSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/BorderSpecs.hpp new file mode 100755 index 000000000..ae0b6e1fb --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/BorderSpecs.hpp @@ -0,0 +1,246 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include +#include +#include +#include +#include + +// sciplot includes + +namespace sciplot { + +/// The class used to specify options for plot border. +class BorderSpecs : public LineSpecsOf, public DepthSpecsOf +{ + public: + /// Construct a default border instance. + BorderSpecs(); + + /// Remove all border edges from a 2d or 3d plot. + auto clear() -> BorderSpecs&; + + /// Set all border edges to inactive. Methods none and clear have identical effect. + auto none() -> BorderSpecs&; + + /// Activate the bottom border edge on the xy plane for a 2d plot. + auto bottom() -> BorderSpecs&; + + /// Activate the left border edge on the xy plane for a 2d plot. + auto left() -> BorderSpecs&; + + /// Activate the top border edge on the xy plane for a 2d plot. + auto top() -> BorderSpecs&; + + /// Activate the right border edge on the xy plane for a 2d plot. + auto right() -> BorderSpecs&; + + /// Activate the border edge on the bottom xy plane going from the left corner to front corner in a 3d perspective. + auto bottomLeftFront() -> BorderSpecs&; + + /// Activate the border edge on the bottom xy plane going from the left corder to back corner in a 3d perspective. + auto bottomLeftBack() -> BorderSpecs&; + + /// Activate the border edge on the bottom xy plane going from the right corner to front corner in a 3d perspective. + auto bottomRightFront() -> BorderSpecs&; + + /// Activate the border edge on the bottom xy plane going from the right corder to back corner in a 3d perspective. + auto bottomRightBack() -> BorderSpecs&; + + /// Activate the left vertical border edge in a 3d perspective. + auto leftVertical() -> BorderSpecs&; + + /// Activate the back vertical border edge in a 3d perspective. + auto backVertical() -> BorderSpecs&; + + /// Activate the right vertical border edge in a 3d perspective. + auto rightVertical() -> BorderSpecs&; + + /// Activate the front vertical border edge in a 3d perspective. + auto frontVertical() -> BorderSpecs&; + + /// Activate the border edge on the top xy plane going from the left corner to back corner in a 3d perspective. + auto topLeftBack() -> BorderSpecs&; + + /// Activate the border edge on the top xy plane going from the right corder to back corner in a 3d perspective. + auto topRightBack() -> BorderSpecs&; + + /// Activate the border edge on the top xy plane going from the left corner to front corner in a 3d perspective. + auto topLeftFront() -> BorderSpecs&; + + /// Activate the border edge on the top xy plane going from the right corder to front corner in a 3d perspective. + auto topRightFront() -> BorderSpecs&; + + /// Set the border for polar plot. + auto polar() -> BorderSpecs&; + + /// Convert this BorderSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The bits encoding the active and inactive borders. + std::bitset<13> m_encoding; + + /// The placement depth of the borders. + std::string m_depth; +}; + +inline BorderSpecs::BorderSpecs() +{ + left(); + bottom(); + lineType(internal::DEFAULT_BORDER_LINETYPE); + lineWidth(internal::DEFAULT_BORDER_LINEWIDTH); + lineColor(internal::DEFAULT_BORDER_LINECOLOR); + front(); +} + +inline auto BorderSpecs::clear() -> BorderSpecs& +{ + m_encoding.reset(); + return *this; +} + +inline auto BorderSpecs::none() -> BorderSpecs& +{ + return clear(); +} + +inline auto BorderSpecs::bottom() -> BorderSpecs& +{ + m_encoding.set(0); + return *this; +} + +inline auto BorderSpecs::left() -> BorderSpecs& +{ + m_encoding.set(1); + return *this; +} + +inline auto BorderSpecs::top() -> BorderSpecs& +{ + m_encoding.set(2); + return *this; +} + +inline auto BorderSpecs::right() -> BorderSpecs& +{ + m_encoding.set(3); + return *this; +} + +inline auto BorderSpecs::bottomLeftFront() -> BorderSpecs& +{ + m_encoding.set(0); + return *this; +} + +inline auto BorderSpecs::bottomLeftBack() -> BorderSpecs& +{ + m_encoding.set(1); + return *this; +} + +inline auto BorderSpecs::bottomRightFront() -> BorderSpecs& +{ + m_encoding.set(2); + return *this; +} + +inline auto BorderSpecs::bottomRightBack() -> BorderSpecs& +{ + m_encoding.set(3); + return *this; +} + +inline auto BorderSpecs::leftVertical() -> BorderSpecs& +{ + m_encoding.set(4); + return *this; +} + +inline auto BorderSpecs::backVertical() -> BorderSpecs& +{ + m_encoding.set(5); + return *this; +} + +inline auto BorderSpecs::rightVertical() -> BorderSpecs& +{ + m_encoding.set(6); + return *this; +} + +inline auto BorderSpecs::frontVertical() -> BorderSpecs& +{ + m_encoding.set(7); + return *this; +} + +inline auto BorderSpecs::topLeftBack() -> BorderSpecs& +{ + m_encoding.set(8); + return *this; +} + +inline auto BorderSpecs::topRightBack() -> BorderSpecs& +{ + m_encoding.set(9); + return *this; +} + +inline auto BorderSpecs::topLeftFront() -> BorderSpecs& +{ + m_encoding.set(10); + return *this; +} + +inline auto BorderSpecs::topRightFront() -> BorderSpecs& +{ + m_encoding.set(11); + return *this; +} + +inline auto BorderSpecs::polar() -> BorderSpecs& +{ + m_encoding.set(2); + return *this; +} + +inline auto BorderSpecs::repr() const -> std::string +{ + std::stringstream ss; + ss << "set border " << m_encoding.to_ulong() << " "; + ss << DepthSpecsOf::repr() << " "; + ss << LineSpecsOf::repr(); + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/DepthSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/DepthSpecsOf.hpp new file mode 100755 index 000000000..d147a61eb --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/DepthSpecsOf.hpp @@ -0,0 +1,96 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include + +namespace sciplot { + +/// The class used to attach depth options to a type. +template +class DepthSpecsOf : virtual public Specs +{ + public: + /// Construct a default DepthSpecsOf instance. + DepthSpecsOf(); + + /// Set the underlying plot element to be displayed on the front of all plot elements. + auto front() -> DerivedSpecs&; + + /// Set the underlying plot element to be displayed on the back of all plot elements. + auto back() -> DerivedSpecs&; + + /// Set the underlying plot element to be displayed behind of all plot elements. + /// In 2D plots, this method is identical to @ref front. + /// In 3D plots, this method is applicable when in hidden mode. + auto behind() -> DerivedSpecs&; + + /// Convert this DepthSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The depth of the underlying plot element (front or back) if applicable. + std::string m_depth; +}; + +/// The class used to specify depth options. +class DepthSpecs : public DepthSpecsOf {}; + +template +DepthSpecsOf::DepthSpecsOf() +{ + back(); +} + +template +auto DepthSpecsOf::front() -> DerivedSpecs& +{ + m_depth = "front"; + return static_cast(*this); +} + +template +auto DepthSpecsOf::back() -> DerivedSpecs& +{ + m_depth = "back"; + return static_cast(*this); +} + +template +auto DepthSpecsOf::behind() -> DerivedSpecs& +{ + m_depth = "behind"; + return static_cast(*this); +} + +template +auto DepthSpecsOf::repr() const -> std::string +{ + return m_depth; +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/DrawSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/DrawSpecs.hpp new file mode 100755 index 000000000..ba6b6437e --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/DrawSpecs.hpp @@ -0,0 +1,159 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include +#include +#include +#include + +namespace sciplot +{ + +/// The class where options for the plotted element can be specified. +class DrawSpecs : public LineSpecsOf, public PointSpecsOf, public FillSpecsOf, public FilledCurvesSpecsOf +{ + public: + /// Construct a DrawSpecs instance. + /// @param what The string representing `what` to be plot (e.g., "'filename'", "sin(x)") + /// @param use The string representing the `using` expression (e.g., "using 1:2", "using 4:6:8:9") + /// @param with The string representing the `with plotstyle` expression (e.g., "lines", "linespoints", "dots") + DrawSpecs(std::string what, std::string use, std::string with); + + /// Set the legend label of the plotted element. + auto label(std::string text) -> DrawSpecs&; + + /// Set the legend label of the plotted element to be retrieved from the header of column. + auto labelFromColumnHeader() -> DrawSpecs&; + + /// Set the legend label of the plotted element to be retrieved from the header of a column with given index. + auto labelFromColumnHeader(int icolumn) -> DrawSpecs&; + + /// Set the legend label of the plotted element to be ignored. + auto labelNone() -> DrawSpecs&; + + /// Set the legend label to be determined automatically from the plot expression. + auto labelDefault() -> DrawSpecs&; + + /// Set the column in the data file containing the tic labels for *x* axis. + auto xtics(ColumnIndex icol) -> DrawSpecs&; + + /// Set the column in the data file containing the tic labels for *y* axis. + auto ytics(ColumnIndex icol) -> DrawSpecs&; + + /// Convert this DrawSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The string representing `what` to be plot (e.g., "'filename'", "sin(x)"). + std::string m_what; + + /// The string representing the `using` expression (e.g., "using 1:2", "using 4:6:8:9"). + std::string m_using; + + /// The string representing the `with plotstyle` expression (e.g., "lines", "linespoints", "dots"). + std::string m_with; + + /// The title of the plot as a gnuplot formatted string (e.g., "title 'sin(x)'"). + std::string m_title; + + /// The column in the data file containing the x tic labels. + std::string m_xtic; + + /// The column in the data file containing the y tic labels. + std::string m_ytic; +}; + +inline DrawSpecs::DrawSpecs(std::string what, std::string use, std::string with) + : m_what(what), m_using(use), m_with(with) +{ + lineWidth(internal::DEFAULT_LINEWIDTH); +} + +inline auto DrawSpecs::label(std::string text) -> DrawSpecs& +{ + m_title = "title '" + text + "'"; + return *this; +} + +inline auto DrawSpecs::labelFromColumnHeader() -> DrawSpecs& +{ + m_title = "title columnheader"; + return *this; +} + +inline auto DrawSpecs::labelFromColumnHeader(int icolumn) -> DrawSpecs& +{ + m_title = "title columnheader(" + std::to_string(icolumn) + ")"; + return *this; +} + +inline auto DrawSpecs::labelNone() -> DrawSpecs& +{ + m_title = "notitle"; + return *this; +} + +inline auto DrawSpecs::labelDefault() -> DrawSpecs& +{ + m_title = ""; + return *this; +} + +inline auto DrawSpecs::xtics(ColumnIndex icol) -> DrawSpecs& +{ + m_xtic = "xtic(stringcolumn(" + icol.value + "))"; // xtic(stringcolumn(1)) or xtic(stringcolumn('Name')) + return *this; +} + +inline auto DrawSpecs::ytics(ColumnIndex icol) -> DrawSpecs& +{ + m_ytic = "ytic(stringcolumn(" + icol.value + "))"; // ytic(stringcolumn(1)) or ytic(stringcolumn('Name')) + return *this; +} + +inline auto DrawSpecs::repr() const -> std::string +{ + std::string use = m_using; + if (m_xtic.size()) use += ":" + m_xtic; + if (m_ytic.size()) use += ":" + m_ytic; + + std::stringstream ss; + ss << m_what << " "; + ss << gnuplot::optionValueStr("using", use); + ss << m_title << " "; + ss << gnuplot::optionValueStr("with", m_with); + ss << FilledCurvesSpecsOf::repr() << " "; + ss << LineSpecsOf::repr() << " "; + ss << PointSpecsOf::repr() << " "; + ss << FillSpecsOf::repr() << " "; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/FillSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/FillSpecsOf.hpp new file mode 100755 index 000000000..e04ff0014 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/FillSpecsOf.hpp @@ -0,0 +1,217 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot +{ + +/// The class used to attach color or pattern fill options to a type. +template +class FillSpecsOf : virtual public Specs +{ + public: + /// Construct a default FillSpecsOf instance. + FillSpecsOf(); + + /// Set an empty fill style for the underlying object. + auto fillEmpty() -> DerivedSpecs&; + + /// Set a solid fill style for the underlying object. + auto fillSolid() -> DerivedSpecs&; + + /// Set a pattern fill style for the underlying object. + auto fillPattern(int number) -> DerivedSpecs&; + + /// Set the color for the solid or pattern fill of the underlying object. + auto fillColor(std::string value) -> DerivedSpecs&; + + /// Set the fill color intensity of the underlying object with respect to its border color (a value between 0.0 and 1.0). + auto fillIntensity(double value) -> DerivedSpecs&; + + /// Set the fill of the underlying object to be transparent or not. + auto fillTransparent(bool active = true) -> DerivedSpecs&; + + /// Set the border line color of the underlying object. + auto borderLineColor(std::string color) -> DerivedSpecs&; + + /// Set the border line width of the underlying object. + auto borderLineWidth(int value) -> DerivedSpecs&; + + /// Set the border of the underlying object to be shown or not. + auto borderShow(bool value = true) -> DerivedSpecs&; + + /// Set the border of the underlying object to be hidden. + auto borderHide() -> DerivedSpecs&; + + /// Convert this FillSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The fill mode for the underlying object (e.g, "empty", "solid", "pattern"). + std::string m_fillmode; + + /// The fill color of the underlying object. + std::string m_fillcolor; + + /// The fill transparency of the underlying object (active or not). + std::string m_transparent; + + /// The fill intensity of the underlying object with respect to its border color. + std::string m_density; + + /// The fill pattern number of the underlying object. + std::string m_pattern_number; + + /// The border color of the underlying object. + std::string m_bordercolor; + + /// The border line width of the underlying object. + std::string m_borderlinewidth; + + /// The border show status of the underlying object. + std::string m_bordershow; +}; + +/// The class used to specify color or pattern fill options. +class FillSpecs : public FillSpecsOf +{ +}; + +template +FillSpecsOf::FillSpecsOf() +{ +} + +template +auto FillSpecsOf::fillEmpty() -> DerivedSpecs& +{ + m_fillmode = "empty"; + return static_cast(*this); +} + +template +auto FillSpecsOf::fillSolid() -> DerivedSpecs& +{ + m_fillmode = "solid"; + return static_cast(*this); +} + +template +auto FillSpecsOf::fillPattern(int number) -> DerivedSpecs& +{ + m_fillmode = "pattern"; + m_pattern_number = internal::str(number); + return static_cast(*this); +} + +template +auto FillSpecsOf::fillColor(std::string color) -> DerivedSpecs& +{ + m_fillcolor = "fillcolor '" + color + "'"; + return static_cast(*this); +} + +template +auto FillSpecsOf::fillIntensity(double value) -> DerivedSpecs& +{ + value = std::min(std::max(0.0, value), 1.0); // value in [0, 1] + m_density = internal::str(value); + m_fillmode = "solid"; + return static_cast(*this); +} + +template +auto FillSpecsOf::fillTransparent(bool active) -> DerivedSpecs& +{ + m_transparent = active ? "transparent" : ""; + if (m_fillmode.empty()) + m_fillmode = "solid"; + return static_cast(*this); +} + +template +auto FillSpecsOf::borderLineColor(std::string color) -> DerivedSpecs& +{ + m_bordercolor = "'" + color + "'"; + return static_cast(*this); +} + +template +auto FillSpecsOf::borderLineWidth(int value) -> DerivedSpecs& +{ + m_borderlinewidth = internal::str(value); + return static_cast(*this); +} + +template +auto FillSpecsOf::borderShow(bool show) -> DerivedSpecs& +{ + m_bordershow = show ? "yes" : "no"; + return static_cast(*this); +} + +template +auto FillSpecsOf::borderHide() -> DerivedSpecs& +{ + return borderShow(false); +} + +template +auto FillSpecsOf::repr() const -> std::string +{ + std::string fillstyle; // ensure it remains empty if no fill style option has been given! + if (m_fillmode == "solid") + fillstyle = "fillstyle " + m_transparent + " solid " + m_density; + else if (m_fillmode == "pattern") + fillstyle = "fillstyle " + m_transparent + " pattern " + m_pattern_number; + else if (m_fillmode == "empty") + fillstyle = "fillstyle empty"; + + std::string borderstyle; // ensure it remains empty if no border option has been given! + if (m_bordershow != "") + { + if (m_bordershow == "yes") + { + borderstyle = "border "; + borderstyle += gnuplot::optionValueStr("linecolor", m_bordercolor); + borderstyle += gnuplot::optionValueStr("linewidth", m_borderlinewidth); + } + else + borderstyle = "noborder"; + } + + std::stringstream ss; + ss << m_fillcolor << " " << fillstyle << " " << borderstyle; + + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/FillStyleSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/FillStyleSpecs.hpp new file mode 100755 index 000000000..7cefc78c7 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/FillStyleSpecs.hpp @@ -0,0 +1,189 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot +{ + +/// The class used to attach color or pattern fill options to a type. +class FillStyleSpecs : virtual public Specs +{ + public: + /// Construct a default FillStyleSpecs instance. + FillStyleSpecs(); + + /// Set an empty fill style for the underlying object. + auto empty() -> FillStyleSpecs&; + + /// Set a solid fill style for the underlying object. + auto solid() -> FillStyleSpecs&; + + /// Set a pattern fill style for the underlying object. + auto pattern(int number) -> FillStyleSpecs&; + + /// Set the fill color intensity of the underlying object with respect to its border color (a value between 0.0 and 1.0). + auto intensity(double value) -> FillStyleSpecs&; + + /// Set the fill of the underlying object to be transparent or not. + auto transparent(bool active = true) -> FillStyleSpecs&; + + /// Set the border line color of the underlying object. + auto borderLineColor(std::string color) -> FillStyleSpecs&; + + /// Set the border line width of the underlying object. + auto borderLineWidth(int value) -> FillStyleSpecs&; + + /// Set the border of the underlying object to be shown or not. + auto borderShow(bool value = true) -> FillStyleSpecs&; + + /// Set the border of the underlying object to be hidden. + auto borderHide() -> FillStyleSpecs&; + + /// Convert this FillStyleSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The fill mode for the underlying object (e.g, "empty", "solid", "pattern"). + std::string m_fillmode; + + /// The fill transparency of the underlying object (active or not). + std::string m_transparent; + + /// The fill intensity of the underlying object with respect to its border color. + std::string m_density; + + /// The fill pattern number of the underlying object. + std::string m_pattern_number; + + /// The border color of the underlying object. + std::string m_bordercolor; + + /// The border line width of the underlying object. + std::string m_borderlinewidth; + + /// The border show status of the underlying object. + std::string m_bordershow; +}; + +inline FillStyleSpecs::FillStyleSpecs() +{ +} + +inline auto FillStyleSpecs::empty() -> FillStyleSpecs& +{ + m_fillmode = "empty"; + return *this; +} + +inline auto FillStyleSpecs::solid() -> FillStyleSpecs& +{ + m_fillmode = "solid"; + return *this; +} + +inline auto FillStyleSpecs::pattern(int number) -> FillStyleSpecs& +{ + m_fillmode = "pattern"; + m_pattern_number = internal::str(number); + return *this; +} + +inline auto FillStyleSpecs::intensity(double value) -> FillStyleSpecs& +{ + value = std::min(std::max(0.0, value), 1.0); // value in [0, 1] + m_density = internal::str(value); + m_fillmode = "solid"; + return *this; +} + +inline auto FillStyleSpecs::transparent(bool active) -> FillStyleSpecs& +{ + m_transparent = active ? "transparent" : ""; + if (m_fillmode.empty()) + m_fillmode = "solid"; + return *this; +} + +inline auto FillStyleSpecs::borderLineColor(std::string color) -> FillStyleSpecs& +{ + m_bordercolor = "'" + color + "'"; + return *this; +} + +inline auto FillStyleSpecs::borderLineWidth(int value) -> FillStyleSpecs& +{ + m_borderlinewidth = internal::str(value); + return *this; +} + +inline auto FillStyleSpecs::borderShow(bool show) -> FillStyleSpecs& +{ + m_bordershow = show ? "yes" : "no"; + return *this; +} + +inline auto FillStyleSpecs::borderHide() -> FillStyleSpecs& +{ + return borderShow(false); +} + +inline auto FillStyleSpecs::repr() const -> std::string +{ + std::string fillstyle; // ensure it remains empty if no fill style option has been given! + if (m_fillmode == "solid") + fillstyle = m_transparent + " solid " + m_density; + else if (m_fillmode == "pattern") + fillstyle = m_transparent + " pattern " + m_pattern_number; + else if (m_fillmode == "empty") + fillstyle = "empty"; + + std::string borderstyle; // ensure it remains empty if no border option has been given! + if (m_bordershow != "") + { + if (m_bordershow == "yes") + { + borderstyle = "border "; + borderstyle += gnuplot::optionValueStr("linecolor", m_bordercolor); + borderstyle += gnuplot::optionValueStr("linewidth", m_borderlinewidth); + } + else + borderstyle = "noborder"; + } + + if (fillstyle.empty() && borderstyle.empty()) + return ""; + + std::string ss = "set style fill " + fillstyle + " " + borderstyle; + + return internal::removeExtraWhitespaces(ss); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/FilledCurvesSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/FilledCurvesSpecsOf.hpp new file mode 100755 index 000000000..c3487c575 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/FilledCurvesSpecsOf.hpp @@ -0,0 +1,90 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot +{ + +/// The class used to set options for the gnuplot filledcurve functionality. +template +class FilledCurvesSpecsOf : virtual public Specs +{ + public: + /// Construct a default FilledCurveSpecs instance. + FilledCurvesSpecsOf(); + + /// Limit filled area to above curves. + auto above() -> DerivedSpecs&; + + /// Limit filled area to below curves. + auto below() -> DerivedSpecs&; + + /// Convert this FillSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// Fill mode for curve(s) + std::string m_fillMode; +}; + +/// The class used to specify color or pattern fill options. +class FilledCurvesSpecs : public FilledCurvesSpecsOf +{ +}; + +template +FilledCurvesSpecsOf::FilledCurvesSpecsOf() +{ +} + +template +auto FilledCurvesSpecsOf::above() -> DerivedSpecs& +{ + m_fillMode = "above"; + return static_cast(*this); +} + +template +auto FilledCurvesSpecsOf::below() -> DerivedSpecs& +{ + m_fillMode = "below"; + return static_cast(*this); +} + +template +auto FilledCurvesSpecsOf::repr() const -> std::string +{ + std::stringstream ss; + ss << " " << m_fillMode; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/FontSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/FontSpecsOf.hpp new file mode 100755 index 000000000..6a15140d5 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/FontSpecsOf.hpp @@ -0,0 +1,89 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include + +namespace sciplot { + +/// The class used to attach font options to a type. +template +class FontSpecsOf : virtual public Specs +{ + public: + /// Construct a default FontSpecsOf instance. + FontSpecsOf(); + + /// Set the name of the font (e.g., Helvetica, Georgia, Times). + auto fontName(std::string name) -> DerivedSpecs&; + + /// Set the point size of the font (e.g., 10, 12, 16). + auto fontSize(std::size_t size) -> DerivedSpecs&; + + /// Convert this FontSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The name of the font. + std::string m_fontname; + + /// The point size of the font. + std::string m_fontsize; +}; + +/// The class used to specify font options. +class FontSpecs : public FontSpecsOf {}; + +template +FontSpecsOf::FontSpecsOf() +{} + +template +auto FontSpecsOf::fontName(std::string name) -> DerivedSpecs& +{ + m_fontname = name; + return static_cast(*this); +} + +template +auto FontSpecsOf::fontSize(std::size_t size) -> DerivedSpecs& +{ + m_fontsize = std::to_string(size); + return static_cast(*this); +} + +template +auto FontSpecsOf::repr() const -> std::string +{ + std::stringstream ss; + if(m_fontname.size() || m_fontsize.size()) + ss << "font '" << m_fontname << "," << m_fontsize << "'"; + return ss.str(); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/FrameSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/FrameSpecsOf.hpp new file mode 100755 index 000000000..627d1050c --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/FrameSpecsOf.hpp @@ -0,0 +1,146 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot { + +/// The class used to attach frame options to a type. +template +class FrameSpecsOf : virtual public Specs +{ + public: + /// Construct a default FrameSpecsOf instance. + FrameSpecsOf(); + + /// Set the visibility of the legend frame to a shown or hidden status. + auto frameShow(bool value=true) -> DerivedSpecs&; + + /// Set the visibility of the legend frame to a hidden status. + auto frameHide() -> DerivedSpecs&; + + /// Set the line style of the legend frame. + auto frameLineStyle(int value) -> DerivedSpecs&; + + /// Set the line type of the legend frame. + auto frameLineType(int value) -> DerivedSpecs&; + + /// Set the line width of the legend frame. + auto frameLineWidth(int value) -> DerivedSpecs&; + + /// Set the line color of the legend frame. + auto frameLineColor(std::string value) -> DerivedSpecs&; + + /// Set the dash type of the legend frame. + auto frameDashType(int value) -> DerivedSpecs&; + + /// Convert this FrameSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The visibility option for the frame. + bool m_show; + + /// The line options for the frame. + LineSpecs m_line_specs; +}; + +/// The class used to specify frame options. +class FrameSpecs : public FrameSpecsOf {}; + +template +FrameSpecsOf::FrameSpecsOf() +{ + frameShow(internal::DEFAULT_LEGEND_FRAME_SHOW); + frameLineWidth(internal::DEFAULT_LEGEND_FRAME_LINEWIDTH); + frameLineColor(internal::DEFAULT_LEGEND_FRAME_LINECOLOR); + frameLineType(internal::DEFAULT_LEGEND_FRAME_LINETYPE); +} + +template +auto FrameSpecsOf::frameShow(bool value) -> DerivedSpecs& +{ + m_show = value; + return static_cast(*this); +} + +template +auto FrameSpecsOf::frameHide() -> DerivedSpecs& +{ + return frameShow(false); +} + +template +auto FrameSpecsOf::frameLineStyle(int value) -> DerivedSpecs& +{ + m_line_specs.lineStyle(value); + return static_cast(*this); +} + +template +auto FrameSpecsOf::frameLineType(int value) -> DerivedSpecs& +{ + m_line_specs.lineType(value); + return static_cast(*this); +} + +template +auto FrameSpecsOf::frameLineWidth(int value) -> DerivedSpecs& +{ + m_line_specs.lineWidth(value); + return static_cast(*this); +} + +template +auto FrameSpecsOf::frameLineColor(std::string value) -> DerivedSpecs& +{ + m_line_specs.lineColor(value); + return static_cast(*this); +} + +template +auto FrameSpecsOf::frameDashType(int value) -> DerivedSpecs& +{ + m_line_specs.dashType(value); + return static_cast(*this); +} + +template +auto FrameSpecsOf::repr() const -> std::string +{ + if(m_show == false) + return "nobox"; + + std::stringstream ss; + ss << "box " << m_line_specs.repr(); + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/GridSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/GridSpecs.hpp new file mode 100755 index 000000000..12b05c64f --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/GridSpecs.hpp @@ -0,0 +1,130 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot { + +/// The class used to specify options for grid. +class GridSpecs : public GridSpecsBase +{ + public: + /// Construct a default GridSpecs instance. + GridSpecs(); + + /// Return the specifications of the grid lines along major xtics on the bottom axis. + auto xtics() -> GridSpecsBase& { return xticsMajorBottom(); } + + /// Return the specifications of the grid lines along major ytics on the left axis. + auto ytics() -> GridSpecsBase& { return yticsMajorLeft(); } + + /// Return the specifications of the grid lines along major ztics. + auto ztics() -> GridSpecsBase& { return zticsMajor(); } + + /// Return the specifications of the grid lines along major rtics. + auto rtics() -> GridSpecsBase& { return rticsMajor(); } + + /// Return the specifications of the grid lines along major xtics on the bottom axis. + auto xticsMajorBottom() -> GridSpecsBase& { return _gridmajor("xtics"); } + + /// Return the specifications of the grid lines along major xtics on the top axis. + auto xticsMajorTop() -> GridSpecsBase& { return _gridmajor("x2tics"); } + + /// Return the specifications of the grid lines along minor xtics on the bottom axis. + auto xticsMinorBottom() -> GridSpecsBase& { return _gridminor("mxtics"); } + + /// Return the specifications of the grid lines along minor xtics on the top axis. + auto xticsMinorTop() -> GridSpecsBase& { return _gridminor("mx2tics"); } + + /// Return the specifications of the grid lines along major ytics on the left axis. + auto yticsMajorLeft() -> GridSpecsBase& { return _gridmajor("ytics"); } + + /// Return the specifications of the grid lines along major ytics on the right axis. + auto yticsMajorRight() -> GridSpecsBase& { return _gridmajor("y2tics"); } + + /// Return the specifications of the grid lines along minor ytics on the left axis. + auto yticsMinorLeft() -> GridSpecsBase& { return _gridminor("mytics"); } + + /// Return the specifications of the grid lines along minor ytics on the right axis. + auto yticsMinorRight() -> GridSpecsBase& { return _gridminor("my2tics"); } + + /// Return the specifications of the grid lines along major ztics. + auto zticsMajor() -> GridSpecsBase& { return _gridmajor("ztics"); } + + /// Return the specifications of the grid lines along minor ztics. + auto zticsMinor() -> GridSpecsBase& { return _gridminor("mztics"); } + + /// Return the specifications of the grid lines along minor rtics. + auto rticsMajor() -> GridSpecsBase& { return _gridmajor("rtics"); } + + /// Return the specifications of the grid lines along minor rtics. + auto rticsMinor() -> GridSpecsBase& { return _gridminor("mrtics"); } + + /// Convert this GridSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// Auxiliary private method that adds a new specs object for grid lines along a major tics. + auto _gridmajor(std::string tics) -> GridSpecsBase& + { + m_gridticsspecs.emplace_back(tics, true); + return m_gridticsspecs.back(); + } + + /// Auxiliary private method that adds a new specs object for grid lines along a minor tics. + auto _gridminor(std::string tics) -> GridSpecsBase& + { + m_gridticsspecs.emplace_back(tics, false); + return m_gridticsspecs.back(); + } + + private: + /// The vector of grid specs for the major and minor grid lines in the plot (for xtics, ytics, mxtics, etc.). + std::vector m_gridticsspecs; +}; + +inline GridSpecs::GridSpecs() +: GridSpecsBase("", true) +{ + show(false); + back(); +} + +inline auto GridSpecs::repr() const -> std::string +{ + std::stringstream ss; + ss << GridSpecsBase::repr(); + for (auto specs : m_gridticsspecs) + ss << '\n' + << specs.repr(); + return ss.str(); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/GridSpecsBase.hpp b/src/cpp/3rdparty/sciplot/specs/GridSpecsBase.hpp new file mode 100755 index 000000000..923e75871 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/GridSpecsBase.hpp @@ -0,0 +1,87 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include +#include +#include + +namespace sciplot { + +/// The class used to specify options for grid lines along axis tics (major or minor). +class GridSpecsBase : public LineSpecsOf, public DepthSpecsOf, public ShowSpecsOf +{ + public: + /// Construct a default GridSpecsBase instance. + GridSpecsBase(std::string tics = "", bool majortics = true); + + /// Convert this GridSpecsBase object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The names of the tics for which the grid is affected. + std::string m_tics; + + /// The boolean flag that indicates if the grid lines are along major tics, if true, or minor tics otherwise. + bool m_majortics; +}; + +inline GridSpecsBase::GridSpecsBase(std::string tics, bool majortics) +: m_tics(tics), m_majortics(majortics) +{ + show(true); + back(); + lineColor(internal::DEFAULT_GRID_LINECOLOR); + lineWidth(internal::DEFAULT_GRID_LINEWIDTH); + lineType(internal::DEFAULT_GRID_LINETYPE); + dashType(internal::DEFAULT_GRID_DASHTYPE); +} + +inline auto GridSpecsBase::repr() const -> std::string +{ + const auto show = ShowSpecsOf::repr(); + const auto visible = show != "no"; + + if(m_tics.empty() && !visible) + return "unset grid"; + + if(m_tics.size() && !visible) + return "set grid no" + m_tics; + + std::stringstream ss; + ss << "set grid " << m_tics << " "; + ss << DepthSpecsOf::repr() << " "; + if(m_majortics) + ss << LineSpecsOf::repr(); + else + ss << ", " + LineSpecsOf::repr(); // For minor tics, the preceding comma is needed + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/HistogramStyleSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/HistogramStyleSpecs.hpp new file mode 100755 index 000000000..0b5df25cf --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/HistogramStyleSpecs.hpp @@ -0,0 +1,142 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include + +namespace sciplot { + +/// The class used to specify histogram style options. +class HistogramStyleSpecs : virtual public Specs +{ + public: + /// Construct a default HistogramStyleSpecs instance. + HistogramStyleSpecs(); + + /// Set the histogram style to be clustered. + auto clustered() -> HistogramStyleSpecs&; + + /// Set the histogram style to be clustered with a given gap size. + auto clusteredWithGap(double value) -> HistogramStyleSpecs&; + + /// Set the histogram style to be stacked with groups formed using data along rows. + auto rowStacked() -> HistogramStyleSpecs&; + + /// Set the histogram style to be stacked with groups formed using data along columns. + auto columnStacked() -> HistogramStyleSpecs&; + + /// Set the histogram style to be with error bars. + auto errorBars() -> HistogramStyleSpecs&; + + /// Set the histogram style to be with error bars and also set its gap size. + auto errorBarsWithGap(double value) -> HistogramStyleSpecs&; + + /// Set the histogram style to be with error bars and also set its line width. + auto errorBarsWithLineWidth(double value) -> HistogramStyleSpecs&; + + /// Convert this HistogramStyleSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The type of the histogram (clustered, errorbars, rowstacked, columnstacked). + std::string m_type; + + /// The gap size (for clustered). + std::string m_gap_clustered; + + /// The gap size (for errorbars). + std::string m_gap_errorbars; + + /// The line width (applicable only to errorbars). + std::string m_linewidth; +}; + +inline HistogramStyleSpecs::HistogramStyleSpecs() +{ +} + +inline auto HistogramStyleSpecs::clustered() -> HistogramStyleSpecs& +{ + m_type = "clustered"; + return *this; +} + +inline auto HistogramStyleSpecs::clusteredWithGap(double value) -> HistogramStyleSpecs& +{ + m_type = "clustered"; + m_gap_clustered = "gap " + internal::str(value); + return *this; +} + +inline auto HistogramStyleSpecs::rowStacked() -> HistogramStyleSpecs& +{ + m_type = "rowstacked"; + return *this; +} + +inline auto HistogramStyleSpecs::columnStacked() -> HistogramStyleSpecs& +{ + m_type = "columnstacked"; + return *this; +} + +inline auto HistogramStyleSpecs::errorBars() -> HistogramStyleSpecs& +{ + m_type = "errorbars"; + return *this; +} + +inline auto HistogramStyleSpecs::errorBarsWithGap(double value) -> HistogramStyleSpecs& +{ + m_type = "errorbars"; + m_gap_errorbars = "gap " + internal::str(value); + return *this; +} + +inline auto HistogramStyleSpecs::errorBarsWithLineWidth(double value) -> HistogramStyleSpecs& +{ + m_type = "errorbars"; + m_linewidth = "linewidth " + internal::str(value); + return *this; +} + +inline auto HistogramStyleSpecs::repr() const -> std::string +{ + [[maybe_unused]] const auto supports_gap = (m_type == "clustered" || m_type == "errorbars"); + [[maybe_unused]] const auto supports_linewidth = (m_type == "errorbars"); + + std::stringstream ss; + ss << "set style histogram" << " "; + ss << m_type << " "; + if(m_type == "clustered") ss << m_gap_clustered << " "; + if(m_type == "errorbars") ss << m_gap_errorbars << " "; + if(m_type == "errorbars") ss << m_linewidth << " "; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/LabelSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/LabelSpecs.hpp new file mode 100755 index 000000000..bc6f18a53 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/LabelSpecs.hpp @@ -0,0 +1,36 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include + +namespace sciplot { + +// TODO: Implement LabelSpecs + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/LayoutSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/LayoutSpecs.hpp new file mode 100755 index 000000000..a7fdac213 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/LayoutSpecs.hpp @@ -0,0 +1,156 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2022 Allan Leal, Bim Overbohm +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include + +namespace sciplot +{ + +/// The class used to attach layout options to a type. +template +class LayoutSpecsOf : virtual public Specs +{ + public: + /// Set the origin of the figure relative to the canvas (0,0 is bottom left and 1,1 is top right). + auto origin(double x, double y) -> DerivedSpecs&; + + /// Set the size factor of the figure relative to the canvas (a value of 1 will fill the entire canvas, < 1 will fill only a part, > 1 will make the figure not fit the canvas). + auto size(double sx, double sy) -> DerivedSpecs&; + + /// Set the absolute margins of the figure to the canvas. A value of -1 will let gnuplot autocalculate the value. + auto marginsAbsolute(double left = -1, double right = -1, double top = -1, double bottom = -1) -> DerivedSpecs&; + + /// Set the relative margins of the figure to the canvas as a fraction of the canvas. + /// Note that size() and origin() will get ignored if you set this. + /// @note This does not seem to work for me with gnuplot 5.4 patchlevel 2 + auto marginsRelative(double left = -1, double right = -1, double top = -1, double bottom = -1) -> DerivedSpecs&; + + /// Convert this LayoutSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// Horizontal origin of figure inside canvas + double m_originX = 0.0; + /// Vertical origin of figure inside canvas + double m_originY = 0.0; + /// True if the origin has been set + bool m_originSet = false; + + /// The size of the plot in x relative to the canvas + double m_sizeX = 0; + /// The size of the plot in y relative to the canvas + double m_sizeY = 0; + /// True if the size has been set + bool m_sizeSet = false; + + /// Left margin of figure inside canvas + double m_marginsLeft = 0.0; + /// Right margin of figure inside canvas + double m_marginsRight = 0.0; + /// Top margin of figure inside canvas + double m_marginsTop = 0.0; + /// Bottom margin of figure inside canvas + double m_marginsBottom = 0.0; + /// If true margins inside canvas are absolute values, else relative + double m_marginsAbsolute = false; + /// True if the margins have been set + bool m_marginsSet = false; +}; + +/// The class used to specify layout options. +class LayoutSpecs : public LayoutSpecsOf +{ +}; + +template +auto LayoutSpecsOf::origin(double x, double y) -> DerivedSpecs& +{ + m_originX = x; + m_originY = y; + m_originSet = true; + return static_cast(*this); +} + +template +auto LayoutSpecsOf::size(double sx, double sy) -> DerivedSpecs& +{ + m_sizeX = sx; + m_sizeY = sy; + m_sizeSet = true; + return static_cast(*this); +} + +template +auto LayoutSpecsOf::marginsAbsolute(double left, double right, double top, double bottom) -> DerivedSpecs& +{ + m_marginsLeft = left; + m_marginsRight = right; + m_marginsTop = top; + m_marginsBottom = bottom; + m_marginsAbsolute = true; + m_marginsSet = true; + return static_cast(*this); +} + + +// This does not seem to work for me with gnuplot 5.4 patchlevel 2 +template +auto LayoutSpecsOf::marginsRelative(double left, double right, double top, double bottom) -> DerivedSpecs& +{ + m_marginsLeft = left; + m_marginsRight = right; + m_marginsTop = top; + m_marginsBottom = bottom; + m_marginsAbsolute = false; + m_marginsSet = true; + return static_cast(*this); +} + +template +auto LayoutSpecsOf::repr() const -> std::string +{ + std::stringstream script; + if (m_originSet) + { + script << "set origin " << m_originX << "," << m_originY << std::endl; + } + if (m_sizeSet) + { + script << "set size " << m_sizeX << "," << m_sizeY << std::endl; + } + if (m_marginsSet) + { + script << "set lmargin " << (m_marginsAbsolute ? "" : "at screen ") << m_marginsLeft << std::endl; + script << "set rmargin " << (m_marginsAbsolute ? "" : "at screen ") << m_marginsRight << std::endl; + script << "set tmargin " << (m_marginsAbsolute ? "" : "at screen ") << m_marginsTop << std::endl; + script << "set bmargin " << (m_marginsAbsolute ? "" : "at screen ") << m_marginsBottom << std::endl; + } + return script.str(); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/LegendSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/LegendSpecs.hpp new file mode 100755 index 000000000..cbfae7c20 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/LegendSpecs.hpp @@ -0,0 +1,493 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include +#include +#include +#include + +namespace sciplot { + +/// The class used to specify options for legend. +class LegendSpecs : public TextSpecsOf, public ShowSpecsOf, public TitleSpecsOf, public FrameSpecsOf +{ + public: + /// Construct a default LegendSpecs instance. + LegendSpecs(); + + /// Set the background of the legend box to be opaque. + auto opaque() -> LegendSpecs&; + + /// Set the background of the legend box to be transparent. + auto transparent() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its left side. + auto atLeft() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its right side. + auto atRight() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its center. + auto atCenter() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its top side. + auto atTop() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its top-left corner. + auto atTopLeft() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its top-right corner. + auto atTopRight() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its bottom side. + auto atBottom() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its bottom-left corner. + auto atBottomLeft() -> LegendSpecs&; + + /// Place the legend on the inside of the plot at its bottom-right corner. + auto atBottomRight() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its left side. + auto atOutsideLeft() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its left-top corner. + auto atOutsideLeftTop() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its left-bottom corner. + auto atOutsideLeftBottom() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its right side. + auto atOutsideRight() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its right-top corner. + auto atOutsideRightTop() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its right-bottom corner. + auto atOutsideRightBottom() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its bottom side. + auto atOutsideBottom() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its bottom-left corner. + auto atOutsideBottomLeft() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its bottom-right corner. + auto atOutsideBottomRight() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its top side. + auto atOutsideTop() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its top-left corner. + auto atOutsideTopLeft() -> LegendSpecs&; + + /// Place the legend on the outside of the plot at its top-right corner. + auto atOutsideTopRight() -> LegendSpecs&; + + /// Place the legend title on the left. + auto titleLeft() -> LegendSpecs&; + + /// Place the legend title on the center. + auto titleCenter() -> LegendSpecs&; + + /// Place the legend title on the right. + auto titleRight() -> LegendSpecs&; + + /// Set the legend entries to be displayed along the vertical (in columns). + auto displayVertical() -> LegendSpecs&; + + /// Set the number of rows that trigger a new column to be created in the legend (when using vertical display). + auto displayVerticalMaxRows(int value) -> LegendSpecs&; + + /// Set the legend entries to be displayed along the horizontal (in rows). + auto displayHorizontal() -> LegendSpecs&; + + /// Set the number of columns that trigger a new row to be created in the legend (when using horizontal display). + auto displayHorizontalMaxCols(int value) -> LegendSpecs&; + + /// Set the labels in the legend entries to appear before their corresponding symbols (on the left). + auto displayLabelsBeforeSymbols() -> LegendSpecs&; + + /// Set the labels in the legend entries to appear after their corresponding symbols (on the right). + auto displayLabelsAfterSymbols() -> LegendSpecs&; + + /// Set the legend labels to be left justified. + auto displayJustifyLeft() -> LegendSpecs&; + + /// Set the legend labels to be right justified. + auto displayJustifyRight() -> LegendSpecs&; + + /// Set the legend entries to be displayed in the order from first to last. + auto displayStartFromFirst() -> LegendSpecs&; + + /// Set the legend entries to be displayed in the order from last to first. + auto displayStartFromLast() -> LegendSpecs&; + + /// Set the spacing between the titles in the legend. + auto displaySpacing(int value) -> LegendSpecs&; + + /// Set the width increment/decrement of the legend frame to either enlarge or reduce its width. + auto displayExpandWidthBy(int value) -> LegendSpecs&; + + /// Set the height increment/decrement of the legend frame to either enlarge or reduce its height. + auto displayExpandHeightBy(int value) -> LegendSpecs&; + + /// Set the length of the samples used to generate the symbols in the legend entries. + auto displaySymbolLength(int value) -> LegendSpecs&; + + /// Convert this LegendSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The place at which the legend is displayed. + std::string m_placement; + + /// The opaque option of the legend. + std::string m_opaque; + + /// The alignment of the labels (either along the horizontal or vertical). + std::string m_alignment; + + /// The reverse option for the labels (if they printed on the left or right sides within the legend). + std::string m_reverse; + + /// The invert option of the labels (if they are printed from first to last or the other way around). + std::string m_invert; + + /// The justification mode of the labels in the legend (Left or Right gnuplot options). + std::string m_justification; + + /// The location of the legend title (left, center, right). + std::string m_title_loc = "left"; + + /// The width increment of the legend frame. + int m_width_increment; + + /// The height increment of the legend frame. + int m_height_increment; + + /// The length of the samples in the legend. + int m_samplen; + + /// The spacing between the titles in the legend. + int m_spacing; + + /// The maximum number of rows of titles in the legend. + std::string m_maxrows = "auto"; + + /// The maximum number of rows of titles in the legend. + std::string m_maxcols = "auto"; +}; + +inline LegendSpecs::LegendSpecs() +{ + atTopRight(); + title(""); + displayExpandWidthBy(internal::DEFAULT_LEGEND_FRAME_EXTRA_WIDTH); + displayExpandHeightBy(internal::DEFAULT_LEGEND_FRAME_EXTRA_HEIGHT); + displaySymbolLength(internal::DEFAULT_LEGEND_SAMPLE_LENGTH); + displaySpacing(internal::DEFAULT_LEGEND_SPACING); + displayVertical(); + displayLabelsAfterSymbols(); + displayJustifyLeft(); + displayStartFromFirst(); + opaque(); +} + +inline auto LegendSpecs::opaque() -> LegendSpecs& +{ + m_opaque = "opaque"; + return *this; +} + +inline auto LegendSpecs::transparent() -> LegendSpecs& +{ + m_opaque = "noopaque"; + return *this; +} + +inline auto LegendSpecs::atLeft() -> LegendSpecs& +{ + m_placement = "inside left"; + return *this; +} + +inline auto LegendSpecs::atRight() -> LegendSpecs& +{ + m_placement = "inside right"; + return *this; +} + +inline auto LegendSpecs::atCenter() -> LegendSpecs& +{ + m_placement = "inside center"; + return *this; +} + +inline auto LegendSpecs::atTop() -> LegendSpecs& +{ + m_placement = "inside center top"; + return *this; +} + +inline auto LegendSpecs::atTopLeft() -> LegendSpecs& +{ + m_placement = "inside left top"; + return *this; +} + +inline auto LegendSpecs::atTopRight() -> LegendSpecs& +{ + m_placement = "inside right top"; + return *this; +} + +inline auto LegendSpecs::atBottom() -> LegendSpecs& +{ + m_placement = "inside center bottom"; + return *this; +} + +inline auto LegendSpecs::atBottomLeft() -> LegendSpecs& +{ + m_placement = "inside left bottom"; + return *this; +} + +inline auto LegendSpecs::atBottomRight() -> LegendSpecs& +{ + m_placement = "inside right bottom"; + return *this; +} + +inline auto LegendSpecs::atOutsideLeft() -> LegendSpecs& +{ + m_placement = "lmargin center"; + return *this; +} + +inline auto LegendSpecs::atOutsideLeftTop() -> LegendSpecs& +{ + m_placement = "lmargin top"; + return *this; +} + +inline auto LegendSpecs::atOutsideLeftBottom() -> LegendSpecs& +{ + m_placement = "lmargin bottom"; + return *this; +} + +inline auto LegendSpecs::atOutsideRight() -> LegendSpecs& +{ + m_placement = "rmargin center"; + return *this; +} + +inline auto LegendSpecs::atOutsideRightTop() -> LegendSpecs& +{ + m_placement = "rmargin top"; + return *this; +} + +inline auto LegendSpecs::atOutsideRightBottom() -> LegendSpecs& +{ + m_placement = "rmargin bottom"; + return *this; +} + +inline auto LegendSpecs::atOutsideBottom() -> LegendSpecs& +{ + m_placement = "bmargin center"; + return *this; +} + +inline auto LegendSpecs::atOutsideBottomLeft() -> LegendSpecs& +{ + m_placement = "bmargin left"; + return *this; +} + +inline auto LegendSpecs::atOutsideBottomRight() -> LegendSpecs& +{ + m_placement = "bmargin right"; + return *this; +} + +inline auto LegendSpecs::atOutsideTop() -> LegendSpecs& +{ + m_placement = "tmargin center"; + return *this; +} + +inline auto LegendSpecs::atOutsideTopLeft() -> LegendSpecs& +{ + m_placement = "tmargin left"; + return *this; +} + +inline auto LegendSpecs::atOutsideTopRight() -> LegendSpecs& +{ + m_placement = "tmargin right"; + return *this; +} + +inline auto LegendSpecs::titleLeft() -> LegendSpecs& +{ + m_title_loc = "left"; + return *this; +} + +inline auto LegendSpecs::titleCenter() -> LegendSpecs& +{ + m_title_loc = "center"; + return *this; +} + +inline auto LegendSpecs::titleRight() -> LegendSpecs& +{ + m_title_loc = "right"; + return *this; +} + +inline auto LegendSpecs::displayVertical() -> LegendSpecs& +{ + m_alignment = "vertical"; + return *this; +} + +inline auto LegendSpecs::displayVerticalMaxRows(int value) -> LegendSpecs& +{ + m_maxrows = internal::str(value); + return *this; +} + +inline auto LegendSpecs::displayHorizontal() -> LegendSpecs& +{ + m_alignment = "horizontal"; + return *this; +} + +inline auto LegendSpecs::displayHorizontalMaxCols(int value) -> LegendSpecs& +{ + m_maxcols = internal::str(value); + return *this; +} + +inline auto LegendSpecs::displayLabelsBeforeSymbols() -> LegendSpecs& +{ + m_reverse = "noreverse"; + return *this; +} + +inline auto LegendSpecs::displayLabelsAfterSymbols() -> LegendSpecs& +{ + m_reverse = "reverse"; + return *this; +} + +inline auto LegendSpecs::displayJustifyLeft() -> LegendSpecs& +{ + m_justification = "Left"; + return *this; +} + +inline auto LegendSpecs::displayJustifyRight() -> LegendSpecs& +{ + m_justification = "Right"; + return *this; +} + +inline auto LegendSpecs::displayStartFromFirst() -> LegendSpecs& +{ + m_invert = "noinvert"; + return *this; +} + +inline auto LegendSpecs::displayStartFromLast() -> LegendSpecs& +{ + m_invert = "invert"; + return *this; +} + +inline auto LegendSpecs::displaySpacing(int value) -> LegendSpecs& +{ + m_spacing = value; + return *this; +} + +inline auto LegendSpecs::displayExpandWidthBy(int value) -> LegendSpecs& +{ + m_width_increment = value; + return *this; +} + +inline auto LegendSpecs::displayExpandHeightBy(int value) -> LegendSpecs& +{ + m_height_increment = value; + return *this; +} + +inline auto LegendSpecs::displaySymbolLength(int value) -> LegendSpecs& +{ + m_samplen = value; + return *this; +} + +inline auto LegendSpecs::repr() const -> std::string +{ + const auto show = ShowSpecsOf::repr(); + if(show == "no") + return "unset key"; + + auto titlespecs = TitleSpecsOf::repr(); + if(titlespecs.size()) + titlespecs += " " + m_title_loc; // attach left|center|right to title (e.g. title 'Legend' right) + + std::stringstream ss; + ss << "set key "; + ss << m_placement << " " << m_opaque << " "; + ss << m_alignment << " "; + ss << m_justification << " "; + ss << m_invert << " "; + ss << m_reverse << " "; + ss << "width " << m_width_increment << " "; + ss << "height " << m_height_increment << " "; + ss << "samplen " << m_samplen << " "; + ss << "spacing " << m_spacing << " "; + ss << TextSpecsOf::repr() << " "; + ss << titlespecs << " "; + ss << FrameSpecsOf::repr() << " "; + ss << "maxrows " << m_maxrows << " "; + ss << "maxcols " << m_maxcols << " "; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/LineSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/LineSpecsOf.hpp new file mode 100755 index 000000000..6f7c493d7 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/LineSpecsOf.hpp @@ -0,0 +1,133 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot { + +/// The class used to attach line options to a type. +template +class LineSpecsOf : virtual public Specs +{ + public: + /// Construct a default LineSpecsOf instance. + LineSpecsOf(); + + /// Set the line style of the underlying line object. + auto lineStyle(int value) -> DerivedSpecs&; + + /// Set the line type of the underlying line object. + auto lineType(int value) -> DerivedSpecs&; + + /// Set the line width of the underlying line object. + auto lineWidth(int value) -> DerivedSpecs&; + + /// Set the line color of the underlying line object. + auto lineColor(std::string value) -> DerivedSpecs&; + + /// Set the dash type of the underlying line object. + auto dashType(int value) -> DerivedSpecs&; + + /// Convert this LineSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The line style of the underlying line object (e.g., "ls 2"). + std::string m_linestyle; + + /// The line type of the underlying line object (e.g., "lt 3"). + std::string m_linetype; + + /// The line width of the underlying line object (e.g., "lw 2"). + std::string m_linewidth; + + /// The line color of the underlying line object (e.g., "lc rgb '#FF00FF'"). + std::string m_linecolor; + + /// The dash type of the underlying line object (e.g., "dt 2"). + std::string m_dashtype; +}; + +/// The class used to specify line options. +class LineSpecs : public LineSpecsOf {}; + +template +LineSpecsOf::LineSpecsOf() +{ +} + +template +auto LineSpecsOf::lineStyle(int value) -> DerivedSpecs& +{ + m_linestyle = "linestyle " + internal::str(value); + return static_cast(*this); +} + +template +auto LineSpecsOf::lineType(int value) -> DerivedSpecs& +{ + m_linetype = "linetype " + internal::str(value); + return static_cast(*this); +} + +template +auto LineSpecsOf::lineWidth(int value) -> DerivedSpecs& +{ + m_linewidth = "linewidth " + internal::str(value); + return static_cast(*this); +} + +template +auto LineSpecsOf::lineColor(std::string value) -> DerivedSpecs& +{ + m_linecolor = "linecolor '" + value + "'"; + return static_cast(*this); +} + +template +auto LineSpecsOf::dashType(int value) -> DerivedSpecs& +{ + m_dashtype = "dashtype " + internal::str(value); + return static_cast(*this); +} + +template +auto LineSpecsOf::repr() const -> std::string +{ + std::stringstream ss; // ensure it remains empty if no line style option has been given! + ss << m_linestyle << " "; + ss << m_linetype << " "; + ss << m_linewidth << " "; + ss << m_linecolor << " "; + ss << m_dashtype << " "; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/OffsetSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/OffsetSpecsOf.hpp new file mode 100755 index 000000000..4980f3540 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/OffsetSpecsOf.hpp @@ -0,0 +1,135 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot { + +/// The class used to attach offset options to a type. +template +class OffsetSpecsOf : virtual public Specs +{ + public: + /// Construct a default OffsetSpecsOf instance. + OffsetSpecsOf(); + + /// Shift the underlying plot element along the x direction by given number of characters (can be fraction). + auto shiftAlongX(double chars) -> DerivedSpecs&; + + /// Shift the underlying plot element along the y direction by given number of characters (can be fraction). + auto shiftAlongY(double chars) -> DerivedSpecs&; + + /// Shift the underlying plot element along the x direction within the graph coordinate system. + auto shiftAlongGraphX(double val) -> DerivedSpecs&; + + /// Shift the underlying plot element along the y direction within the graph coordinate system. + auto shiftAlongGraphY(double val) -> DerivedSpecs&; + + /// Shift the underlying plot element along the x direction within the screen coordinate system. + auto shiftAlongScreenX(double val) -> DerivedSpecs&; + + /// Shift the underlying plot element along the y direction within the screen coordinate system. + auto shiftAlongScreenY(double val) -> DerivedSpecs&; + + /// Convert this OffsetSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The offset of the title element along x direction. + std::string xoffset = "0"; + + /// The offset of the title element along y direction. + std::string yoffset = "0"; +}; + +/// The class used to specify offset options. +class OffsetSpecs : public OffsetSpecsOf {}; + +template +OffsetSpecsOf::OffsetSpecsOf() +{ +} + +template +auto OffsetSpecsOf::shiftAlongX(double chars) -> DerivedSpecs& +{ + xoffset = internal::str(chars); + return static_cast(*this); +} + +template +auto OffsetSpecsOf::shiftAlongY(double chars) -> DerivedSpecs& +{ + yoffset = internal::str(chars); + return static_cast(*this); +} + +template +auto OffsetSpecsOf::shiftAlongGraphX(double val) -> DerivedSpecs& +{ + xoffset = "graph " + internal::str(val); + return static_cast(*this); +} + +template +auto OffsetSpecsOf::shiftAlongGraphY(double val) -> DerivedSpecs& +{ + yoffset = "graph " + internal::str(val); + return static_cast(*this); +} + +template +auto OffsetSpecsOf::shiftAlongScreenX(double val) -> DerivedSpecs& +{ + xoffset = "screen " + internal::str(val); + return static_cast(*this); +} + +template +auto OffsetSpecsOf::shiftAlongScreenY(double val) -> DerivedSpecs& +{ + yoffset = "screen " + internal::str(val); + return static_cast(*this); +} + +template +auto OffsetSpecsOf::repr() const -> std::string +{ + std::string offset; + + if(xoffset != "0" || yoffset != "0") + offset = "offset " + xoffset + ", " + yoffset; + + std::stringstream ss; + ss << gnuplot::optionStr(offset); + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/PointSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/PointSpecsOf.hpp new file mode 100755 index 000000000..463cfb229 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/PointSpecsOf.hpp @@ -0,0 +1,91 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot { + +/// The class used to attach point options to a type. +template +class PointSpecsOf : virtual public Specs +{ + public: + /// Construct a default PointSpecsOf instance. + PointSpecsOf(); + + /// Set the point type of the underlying plot object. + auto pointType(int value) -> DerivedSpecs&; + + /// Set the point size of the underlying plot object. + auto pointSize(int value) -> DerivedSpecs&; + + /// Convert this PointSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The point type of the underlying plot object (e.g., "pt 3"). + std::string m_pointtype; + + /// The point width of the underlying plot object (e.g., "ps 2"). + std::string m_pointsize; +}; + +/// The class used to specify point options. +class PointSpecs : public PointSpecsOf {}; + +template +PointSpecsOf::PointSpecsOf() +{ +} + +template +auto PointSpecsOf::pointType(int value) -> DerivedSpecs& +{ + m_pointtype = "pointtype " + internal::str(value); + return static_cast(*this); +} + +template +auto PointSpecsOf::pointSize(int value) -> DerivedSpecs& +{ + m_pointsize = "pointsize " + internal::str(value); + return static_cast(*this); +} + +template +auto PointSpecsOf::repr() const -> std::string +{ + std::stringstream ss; // ensure it remains empty if no point style option has been given! + ss << m_pointtype << " "; + ss << m_pointsize; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/ShowSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/ShowSpecsOf.hpp new file mode 100755 index 000000000..df5ddd231 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/ShowSpecsOf.hpp @@ -0,0 +1,92 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include + +namespace sciplot { + +/// The class used to attach visibility options to a type. +template +class ShowSpecsOf : virtual public Specs +{ +public: + /// Construct a default ShowSpecsOf instance. + ShowSpecsOf(); + + /// Set the visibility status of the plot element. + auto show(bool value=true) -> DerivedSpecs&; + + /// Set the visibility status of the plot element as hidden. + auto hide() -> DerivedSpecs&; + + /// Return true if the underlying plot element is hidden. + auto isHidden() const -> bool; + + /// Convert this ShowSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + +private: + /// The boolean flag that indicates if the plot element is shown or not. + bool m_show; +}; + +/// The class used to specify visibility options. +class ShowSpecs : public ShowSpecsOf {}; + +template +ShowSpecsOf::ShowSpecsOf() +{ + show(); +} + +template +auto ShowSpecsOf::show(bool value) -> DerivedSpecs& +{ + m_show = value; + return static_cast(*this); +} + +template +auto ShowSpecsOf::hide() -> DerivedSpecs& +{ + return show(false); +} + +template +auto ShowSpecsOf::isHidden() const -> bool +{ + return !m_show; +} + +template +auto ShowSpecsOf::repr() const -> std::string +{ + return m_show ? "" : "no"; +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/Specs.hpp b/src/cpp/3rdparty/sciplot/specs/Specs.hpp new file mode 100755 index 000000000..4b7133fec --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/Specs.hpp @@ -0,0 +1,61 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include + +namespace sciplot { + +/// The base class for other specs classes (e.g., LineSpecsOf, DrawSpecs, BorderSpecs, etc.) +template +class Specs +{ + public: + /// Pure virtual destructor (this class is an abstract base class). + virtual ~Specs() = default; + + /// Return a string representation of this object of some class that derives from specs. + virtual auto repr() const -> std::string = 0; + + /// Return a string representation of this object of some class that derives from specs. + operator std::string() const { return repr(); } + + /// Return a reference to the specs object of class derived from this. + auto derived() -> DerivedSpecs& { return static_cast(*this); } + + /// Return a const reference to the specs object of class derived from this. + auto derived() const -> const DerivedSpecs& { return static_cast(*this); } +}; + +/// Output the state of a specs object to a ostream object. +template +auto operator<<(std::ostream& stream, const Specs& obj) -> std::ostream& +{ + return stream << obj.repr(); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/TextSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/TextSpecsOf.hpp new file mode 100755 index 000000000..9616ac811 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/TextSpecsOf.hpp @@ -0,0 +1,97 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot { + +/// The class used to attach text options to a type. +template +class TextSpecsOf : public FontSpecsOf +{ + public: + /// Construct a default TextSpecsOf instance. + TextSpecsOf(); + + /// Set the color of the text (e.g., `"blue"`, `"#404040"`) + auto textColor(std::string color) -> DerivedSpecs&; + + /// Set the enhanced mode of the text. + /// The enhanced text mode allows superscript text to be represented as + /// `a^x`, subscript text with `a_x`, and combined superscript and + /// subscript text with `a@^b_{cd}`. + /// For more details, read "Enhanced text mode" section of the Gnuplot manual. + auto enhanced(bool value=false) -> DerivedSpecs&; + + /// Convert this TextSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The color of the title text. + std::string m_color; + + /// The enhanced mode of the text (enhanced or noenhanced) + std::string m_enhanced; +}; + +/// The class used to specify text options. +class TextSpecs : public TextSpecsOf {}; + +template +TextSpecsOf::TextSpecsOf() +{ + enhanced(true); + textColor(internal::DEFAULT_TEXTCOLOR); +} + +template +auto TextSpecsOf::textColor(std::string color) -> DerivedSpecs& +{ + m_color = "'" + color + "'"; + return static_cast(*this); +} + +template +auto TextSpecsOf::enhanced(bool value) -> DerivedSpecs& +{ + m_enhanced = value ? "enhanced" : "noenhanced"; + return static_cast(*this); +} + +template +auto TextSpecsOf::repr() const -> std::string +{ + std::stringstream ss; + ss << m_enhanced << " textcolor " << m_color << " "; + ss << FontSpecsOf::repr(); + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/TicsSpecs.hpp b/src/cpp/3rdparty/sciplot/specs/TicsSpecs.hpp new file mode 100755 index 000000000..2268d05ca --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/TicsSpecs.hpp @@ -0,0 +1,88 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include + +namespace sciplot +{ + +/// The class used to specify options for tics. +class TicsSpecs : public TicsSpecsBaseOf +{ + public: + /// Construct a default TicsSpecs instance. + TicsSpecs(); + + /// Set the tics to be displayed on the front of all plot elements. + auto stackFront() -> TicsSpecs&; + + /// Set the tics to be displayed on the back of all plot elements. + auto stackBack() -> TicsSpecs&; + + /// Convert this TicsSpecs object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The depth where the tics are displayed (back or front). + std::string m_depth; +}; + +inline TicsSpecs::TicsSpecs() + : TicsSpecsBaseOf() +{ + stackFront(); +} + +inline auto TicsSpecs::stackFront() -> TicsSpecs& +{ + m_depth = "front"; + return *this; +} + +inline auto TicsSpecs::stackBack() -> TicsSpecs& +{ + m_depth = "back"; + return *this; +} + +inline auto TicsSpecs::repr() const -> std::string +{ + const auto baserepr = TicsSpecsBaseOf::repr(); + + if (isHidden()) + return baserepr; + + std::stringstream ss; + ss << baserepr << " "; + ss << m_depth; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/TicsSpecsBaseOf.hpp b/src/cpp/3rdparty/sciplot/specs/TicsSpecsBaseOf.hpp new file mode 100755 index 000000000..3d774a341 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/TicsSpecsBaseOf.hpp @@ -0,0 +1,239 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include +#include +#include + +namespace sciplot +{ + +/// The class used to attach common tic options to a type that also specifies tic options. +template +class TicsSpecsBaseOf : public TextSpecsOf, public OffsetSpecsOf, public ShowSpecsOf +{ + public: + /// Construct a default TicsSpecsBaseOf instance. + TicsSpecsBaseOf(); + + /// Set the tics to be displayed along the axis. + auto alongAxis() -> DerivedSpecs&; + + /// Set the tics to be displayed along the border. + auto alongBorder() -> DerivedSpecs&; + + /// Set the tics to be mirrored on the opposite border if `true`. + auto mirror(bool value = true) -> DerivedSpecs&; + + /// Set the tics to be displayed inside the graph. + auto insideGraph() -> DerivedSpecs&; + + /// Set the tics to be displayed outside the graph. + auto outsideGraph() -> DerivedSpecs&; + + /// Set the tics to be rotated by 90 degrees if `true`. + auto rotate(bool value = true) -> DerivedSpecs&; + + /// Set the tics to be rotated by given degrees. + auto rotateBy(double degrees) -> DerivedSpecs&; + + /// Set the scale for the major tics (identical to method scaleMajorBy). + auto scaleBy(double value) -> DerivedSpecs&; + + /// Set the scale for the major tics. + auto scaleMajorBy(double value) -> DerivedSpecs&; + + /// Set the scale for the minor tics. + auto scaleMinorBy(double value) -> DerivedSpecs&; + + /// Set the format of the tics using a format expression (`"%.2f"`) + auto format(std::string fmt) -> DerivedSpecs&; + + /// Set logarithmic scale with base for an axis. + auto logscale(int base = 10) -> DerivedSpecs&; + + /// Convert this TicsSpecsBaseOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + /// Convert this TicsSpecsBaseOf object into a gnuplot formatted string. + auto repr(std::string axis) const -> std::string; + + private: + /// The option indicating if tics are displayed along axis or border. + std::string m_along; + + /// The mirror option of the tics. + std::string m_mirror; + + /// The rotate option for the tics. + std::string m_rotate; + + /// The place where the tics are displayed (in or out). + std::string m_inout; + + /// The format expression for formatting the display of the tics. + std::string m_format; + + /// The scale of the major tics. + double m_scalemajor = 1.0; + + /// The scale of the minor tics. + double m_scaleminor = 1.0; + + /// Logarithmic scaling base settings for the axis. + std::string m_logscaleBase; +}; + +template +TicsSpecsBaseOf::TicsSpecsBaseOf() +{ + alongBorder(); + mirror(internal::DEFAULT_TICS_MIRROR); + outsideGraph(); + rotate(internal::DEFAULT_TICS_ROTATE); + scaleMajorBy(internal::DEFAULT_TICS_SCALE_MAJOR_BY); + scaleMinorBy(internal::DEFAULT_TICS_SCALE_MINOR_BY); +} + +template +auto TicsSpecsBaseOf::alongAxis() -> DerivedSpecs& +{ + m_along = "axis"; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::alongBorder() -> DerivedSpecs& +{ + m_along = "border"; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::mirror(bool value) -> DerivedSpecs& +{ + m_mirror = value ? "mirror" : "nomirror"; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::rotate(bool value) -> DerivedSpecs& +{ + m_rotate = value ? "rotate" : "norotate"; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::rotateBy(double degrees) -> DerivedSpecs& +{ + m_rotate = "rotate by " + internal::str(degrees); + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::insideGraph() -> DerivedSpecs& +{ + m_inout = "in"; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::outsideGraph() -> DerivedSpecs& +{ + m_inout = "out"; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::scaleBy(double value) -> DerivedSpecs& +{ + return scaleMajorBy(value); +} + +template +auto TicsSpecsBaseOf::scaleMajorBy(double value) -> DerivedSpecs& +{ + m_scalemajor = value; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::scaleMinorBy(double value) -> DerivedSpecs& +{ + m_scaleminor = value; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::format(std::string fmt) -> DerivedSpecs& +{ + m_format = "'" + fmt + "'"; + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::logscale(int base) -> DerivedSpecs& +{ + m_logscaleBase = std::to_string(base); + return static_cast(*this); +} + +template +auto TicsSpecsBaseOf::repr() const -> std::string +{ + return repr(""); +} + +template +auto TicsSpecsBaseOf::repr(std::string axis) const -> std::string +{ + const auto show = ShowSpecsOf::repr(); + if (show == "no") + return "unset " + axis + "tics"; + + std::stringstream ss; + if (!m_logscaleBase.empty()) + { + ss << "set logscale " + axis + " " + m_logscaleBase + "\n"; + } + ss << "set " + axis + "tics" + << " "; + ss << m_along << " "; + ss << m_mirror << " "; + ss << m_inout << " "; + ss << "scale " << m_scalemajor << "," << m_scaleminor << " "; + ss << m_rotate << " "; + ss << OffsetSpecsOf::repr() << " "; + ss << TextSpecsOf::repr() << " "; + ss << m_format; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/TicsSpecsMajor.hpp b/src/cpp/3rdparty/sciplot/specs/TicsSpecsMajor.hpp new file mode 100755 index 000000000..1bc4df953 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/TicsSpecsMajor.hpp @@ -0,0 +1,210 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include + +// sciplot includes +#include +#include + +namespace sciplot +{ + +/// The class used to specify options for major tics of a specific axis. +class TicsSpecsMajor : public TicsSpecsBaseOf +{ + public: + /// Construct a default TicsSpecsMajor instance. + TicsSpecsMajor(std::string axis); + + /// Set the values of the tics to be identified automatically. + auto automatic() -> TicsSpecsMajor&; + + /// Set the start value for the tics (you must also call method @ref increment). + auto start(double value) -> TicsSpecsMajor&; + + /// Set the increment for the tics (start and end values determined automatically). + auto increment(double value) -> TicsSpecsMajor&; + + /// Set the end value for the tics (you must also call methods @ref start and @ref increment). + auto end(double value) -> TicsSpecsMajor&; + + /// Set the start, increment and end values of the tics. + auto interval(double start, double increment, double end) -> TicsSpecsMajor&; + + /// Set the values of the tics that should be displayed. + auto at(const std::vector& values) -> TicsSpecsMajor&; + + /// Set the labels that should be displayed on given tic values. + auto at(const std::vector& values, const std::vector& labels) -> TicsSpecsMajor&; + + /// Add more tics to be displayed with given tic values. + auto add(const std::vector& values) -> TicsSpecsMajor&; + + /// Add more tics to be displayed with given tic values and corresponding labels. + auto add(const std::vector& values, const std::vector& labels) -> TicsSpecsMajor&; + + /// Convert this TicsSpecsMajor object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The name of the axis associated with these tics. + const std::string m_axis; + + /// The start value for the tics. + std::string m_start; + + /// The increment for the tics. + std::string m_increment; + + /// The end value for the tics. + std::string m_end; + + /// The values/labels of the tics that should be displayed. + std::string m_at; + + /// The extra values/labels of the tics to be displayed. + std::string m_add; +}; + +inline TicsSpecsMajor::TicsSpecsMajor(std::string axis) + : TicsSpecsBaseOf(), m_axis(axis) +{ + if (axis.empty()) + throw std::runtime_error( + "You have provided an empty string " + "in `axis` argument of constructor TicsSpecsMajor(axis)."); +} + +inline auto TicsSpecsMajor::automatic() -> TicsSpecsMajor& +{ + // clear strings related to tics values/labels + m_start = ""; + m_end = ""; + m_increment = ""; + m_at = ""; + return *this; +} + +inline auto TicsSpecsMajor::start(double value) -> TicsSpecsMajor& +{ + m_start = internal::str(value) + ", "; + m_at = m_start + m_increment + m_end; + return *this; +} + +inline auto TicsSpecsMajor::increment(double value) -> TicsSpecsMajor& +{ + m_increment = internal::str(value); + m_at = m_start + m_increment + m_end; + return *this; +} + +inline auto TicsSpecsMajor::end(double value) -> TicsSpecsMajor& +{ + m_end = ", " + internal::str(value); + m_at = m_start + m_increment + m_end; + return *this; +} + +inline auto TicsSpecsMajor::interval(double start, double increment, double end) -> TicsSpecsMajor& +{ + if (increment <= 0.0) throw std::runtime_error("The `increment` argument in method TicsSpecsMajor::interval must be positive."); + if (end <= start) throw std::runtime_error("The `end` argument in method TicsSpecsMajor::interval must be greater than `start`."); + std::stringstream ss; + ss << start << ", " << increment << ", " << end; + m_at = ss.str(); + return *this; +} + +inline auto TicsSpecsMajor::at(const std::vector& values) -> TicsSpecsMajor& +{ + std::stringstream ss; + ss << "("; + for (auto i = 0; i < values.size(); ++i) + ss << (i == 0 ? "" : ", ") << values[i]; + ss << ")"; + m_at = ss.str(); + return *this; +} + +inline auto TicsSpecsMajor::at(const std::vector& values, const std::vector& labels) -> TicsSpecsMajor& +{ + std::stringstream ss; + ss << "("; + for (auto i = 0; i < values.size(); ++i) + ss << (i == 0 ? "" : ", ") << "'" << labels[i] << "' " << values[i]; + ss << ")"; + m_at = ss.str(); + return *this; +} + +inline auto TicsSpecsMajor::add(const std::vector& values) -> TicsSpecsMajor& +{ + std::stringstream ss; + ss << "add ("; + for (auto i = 0; i < values.size(); ++i) + ss << (i == 0 ? "" : ", ") << values[i]; + ss << ")"; + m_add = ss.str(); + return *this; +} + +inline auto TicsSpecsMajor::add(const std::vector& values, const std::vector& labels) -> TicsSpecsMajor& +{ + std::stringstream ss; + ss << "add ("; + for (auto i = 0; i < values.size(); ++i) + ss << (i == 0 ? "" : ", ") << "'" << labels[i] << "' " << values[i]; + ss << ")"; + m_add = ss.str(); + return *this; +} + +inline auto TicsSpecsMajor::repr() const -> std::string +{ + const auto baserepr = TicsSpecsBaseOf::repr(m_axis); + + if (isHidden()) + return baserepr; + + if (m_start.size() && m_increment.empty()) + throw std::runtime_error("You have called method TicsSpecsMajor::start but not TicsSpecsMajor::increment."); + if (m_end.size() && m_increment.empty()) + throw std::runtime_error("You have called method TicsSpecsMajor::end but not TicsSpecsMajor::increment."); + if (m_end.size() && m_start.empty()) + throw std::runtime_error("You have called method TicsSpecsMajor::end but not TicsSpecsMajor::start."); + + std::stringstream ss; + ss << baserepr << " "; + ss << m_at << " "; + ss << m_add << " "; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/TicsSpecsMinor.hpp b/src/cpp/3rdparty/sciplot/specs/TicsSpecsMinor.hpp new file mode 100755 index 000000000..b6ba491ae --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/TicsSpecsMinor.hpp @@ -0,0 +1,97 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// C++ includes +#include + +// sciplot includes +#include +#include +#include + +namespace sciplot +{ + +/// The class used to specify options for minor tics of a specific axis. +class TicsSpecsMinor : public ShowSpecsOf +{ + public: + /// Construct a default TicsSpecsMinor instance. + TicsSpecsMinor(std::string axis); + + /// Set the number of minor tics between major tics to be identified automatically. + auto automatic() -> TicsSpecsMinor&; + + /// Set the number of minor tics between major tics. + auto number(int value) -> TicsSpecsMinor&; + + /// Convert this TicsSpecsMinor object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The name of the axis associated with these tics. + const std::string m_axis; + + /// The frequency of minor tics between major tics (number of minor tics = frequency - 1). + std::string m_frequency; +}; + +inline TicsSpecsMinor::TicsSpecsMinor(std::string axis) + : m_axis(axis) +{ + if (axis.empty()) + throw std::runtime_error( + "You have provided an empty string " + "in `axis` argument of constructor TicsSpecsMinor(axis)."); +} + +inline auto TicsSpecsMinor::automatic() -> TicsSpecsMinor& +{ + m_frequency = ""; + return *this; +} + +inline auto TicsSpecsMinor::number(int value) -> TicsSpecsMinor& +{ + value = std::max(value, 0); + m_frequency = internal::str(value + 1); + return *this; +} + +inline auto TicsSpecsMinor::repr() const -> std::string +{ + if (isHidden()) + return "unset m" + m_axis + "tics"; + + std::stringstream ss; + ss << "set m" << m_axis << "tics" + << " "; + ss << m_frequency; + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/sciplot/specs/TitleSpecsOf.hpp b/src/cpp/3rdparty/sciplot/specs/TitleSpecsOf.hpp new file mode 100755 index 000000000..b753ffa27 --- /dev/null +++ b/src/cpp/3rdparty/sciplot/specs/TitleSpecsOf.hpp @@ -0,0 +1,180 @@ +// sciplot - a modern C++ scientific plotting library powered by gnuplot +// https://github.com/sciplot/sciplot +// +// Licensed under the MIT License . +// +// Copyright (c) 2018-2021 Allan Leal +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +// sciplot includes +#include +#include +#include +#include + +namespace sciplot { + +/// The class used to attach title options to a type. +template +class TitleSpecsOf : virtual public Specs +{ + public: + /// Construct a default TitleSpecsOf instance. + TitleSpecsOf(); + + /// Set the text of the title. + auto title(std::string title) -> DerivedSpecs&; + + /// Shift the title element along the x direction by given number of characters (can be fraction). + auto titleShiftAlongX(double chars) -> DerivedSpecs&; + + /// Shift the title element along the y direction by given number of characters (can be fraction). + auto titleShiftAlongY(double chars) -> DerivedSpecs&; + + /// Shift the title element along the x direction within the graph coordinate system. + auto titleShiftAlongGraphX(double val) -> DerivedSpecs&; + + /// Shift the title element along the y direction within the graph coordinate system. + auto titleShiftAlongGraphY(double val) -> DerivedSpecs&; + + /// Shift the title element along the x direction within the screen coordinate system. + auto titleShiftAlongScreenX(double val) -> DerivedSpecs&; + + /// Shift the title element along the y direction within the screen coordinate system. + auto titleShiftAlongScreenY(double val) -> DerivedSpecs&; + + /// Set the color of the title text (e.g., `"blue"`, `"#404040"`) + auto titleTextColor(std::string color) -> DerivedSpecs&; + + /// Set the font name of the title text (e.g., Helvetica, Georgia, Times). + auto titleFontName(std::string name) -> DerivedSpecs&; + + /// Set the font point size of the title text (e.g., 10, 12, 16). + auto titleFontSize(int size) -> DerivedSpecs&; + + /// Convert this TitleSpecsOf object into a gnuplot formatted string. + auto repr() const -> std::string; + + private: + /// The text of the title. + std::string m_title; + + /// The text options for the title. + TextSpecs m_text_specs; + + /// The offset options for the title. + OffsetSpecs m_offset_specs; +}; + +/// The class used to specify title options. +class TitleSpecs : public TitleSpecsOf {}; + +template +TitleSpecsOf::TitleSpecsOf() +{ + title(""); +} + +template +auto TitleSpecsOf::title(std::string title) -> DerivedSpecs& +{ + m_title = "'" + title + "'"; + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleShiftAlongX(double chars) -> DerivedSpecs& +{ + m_offset_specs.shiftAlongX(chars); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleShiftAlongY(double chars) -> DerivedSpecs& +{ + m_offset_specs.shiftAlongY(chars); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleShiftAlongGraphX(double val) -> DerivedSpecs& +{ + m_offset_specs.shiftAlongGraphX(val); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleShiftAlongGraphY(double val) -> DerivedSpecs& +{ + m_offset_specs.shiftAlongGraphY(val); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleShiftAlongScreenX(double val) -> DerivedSpecs& +{ + m_offset_specs.shiftAlongScreenX(val); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleShiftAlongScreenY(double val) -> DerivedSpecs& +{ + m_offset_specs.shiftAlongScreenY(val); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleTextColor(std::string color) -> DerivedSpecs& +{ + m_text_specs.textColor(color); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleFontName(std::string name) -> DerivedSpecs& +{ + m_text_specs.fontName(name); + return static_cast(*this); +} + +template +auto TitleSpecsOf::titleFontSize(int size) -> DerivedSpecs& +{ + m_text_specs.fontSize(size); + return static_cast(*this); +} + +template +auto TitleSpecsOf::repr() const -> std::string +{ + if(m_title == "''") + return ""; + + std::stringstream ss; + ss << "title " << m_title << " "; + ss << m_text_specs.repr() << " "; + ss << m_offset_specs.repr(); + return internal::removeExtraWhitespaces(ss.str()); +} + +} // namespace sciplot diff --git a/src/cpp/3rdparty/slr/crd.h b/src/cpp/3rdparty/slr/crd.h new file mode 100644 index 000000000..a4e4ed641 --- /dev/null +++ b/src/cpp/3rdparty/slr/crd.h @@ -0,0 +1,447 @@ +/* Consolidated laser Ranging Data format (CRD) + * record and variable definitions for FORTRAN + * R. Ricklefs UT/CSR July 2007 + * History: + * 08/xx/07 - added H3 Target type (v0.27) + * 11/26/07 - added H4 data quality alert + * and #10 stop number + * and #20 origin of values (v0.27) rlr. + * 05/07/08 - Expand all configuration and data section character strings + * to allow up to 40 characters (plus NULL). + * - Added detector channel to normalpoint (11) and calibration (40) + * records. + * - Added field for 'crd' literal to H1. + * - Record '21' sky_clarity is not double rather than int. + * (v1.00 rlr) + * 03/08/18 - Changes for CRD v2.00. rlr. + * 06/26/19 - Added #42 calibration "shot" record for v2.00. rlr. + * 07/xx/19 - Added NA_VALUE. v2.00. rlr. + * 09/05/19 - Added NA_VALUEF. v2.01. rlr. + * + * ---------------------------------------------------------------------- +*/ + +#ifndef _CRD_H +#define _CRD_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Common name abbreviations: + * app = applied + * cdp = Crustal Dynamics Project (old NASA name) + * CofM = Center of Mass + * corr = correction or corrected + * est = estimated + * ind = indicator + * num = number + * osc = oscillator + * off = offset + * PmM = peak minus mean + * sic = (Goddard) Satellite ID Code + * stn = station + * SC = spacecraft + * sys = system + * utc = Universal Time Coordinated + * xcv = receive + * xmt = transmit + */ +#define NA_VALUE (-10000000) +#define NA_VALUEF (-1.0e30) + +/* Ranging data header fields */ + /* H1 - format header */ + struct CrdH1 { + char crd_literal[4]; + int format_version; + int prod_year; + int prod_mon; + int prod_day; + int prod_hour; + }; + + /* H2 - station header */ + struct CrdH2 { + char stn_name[11]; + int cdp_pad_id; + int cdp_sys_num; + int cdp_occ_num; + int stn_timescale; + char stn_network[11]; + }; + + /* H3 - spacecraft header */ + struct CrdH3 { + char target_name[11]; + int ilrs_id; + int sic; + int norad; + int SC_timescale; + int target_type; + int target_class; // V2 + int target_loc; // V2 + }; + + /* H4 - Session header */ + struct CrdH4 { + int data_type; + int start_year; + int start_mon; + int start_day; + int start_hour; + int start_min; + int start_sec; + int end_year; + int end_mon; + int end_day; + int end_hour; + int end_min; + int end_sec; + int data_release; + int refraction_app_ind; + int CofM_app_ind; + int xcv_amp_app_ind; + int stn_sysdelay_app_ind; + int SC_sysdelay_app_ind; + int range_type_ind; + int data_qual_alert_ind; + }; + + /* H5 - Prediction header */ + struct CrdH5 { // V2 + int prediction_type; + int year_of_century; + char date_and_time[13]; + char prediction_provider[11]; + int sequence_number; + }; + + /* Need indicators that these have been read? */ + /* H8 - End of Session footer */ + /* H9 - End of File footer */ + +/* Ranging data configuration fields (1 of n) */ + /* C0 - System Configuration Record */ + struct CrdC0 { + int detail_type; + double xmit_wavelength; +/** + char sysconfig_id[5]; + char laserconfig_id[4]; + char detectorconfig_id[4]; + char timingconfig_id[4]; + char xponderconfig_id[4]; + char softwareconfig_id[4]; + char metconfig_id[4]; + char calconfig_id[4]; +**/ + char config_ids[10][41]; + }; + + /* C1 - Laser Configuration Record */ + struct CrdC1 { + int detail_type; + char laser_config_id[41]; + char laser_type[41]; + double prim_wavelength; /* Primary wavelength of laser */ + double nom_fire_rate; /* Nominal fire rate of laser */ + double pulse_energy; + double pulse_width; + double beam_div; + int pulses_in_semitrain; /* for multi-pulse systems */ + }; + + /* C2 - Detector Configuration Record */ + struct CrdC2 { + int detail_type; + char detector_config_id[41]; + char detector_type[41]; + double app_wavelength; + double qe; /* quantum efficiency (in %) */ + double voltage; + double dark_count; + char output_pulse_type[41]; + double output_pulse_width; + double spectral_filter; + double spectral_filter_xmission; /* % transmission of filter */ + double spatial_filter; + char signal_proc[41]; /* signal processing algorithm or pgm name */ + double amp_gain; + double amp_bandwidth; + int amp_in_use; + }; + + /* C3 - Timing Configuration Record */ + struct CrdC3 { + int detail_type; + char timing_config_id[41]; + char time_source[41]; + char freq_source[41]; + char timer[41]; + char timer_serial_num[41]; + double epoch_delay_corr; + }; + + /* C4 - Transponder Configuration Record */ + struct CrdC4 { + int detail_type; + char xponder_config_id[41]; + long double est_stn_utc_offset; + double est_stn_osc_drift; + long double est_xponder_utc_offset; + double est_xponder_osc_drift; + long double xponder_clock_ref_time; + int stn_off_drift_app_ind; + int SC_off_drift_app_ind; + int SC_time_simplified_ind; + }; + + /* C5 - Software Configuration Record */ + struct CrdC5 { // V2 + int detail_type; + char software_config_id[41]; + char tracking_software[41]; + char tracking_software_versions[41]; + char processing_software[41]; + char processing_software_versions[41]; + }; + + /* C6 - Meteorology Configuration Record */ + struct CrdC6 { // V2 + int detail_type; + char met_config_id[41]; + char pressure_sensor_manufacturer[41]; + char pressure_sensor_model[41]; + char pressure_sensor_serial_num[41]; + char temperature_sensor_manufacturer[41]; + char temperature_sensor_model[41]; + char temperature_sensor_serial_num[41]; + char humidity_sensor_manufacturer[41]; + char humidity_sensor_model[41]; + char humidity_sensor_serial_num[41]; + }; + + /* C7 - Calibration Target Configuration Record */ + struct CrdC7 { // V2 + int detail_type; + char calconfig_id[41]; + char target_name[41]; + double surveyed_target_dist; + double survey_error; + double other_fixed_delays; + double pulse_energy; + char processing_software[41]; + char processing_software_version[41]; + }; + +/* Ranging data fields */ + /* 10 - Range Record */ + struct CrdD10 { + long double sec_of_day; + long double time_of_flight; + char sysconfig_id[41]; + int epoch_event; + int filter_flag; + int detector_channel; + int stop_number; + int xcv_amp; + int xmt_amp; // V2 + }; + + /* 11 - Normal Point Record */ + struct CrdD11 { + long double sec_of_day; + long double time_of_flight; + char sysconfig_id[41]; + int epoch_event; + double np_window_length; + int num_ranges; + double bin_rms; + double bin_skew; + double bin_kurtosis; + double bin_PmM; + double return_rate; + int detector_channel; + double signal_to_noise; // V2 + }; + + /* 12 - Range Supplement Record */ + struct CrdD12 { + long double sec_of_day; + char sysconfig_id[41]; + double refraction_corr; + double target_CofM_corr; + double nd_value; + double time_bias; + double range_rate; // V2 + }; + + /* 20 - Meteorological Record */ + struct CrdD20 { + long double sec_of_day; + double pressure; + double temperature; + double humidity; + int value_origin; + }; + + /* 21 - Meteorological Supplement Record */ + struct CrdD21 { + long double sec_of_day; + double wind_speed; + double wind_direction; + char weather_conditions[41]; // V2 + int visibility; + double sky_clarity; + int atmospheric_seeing; + int cloud_cover; + double sky_temperature; // V2 + }; + + /* 30 - Pointing Angles Record */ + struct CrdD30 { + long double sec_of_day; + double azimuth; + double elevation; + int direction_ind; + int angle_origin_ind; + int refraction_corr_ind; + double azimuth_rate; // v2 + double elevation_rate; // V2 + }; + + /* 40 - Calibration Record */ + struct CrdD40 { + long double sec_of_day; + int type_of_data; + char sysconfig_id[41]; + int num_points_recorded; + int num_points_used; + double one_way_target_dist; + double cal_sys_delay; + double cal_delay_shift; + double cal_rms; + double cal_skew; + double cal_kurtosis; + double cal_PmM; + int cal_type_ind; + int cal_shift_type_ind; + int detector_channel; + int cal_span; + double cal_return_rate; + }; + + /* 42 - Calibration "Shot" Record */ + struct CrdD42 { // V2 + long double sec_of_day; + long double time_of_flight; + char sysconfig_id[41]; + char calconfig_id[41]; + double other_variable_delays; + int type_of_data; + int cal_type_ind; + int filter_flag; + int detector_channel; + int stop_number; + int cal_span; + int xcv_amp; + int xmt_amp; + }; + + /* 50 - Session Statistics Record */ + struct CrdD50 { + char sysconfig_id[41]; + double sess_rms; + double sess_skew; + double sess_kurtosis; + double sess_PmM; + int data_qual_ind; + }; + + /* 60 - Compatibility Record */ + // OBSOLETE -- V2 + struct CrdD60 { + char sysconfig_id[41]; + int sys_change_ind; + int sys_config_ind; + }; + + /* 9X - User Defined Record */ + struct CrdD9x { + /********** + Add userdefined record types and fields here + **********/ + }; + + /* 00 - Comment Record */ + struct CrdD00 { + char comment[81]; + }; + +int read_h1 (char *, struct CrdH1 *); +int read_h2 (char *, struct CrdH2 *); +int read_h3 (char *, struct CrdH3 *); +int read_h4 (char *, struct CrdH4 *); +int read_h5 (char *, struct CrdH5 *); +int read_h8 (char*); +int read_h9 (char*); +int read_c0 (char *, struct CrdC0 *); +int read_c1 (char *, struct CrdC1 *); +int read_c2 (char *, struct CrdC2 *); +int read_c3 (char *, struct CrdC3 *); +int read_c4 (char *, struct CrdC4 *); +int read_c5 (char *, struct CrdC5 *); +int read_c6 (char *, struct CrdC6 *); +int read_c7 (char *, struct CrdC7 *); +int read_10 (char *, struct CrdD10 *); +int read_11 (char *, struct CrdD11 *); +int read_12 (char *, struct CrdD12 *); +int read_20 (char *, struct CrdD20 *); +int read_21 (char *, struct CrdD21 *); +int read_30 (char *, struct CrdD30 *); +int read_40 (char *, struct CrdD40 *); +int read_41 (char *, struct CrdD40 *); +int read_42 (char *, struct CrdD42 *); +int read_50 (char *, struct CrdD50 *); +int read_60 (char *, struct CrdD60 *); +int read_9x (char *, struct CrdD9x *); +int read_00 (char *, struct CrdD00 *); + +int write_h1 (FILE *, struct CrdH1); +int write_h2 (FILE *, struct CrdH2); +int write_h3 (FILE *, struct CrdH3); +int write_h4 (FILE *, struct CrdH4); +int write_h5 (FILE *, struct CrdH5); +int write_h8 (FILE *); +int write_h9 (FILE *); +int write_c0 (FILE *, struct CrdC0); +int write_c1 (FILE *, struct CrdC1); +int write_c2 (FILE *, struct CrdC2); +int write_c3 (FILE *, struct CrdC3); +int write_c4 (FILE *, struct CrdC4); +int write_c5 (FILE *, struct CrdC5); +int write_c6 (FILE *, struct CrdC6); +int write_c7 (FILE *, struct CrdC7); +int write_10 (FILE *, struct CrdD10); +int write_11 (FILE *, struct CrdD11); +int write_12 (FILE *, struct CrdD12); +int write_20 (FILE *, struct CrdD20); +int write_21 (FILE *, struct CrdD21); +int write_30 (FILE *, struct CrdD30); +int write_40 (FILE *, struct CrdD40); +int write_41 (FILE *, struct CrdD40); +int write_42 (FILE *, struct CrdD42); +int write_50 (FILE *, struct CrdD50); +int write_60 (FILE *, struct CrdD60); +int write_9x (FILE *, struct CrdD9x); +int write_00 (FILE *, struct CrdD00); + + +#ifdef __cplusplus +} +#endif + +#endif /* crd.h */ + + diff --git a/src/cpp/3rdparty/slr/fcul_a.cpp b/src/cpp/3rdparty/slr/fcul_a.cpp new file mode 100644 index 000000000..7d9972be0 --- /dev/null +++ b/src/cpp/3rdparty/slr/fcul_a.cpp @@ -0,0 +1,71 @@ +// From https://github.com/xanthospap/iers2010 +#include "iers2010.hpp" + +/// @details This function computes the global total FCULa mapping function +/// (Mendes et al. 2002). It is dependent on latitude, height, and +/// surface temperature. +/// This function is a translation/wrapper for the fortran FCUL_A +/// subroutine, found here : +/// http://maia.usno.navy.mil/conv2010/software.html +/// +/// @param[in] dlat Latitude given in degrees (North Latitude) +/// @param[in] dhgt Height given in meters (mean sea level) +/// @param[in] t Surface temperature given in Kelvin +/// @param[in] elev Elevation angle in degrees +/// @return Mapping function to scale total delay (Note 1) +/// +/// @note +/// -# These coefficients are based on a LS adjustment of 87766 (cleaned) +/// set of traces, based on Ciddor routines to compute refractivity, +/// according to IUGG recommendations (1999). +/// -# Status: Class 1 model +/// +/// @version 13.08.2009 +/// +/// @cite iers2010 +/// Mendes, V.B., G. Prates, E.C. Pavlis, D.E. Pavlis, +/// and R.B. Langley (2002). "Improved mapping functions for +/// atmospheric refraction correction in SLR", Geophysical +/// Res. Lett., 29(10), 1414, doi:10.1029/2001GL014394, 2002 +double iers2010::fcul_a(double dlat, double dhgt, double t, + double elev) noexcept { +#ifdef USE_EXTERNAL_CONSTS + constexpr double PI(DPI); +#else + constexpr double PI(3.14159265358979323846e0); +#endif + + // Convert elevation angle to radians + const double epsilon{elev * (PI / 180e0)}; + const double sine{std::sin(epsilon)}; + // Convert temperature to Celsius + const double t_c{t - 273.15e0}; + const double cosphi{std::cos(dlat * (PI / 180e0))}; + + // Define coefficients used in the model + constexpr double a10{0.121008e-02}; + constexpr double a11{0.17295e-05}; + constexpr double a12{0.3191e-04}; + constexpr double a13{-0.18478e-07}; + + constexpr double a20{0.304965e-02}; + constexpr double a21{0.2346e-05}; + constexpr double a22{-0.1035e-03}; + constexpr double a23{-0.1856e-07}; + + constexpr double a30{0.68777e-01}; + constexpr double a31{0.1972e-04}; + constexpr double a32{-0.3458e-02}; + constexpr double a33{0.1060e-06}; + + // a, b, and c in Marini continued fraction (Eq. 5) + double a1{a10 + a11 * t_c + a12 * cosphi + a13 * dhgt}; + double a2{a20 + a21 * t_c + a22 * cosphi + a23 * dhgt}; + double a3{a30 + a31 * t_c + a32 * cosphi + a33 * dhgt}; + + // numerator in continued fraction + double map_zen{(1e0 + a1 / (1e0 + a2 / (1e0 + a3)))}; + + // result + return map_zen / (sine + a1 / (sine + a2 / (sine + a3))); +} diff --git a/src/cpp/3rdparty/slr/fcul_zd_hpa.cpp b/src/cpp/3rdparty/slr/fcul_zd_hpa.cpp new file mode 100644 index 000000000..16289c41a --- /dev/null +++ b/src/cpp/3rdparty/slr/fcul_zd_hpa.cpp @@ -0,0 +1,104 @@ +// From https://github.com/xanthospap/iers2010 +#include "iers2010.hpp" + +/// @details This function determines the total zenith delay following +/// (Mendes and Pavlis, 2004). +/// This function is a translation/wrapper for the fortran FCUL_A +/// subroutine, found here : +/// http://maia.usno.navy.mil/conv2010/software.html +/// +/// @param[in] dlat Geodetic Latitude given in degrees (North Latitude) +/// @param[in] dhgt Height above ellipsoid given in meters +/// @param[in] pres Surface pressure given in hPa (mbars) (Note 1) +/// @param[in] wvp Water vapor pressure in hPa (mbars) (Note 1) +/// @param[in] lambda Laser wavelength (micrometers) +/// @param[out] f_ztd Zenith total delay in meters +/// @param[out] f_zhd Zenith hydrostatic delay in meters +/// @param[out] f_zwd Zenith non-hydrostatic delay in meters +/// @return An integer, always zero +/// +/// @note +/// -# The surface pressure provided was converted from inches Hg. +/// The water vapor pressure was calculated from the surface +/// temperature (Celsius) and Relative Humidity (% R.H.) at the station. +/// -# Status: Class 1 model +/// +/// @verbatim +/// given input: LATITUDE = 30.67166667D0 degrees (McDonald Observatory) +/// ELLIP_HT = 2010.344D0 meters +/// PRESSURE = 798.4188D0 hPa (August 14, 2009) +/// WVP = 14.322D0 hPa (August 14, 2009) +/// LAMBDA_UM = 0.532D0 micrometers (See Mendes et al.) +/// expected output: FCUL_ZTD = 1.935225924846803114D0 m +/// FCUL_ZHD = 1.932992176591644462D0 m +/// FCUL_ZWD = 0.2233748255158703871D-02 m +/// @endverbatim +/// +/// @version 14.08.2009 +/// +/// @cite iers2010 +/// Mendes, V.B. and E.C. Pavlis, 2004, +/// "High-accuracy zenith delay prediction at optical wavelengths," +/// Geophysical Res. Lett., 31, L14602, doi:10.1029/2004GL020308, 2004 +int iers2010::fcul_zd_hpa(double dlat, double dhgt, double pres, double wvp, + double lambda, double &f_ztd, double &f_zhd, + double &f_zwd) noexcept { +#ifdef USE_EXTERNAL_CONSTS + constexpr double PI(DPI); + // constexpr double C (DC); +#else + constexpr double PI(3.14159265358979323846e0); + // speed of light in vacuum (m/s) + // constexpr double C (2.99792458e8); +#endif + + // CO2 content in ppm + constexpr double xc(375e0); + // constant values to be used in Equation (20) + // k1 and k3 are k1* and k3* + constexpr double k0(238.0185e0); + constexpr double k1(19990.975e0); + constexpr double k2(57.362e0); + constexpr double k3(579.55174e0); + + // constant values to be used in Equation (32) + constexpr double w0(295.235e0); + constexpr double w1(2.6422e0); + constexpr double w2(-0.032380e0); + constexpr double w3(0.004028e0); + + // Wave number + const double sigma(1e0 / lambda); + + // correction factor - Equation (24) + const double f(1e0 - 0.00266e0 * cos(2e0 * PI / 180e0 * dlat) - + 0.00028e-3 * dhgt); + + // correction for CO2 content + const double corr(1e0 + 0.534e-6 * (xc - 450e0)); + + // dispersion equation for the hydrostatic component - Equation (20) + const double sigma2(sigma * sigma); + const double fh(0.01e0 * corr * + ((k1 * (k0 + sigma2)) / (pow((k0 - sigma2), 2)) + + k3 * (k2 + sigma2) / (pow((k2 - sigma2), 2)))); + + // computation of the hydrostatic component - Equation (26) + // caution: pressure in hectoPascal units + f_zhd = 2.416579e-3 * fh * pres / f; + + // dispersion equation for the non-hydrostatic component - Equation (32) + const double fnh(0.003101e0 * + (w0 + 3e0 * w1 * sigma2 + 5e0 * w2 * (sigma2 * sigma2) + + 7e0 * w3 * pow(sigma, 6))); + + // computation of the non-hydrostatic component - Equation (38) + // caution: pressure in hectoPascal units + f_zwd = 1.e-4 * (5.316e0 * fnh - 3.759e0 * fh) * wvp / f; + + // compute the zenith total delay + f_ztd = f_zhd + f_zwd; + + // return + return 0; +} diff --git a/src/cpp/3rdparty/slr/read_crd.c b/src/cpp/3rdparty/slr/read_crd.c new file mode 100644 index 000000000..c462bb4c0 --- /dev/null +++ b/src/cpp/3rdparty/slr/read_crd.c @@ -0,0 +1,1000 @@ +#include +#include +#include +#include +#include "crd.h" + +/*------------------------------------------------------------------------- +* Subroutines: read CRD data records from an input string. +* +* Author: Randall Ricklefs / Univ of Texas / Center for Space Research +* +* History: +* July 06, 2007 - Initial version +* June 24, 2008 - v1.00 +* July 02, 2019 - v2.00 plus NA. rlr. +* Sept 09, 2020 - v2.01 - Fixed string copy length in header records and +* returns from readi, readd, and readld, and +* writing a substitute strcasecpy. +* Thanks to Mark Yeo, Industrial Sciences Group, for catching +* these errors! rlr. +* Dec 15, 2020 - V2.01b - Removed the test for "na" for the detail type +* in the C3 and C6 records. "NA" should never be allowed for +* detail type. rlr. +* +**-----------------------------------------------------------------------*/ + +char stro[256]; +static int format_version; +void remove_blanks (char *, int); +int tokenize (char *, char *, int, int, char *); +int readi (char *, int *); +int readd (char *, double *); +int readld (char *, long double *); +int isna (char *); + +/* Ranging data header/footer records */ +/* H1 - format header */ +int +read_h1 (char * str, struct CrdH1 *header) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +strncpy (header->crd_literal, &tokens[i*ncols], 3); // fixed 09/09/2020 +header->crd_literal[3]= '\0'; i++; +if (readi (&tokens[i*ncols], &header->format_version) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->prod_year) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->prod_mon) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->prod_day) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->prod_hour) < 0) nstat--; + + +// make sure later records know the format version +// version 0 was for beta-version data. +if (header->format_version == 0) header->format_version= 1; +format_version= header->format_version; + +return (nstat+1); +} + +/* H2 - station header */ +int +read_h2 (char * str, struct CrdH2 *header) +{ +int nstat; + + +if (format_version == 1) + { + nstat= sscanf (&str[14], + "%d %d %d %d", + &header->cdp_pad_id, &header->cdp_sys_num, &header->cdp_occ_num, + &header->stn_timescale); + + strncpy (header->stn_name, &str[3], 10); /* to preserve spaces */ + header->stn_name[10]= '\0'; + remove_blanks (header->stn_name, strlen (header->stn_name)); + nstat+= 2; + } +else if (format_version == 2) + { + int nrows= 100, ncols= 256; + int i= 1; // =1 to skip the record id. + char tokens[100*256]; + + nstat= tokenize (str, " \n", 100, 256, tokens); + + strncpy (header->stn_name, &tokens[i*ncols], 10); // fixed 09/09/2020 + header->stn_name[10]= '\0'; i++; + if (readi (&tokens[i*ncols], &header->cdp_pad_id) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->cdp_sys_num) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->cdp_occ_num) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->stn_timescale) < 0) nstat--; i++; + strncpy (header->stn_network, &tokens[i*ncols], 10); // fixed 09/09/2020 + header->stn_network[10]= '\0'; + + } + +return (nstat); +} + +/* H3 - spacecraft header */ +int +read_h3 (char * str, struct CrdH3 *header) +{ +int nstat; + +if (format_version == 1) + { + nstat= sscanf (&str[14], + "%d %d %d %d %d", + &header->ilrs_id, &header->sic, + &header->norad, &header->SC_timescale, + &header->target_type); + + strncpy (header->target_name, &str[3], 10); /* to preserve spaces */ + header->target_name[10]= '\0'; + remove_blanks (header->target_name, strlen (header->target_name)); + + // Convert to v2 target class and location + // incomplete: Could include LRO, ELT, etc. + header->target_class= header->target_type; + header->target_loc= 1; + if (header->target_type == 2) // old lunar reflector entry + { + header->target_class= 1; + header->target_loc= 3; + } + nstat+= 2; + } +else if (format_version == 2) + { + int nrows= 100, ncols= 256; + int i= 1; // =1 to skip the record id. + char tokens[100*256]; + + nstat= tokenize (str, " \n", 100, 256, tokens); + + strncpy (header->target_name, &tokens[i*ncols], 10); // fixed 09/09/2020 + header->target_name[10]= '\0'; i++; + if (readi (&tokens[i*ncols], &header->ilrs_id) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->sic) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->norad) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->SC_timescale) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->target_class) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &header->target_loc) < 0) nstat--; + + // Convert to v1 target type + header->target_type= header->target_class; + if (header->target_class == 1 && header->target_loc == 3) + { + header->target_type= 2; + } + nstat++; + } +return (nstat); +} + +/* H4 - Session header */ +int +read_h4 (char * str, struct CrdH4 *header) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &header->data_type) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->start_year) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->start_mon) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->start_day) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->start_hour) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->start_min) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->start_sec) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->end_year) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->end_mon) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->end_day) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->end_hour) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->end_min) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->end_sec) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->data_release) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->refraction_app_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->CofM_app_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->xcv_amp_app_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->stn_sysdelay_app_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->SC_sysdelay_app_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->range_type_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->data_qual_alert_ind) < 0) nstat--; + +return (nstat+1); +} + +/* H5 - Prediction header */ +// New in v2. +int +read_h5 (char * str, struct CrdH5 *header) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &header->prediction_type) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &header->year_of_century) < 0) nstat--; i++; +strncpy (header->date_and_time, &tokens[i*ncols], 12); // fixed 09/09/2020 +header->date_and_time[12]= '\0'; i++; +strncpy (header->prediction_provider, &tokens[i*ncols], 10); // fixed 09/09/2020 +header->prediction_provider[10]= '\0'; i++; +if (readi (&tokens[i*ncols], &header->sequence_number) < 0) nstat--; + + +return (nstat+1); +} + +/* Need indicators that these have been read? */ +/* H8 - End of Session footer */ +int +read_h8 (char * str) +{ +sscanf (str, "H8"); +} + +/* H9 - End of File footer */ +int +read_h9 (char * str) +{ +sscanf (str, "H9"); +} + +/* Ranging data configuration records (1 of n) */ + /* C0 - System Configuration Record */ +int +read_c0 (char * str, struct CrdC0 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +int ii; +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->xmit_wavelength) < 0) nstat--; i++; + +// Zero-initialise config_ids - added 09/09/2020 +// 10 -> from "char config_ids[10][41];" in crd.h +for (int j = 0; j < 10; j++) { + config->config_ids[j][0] = '\0'; +} + +// Write only those config_ids that exist, hence nstat below +for (ii=i; iiconfig_ids[ii-i], &tokens[ii*ncols], 40); + config->config_ids[ii-i][40]= '\0'; + } + + +return (nstat+1); +} + + /* C1 - Laser Configuration Record */ +int +read_c1 (char * str, struct CrdC1 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +strncpy (config->laser_config_id, &tokens[i*ncols], 40); +config->laser_config_id[40]= '\0'; i++; +strncpy (config->laser_type, &tokens[i*ncols], 40); +config->laser_type[40]= '\0'; i++; +if (readd (&tokens[i*ncols], &config->prim_wavelength) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->nom_fire_rate) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->pulse_energy) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->pulse_width) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->beam_div) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &config->pulses_in_semitrain)< 0) nstat--; + + +return (nstat+1); +} + + /* C2 - Detector Configuration Record */ +int +read_c2 (char * str, struct CrdC2 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +strncpy (config->detector_config_id, &tokens[i*ncols], 40); +config->detector_config_id[40]= '\0'; i++; +strncpy (config->detector_type, &tokens[i*ncols], 40); +config->detector_type[40]= '\0'; i++; +if (readd (&tokens[i*ncols], &config->app_wavelength) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->qe) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->voltage) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->dark_count) < 0) nstat--; i++; +strncpy (config->output_pulse_type, &tokens[i*ncols], 40); +config->output_pulse_type[40]= '\0'; i++; +if (readd (&tokens[i*ncols], &config->output_pulse_width) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->spectral_filter) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->spectral_filter_xmission) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->spatial_filter) < 0) nstat--; i++; +strncpy (config->signal_proc, &tokens[i*ncols], 40); +config->signal_proc[40]= '\0'; + +if (format_version == 2) + { + i++; + if (readd (&tokens[i*ncols], &config->amp_gain) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &config->amp_bandwidth) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &config->amp_in_use) < 0) nstat--; + } + + +return (nstat+1); +} + + /* C3 - Timing Configuration Record */ +int +read_c3 (char * str, struct CrdC3 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +strncpy (config->timing_config_id, &tokens[i*ncols], 40); config->timing_config_id[40]= '\0'; i++; +strncpy (config->time_source, &tokens[i*ncols], 40); config->time_source [40]= '\0'; i++; +strncpy (config->freq_source, &tokens[i*ncols], 40); config->freq_source [40]= '\0'; i++; +strncpy (config->timer, &tokens[i*ncols], 40); config->timer [40]= '\0'; i++; +strncpy (config->timer_serial_num, &tokens[i*ncols], 40); config->timer_serial_num[40]= '\0'; i++; + +if (readd (&tokens[i*ncols], &config->epoch_delay_corr) < 0) nstat--; + +return (nstat+1); +} + + /* C4 - Transponder Configuration Record */ +int +read_c4 (char * str, struct CrdC4 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +strncpy (config->xponder_config_id, &tokens[i*ncols], 40); +config->xponder_config_id[40]= '\0'; i++; +if (readld(&tokens[i*ncols], &config->est_stn_utc_offset) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->est_stn_osc_drift) < 0) nstat--; i++; +if (readld(&tokens[i*ncols], &config->est_xponder_utc_offset) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->est_xponder_osc_drift) < 0) nstat--; i++; +if (readld(&tokens[i*ncols], &config->xponder_clock_ref_time) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &config->stn_off_drift_app_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &config->SC_off_drift_app_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &config->SC_time_simplified_ind) < 0) nstat--; + +return (nstat+1); +} + + /* C5 - Software Configuration Record */ + // new in v2. +int +read_c5 (char * str, struct CrdC5 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +strncpy (config->software_config_id, &tokens[i*ncols], 40); config->software_config_id [40]= '\0'; i++; +strncpy (config->tracking_software, &tokens[i*ncols], 40); config->tracking_software [40]= '\0'; i++; +strncpy (config->tracking_software_versions, &tokens[i*ncols], 40); config->tracking_software_versions [40]= '\0'; i++; +strncpy (config->processing_software, &tokens[i*ncols], 40); config->processing_software [40]= '\0'; i++; +strncpy (config->processing_software_versions, &tokens[i*ncols], 40); config->processing_software_versions [40]= '\0'; + +return (nstat+1); +} + + /* C6 - Meteorology Configuration Record */ + // new in v2. +int +read_c6 (char * str, struct CrdC6 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +strncpy (config->met_config_id, &tokens[i*ncols], 40); config->met_config_id [40]= '\0'; i++; +strncpy (config->pressure_sensor_manufacturer, &tokens[i*ncols], 40); config->pressure_sensor_manufacturer [40]= '\0'; i++; +strncpy (config->pressure_sensor_model, &tokens[i*ncols], 40); config->pressure_sensor_model [40]= '\0'; i++; +strncpy (config->pressure_sensor_serial_num, &tokens[i*ncols], 40); config->pressure_sensor_serial_num [40]= '\0'; i++; +strncpy (config->temperature_sensor_manufacturer, &tokens[i*ncols], 40); config->temperature_sensor_manufacturer [40]= '\0'; i++; +strncpy (config->temperature_sensor_model, &tokens[i*ncols], 40); config->temperature_sensor_model [40]= '\0'; i++; +strncpy (config->temperature_sensor_serial_num, &tokens[i*ncols], 40); config->temperature_sensor_serial_num [40]= '\0'; i++; +strncpy (config->humidity_sensor_manufacturer, &tokens[i*ncols], 40); config->humidity_sensor_manufacturer [40]= '\0'; i++; +strncpy (config->humidity_sensor_model, &tokens[i*ncols], 40); config->humidity_sensor_model [40]= '\0'; i++; +strncpy (config->humidity_sensor_serial_num, &tokens[i*ncols], 40); config->humidity_sensor_serial_num [40]= '\0'; + +return (nstat+1); +} + + /* C7 - Meteorology Configuration Record */ + // new in v2. +int +read_c7 (char * str, struct CrdC7 *config) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readi (&tokens[i*ncols], &config->detail_type) < 0) nstat--; i++; +strncpy (config->calconfig_id, &tokens[i*ncols], 40); +config->calconfig_id[40]= '\0'; i++; +strncpy (config->target_name, &tokens[i*ncols], 40); +config->target_name[40]= '\0'; i++; +if (readd (&tokens[i*ncols], &config->surveyed_target_dist) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->survey_error) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->other_fixed_delays) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &config->pulse_energy) < 0) nstat--; i++; +strncpy (config->processing_software, &tokens[i*ncols], 40); +config->processing_software[40]= '\0'; i++; +strncpy (config->processing_software_version, &tokens[i*ncols], 40); +config->processing_software_version[40]= '\0'; + +return (nstat+1); +} + +/* Ranging data records */ +/* Secofday: need int sec and int psec? */ + /* 10 - Range Record */ +int +read_10 (char * str, struct CrdD10 *data_recd) +{ +int nstat; + +if (format_version == 1) + { + char temp_sysconfig_id[256]; + nstat= sscanf (str, + "%*s %Lf %Lf %255s %d %d %d %d %d", + &data_recd->sec_of_day, &data_recd->time_of_flight, + temp_sysconfig_id, &data_recd->epoch_event, + &data_recd->filter_flag, &data_recd->detector_channel, + &data_recd->stop_number, &data_recd->xcv_amp); + strncpy (data_recd->sysconfig_id, temp_sysconfig_id, 40); + data_recd->sysconfig_id[40]= '\0'; + } +else if (format_version == 2) + { + int nrows= 100, ncols= 256; + int i= 1; // =1 to skip the record id. + char tokens[100*256]; + nstat= tokenize (str, " \n", 100, 256, tokens); + + if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; + if (readld(&tokens[i*ncols], &data_recd->time_of_flight) < 0) nstat--; i++; + strncpy (data_recd->sysconfig_id, &tokens[i*ncols], 40); + data_recd->sysconfig_id[40]= '\0'; i++; + if (readi (&tokens[i*ncols], &data_recd->epoch_event) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->filter_flag) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->detector_channel) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->stop_number) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->xcv_amp) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->xmt_amp) < 0) nstat--; + } + +return (nstat+1); +} + + /* 11 - Normal Point Record */ +int +read_11 (char * str, struct CrdD11 *data_recd) +{ +char temp_sysconfig_id[256]; +int nstat; + +if (format_version == 1) + { + nstat= sscanf (str, + "%*s %Lf %Lf %255s %d %lf %d %lf %lf %lf %lf %lf %d", + &data_recd->sec_of_day, &data_recd->time_of_flight, + temp_sysconfig_id, &data_recd->epoch_event, + &data_recd->np_window_length, &data_recd->num_ranges, + &data_recd->bin_rms, &data_recd->bin_skew, &data_recd->bin_kurtosis, + &data_recd->bin_PmM, &data_recd->return_rate, + &data_recd->detector_channel); + strncpy (data_recd->sysconfig_id, temp_sysconfig_id, 40); + data_recd->sysconfig_id[40]= '\0'; + } +else if (format_version == 2) + { + int nrows= 100, ncols= 256; + int i= 1; // =1 to skip the record id. + char tokens[100*256]; + nstat= tokenize (str, " \n", 100, 256, tokens); + + if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; + if (readld(&tokens[i*ncols], &data_recd->time_of_flight) < 0) nstat--; i++; + strncpy (data_recd->sysconfig_id, &tokens[i*ncols], 40); + data_recd->sysconfig_id[40]= '\0'; i++; + if (readi (&tokens[i*ncols], &data_recd->epoch_event) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->np_window_length) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->num_ranges) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->bin_rms) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->bin_skew) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->bin_kurtosis) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->bin_PmM) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->return_rate) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->detector_channel) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->signal_to_noise) < 0) nstat--; + } + +return (nstat+1); +} + + /* 12 - Range Supplement Record */ +int +read_12 (char * str, struct CrdD12 *data_recd) +{ +char temp_sysconfig_id[256]; +int nstat; + +if (format_version == 1) + { + nstat= sscanf (str, + "%*s %Lf %255s %lf %lf %lf %lf", + &data_recd->sec_of_day, temp_sysconfig_id, + &data_recd->refraction_corr, &data_recd->target_CofM_corr, + &data_recd->nd_value, &data_recd->time_bias); + strncpy (data_recd->sysconfig_id, temp_sysconfig_id, 40); + data_recd->sysconfig_id[40]= '\0'; + } +else if (format_version == 2) + { + int nrows= 100, ncols= 256; + int i= 1; // =1 to skip the record id. + char tokens[100*256]; + + nstat= tokenize (str, " \n", 100, 256, tokens); + if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; + + strncpy (data_recd->sysconfig_id, &tokens[i*ncols], 40); + data_recd->sysconfig_id[40]= '\0'; i++; + + if (readd (&tokens[i*ncols], &data_recd->refraction_corr) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->target_CofM_corr) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->nd_value) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->time_bias) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->range_rate) < 0) nstat--; + } + +return (nstat+1); +} + + /* 20 - Meteorological Record */ +int +read_20 (char * str, struct CrdD20 *data_recd) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); +if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->pressure) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->temperature) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->humidity) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->value_origin) < 0) nstat--; i++; + +return (nstat+1); +} + + /* 21 - Meteorological Supplement Record */ +int +read_21 (char * str, struct CrdD21 *data_recd) +{ +char temp_precip_type[256]; +char temp_weather_conditions[256]; +int nstat; + +if (format_version == 1) + { + nstat= sscanf (str, + "%*s %Lf %lf %lf %255s %d %lf %d %d", + &data_recd->sec_of_day, &data_recd->wind_speed, + &data_recd->wind_direction, temp_precip_type, + &data_recd->visibility, &data_recd->sky_clarity, + &data_recd->atmospheric_seeing, &data_recd->cloud_cover); + strncpy (data_recd->weather_conditions, temp_precip_type, 40); + data_recd->weather_conditions[40]= '\0'; + } +else if (format_version == 2) + { + int nrows= 100, ncols= 256; + int i= 1; // =1 to skip the record id. + char tokens[100*256]; + + nstat= tokenize (str, " \n", 100, 256, tokens); + + if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->wind_speed) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->wind_direction) < 0) nstat--; i++; + + strncpy (data_recd->weather_conditions, &tokens[i*ncols], 40); + data_recd->weather_conditions[40]= '\0'; i++; + + if (readi (&tokens[i*ncols], &data_recd->visibility) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->sky_clarity) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->atmospheric_seeing) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->cloud_cover) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->sky_temperature) < 0) nstat--; + } + +return (nstat+1); +} + + /* 30 - Pointing Angles Record */ +int +read_30 (char * str, struct CrdD30 *data_recd) +{ +int nstat; + +if (format_version == 1) + { + nstat= sscanf (str, + "%*s %Lf %lf %lf %d %d %d", + &data_recd->sec_of_day, &data_recd->azimuth, &data_recd->elevation, + &data_recd->direction_ind, &data_recd->angle_origin_ind, + &data_recd->refraction_corr_ind); + } +else if (format_version == 2) + { + int nrows= 100, ncols= 256; + int i= 1; // =1 to skip the record id. + char tokens[100*256]; + + nstat= tokenize (str, " \n", 100, 256, tokens); + + if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->azimuth) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->elevation) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->direction_ind) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->angle_origin_ind) < 0) nstat--; i++; + if (readi (&tokens[i*ncols], &data_recd->refraction_corr_ind) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->azimuth_rate) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->elevation_rate) < 0) nstat--; +} + +return (nstat+1); +} + + /* 40 - Calibration Record */ +int +read_40 (char * str, struct CrdD40 *data_recd) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->type_of_data) < 0) nstat--; i++; + +strncpy (data_recd->sysconfig_id, &tokens[i*ncols], 40); +data_recd->sysconfig_id[40]= '\0'; i++; + +if (readi (&tokens[i*ncols], &data_recd->num_points_recorded) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->num_points_used) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->one_way_target_dist) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_sys_delay) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_delay_shift) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_rms) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_skew) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_kurtosis) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_PmM) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->cal_type_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->cal_shift_type_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->detector_channel) < 0) nstat--; +if (format_version == 2) + { + i++; + if (readi (&tokens[i*ncols], &data_recd->cal_span) < 0) nstat--; i++; + if (readd (&tokens[i*ncols], &data_recd->cal_return_rate) < 0) nstat--; + } + + +return (nstat+1); +} + + /* 41 - Calibration Detail Record */ +int +read_41 (char * str, struct CrdD40 *data_recd) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->type_of_data) < 0) nstat--; i++; +strncpy (data_recd->sysconfig_id, &tokens[i*ncols], 40); +data_recd->sysconfig_id[40]= '\0'; i++; +if (readi (&tokens[i*ncols], &data_recd->num_points_recorded) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->num_points_used) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->one_way_target_dist) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_sys_delay) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_delay_shift) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_rms) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_skew) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_kurtosis) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_PmM) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->cal_type_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->cal_shift_type_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->detector_channel) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->cal_span) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->cal_return_rate) < 0) nstat--; + +return (nstat+1); +} + + /* 42 - Calibration "Shot" Record */ +int +read_42 (char * str, struct CrdD42 *data_recd) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +if (readld(&tokens[i*ncols], &data_recd->sec_of_day) < 0) nstat--; i++; +if (readld(&tokens[i*ncols], &data_recd->time_of_flight) < 0) nstat--; i++; +strncpy (data_recd->sysconfig_id, &tokens[i*ncols], 40); +data_recd->sysconfig_id[40]= '\0'; i++; +strncpy (data_recd->calconfig_id, &tokens[i*ncols], 40); +data_recd->calconfig_id[40]= '\0'; i++; +if (readd (&tokens[i*ncols], &data_recd->other_variable_delays) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->type_of_data) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->cal_type_ind) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->filter_flag) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->detector_channel) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->stop_number) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->cal_span) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->xcv_amp) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->xmt_amp) < 0) nstat--; + +return (nstat+1); +} + + /* 50 - Session Statistics Record */ +int +read_50 (char * str, struct CrdD50 *data_recd) +{ +int nstat; +int nrows= 100, ncols= 256; +int i= 1; // =1 to skip the record id. +char tokens[100*256]; + +nstat= tokenize (str, " \n", 100, 256, tokens); + +strncpy (data_recd->sysconfig_id, &tokens[i*ncols], 40); +data_recd->sysconfig_id[40]= '\0'; i++; +if (readd (&tokens[i*ncols], &data_recd->sess_rms) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->sess_skew) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->sess_kurtosis) < 0) nstat--; i++; +if (readd (&tokens[i*ncols], &data_recd->sess_PmM) < 0) nstat--; i++; +if (readi (&tokens[i*ncols], &data_recd->data_qual_ind) < 0) nstat--; + +return (nstat+1); +} + + /* 60 - Compatibility Record */ +int +read_60 (char * str, struct CrdD60 *data_recd) +{ +char temp_sysconfig_id[256]; +int nstat; + +nstat= sscanf (str, + "%*s %255s %d %d", + temp_sysconfig_id, &data_recd->sys_change_ind, + &data_recd->sys_config_ind); + +strncpy (data_recd->sysconfig_id, temp_sysconfig_id, 40); +data_recd->sysconfig_id[40]= '\0'; + +return (nstat+1); +} + + /* 9X - User Defined Records 90-99 */ +int +read_9x (char * str, struct CrdD9x *data_recd) +{ +int nstat= 0; +return (nstat); +} + + /* 00 - Comment Record */ +int +read_00 (char * str, struct CrdD00 *data_recd) +{ +int i; +int nstat= 1; + +// search for and remove '\n' (and '\r' for MS Windows) +strncpy(data_recd->comment, &str[3], 80); +data_recd->comment[80]= '\0'; +for (i=0; i<80; i++) + { + if (data_recd->comment[i] == '\n' || + data_recd->comment[i] == '\r') + data_recd->comment[i]= '\0'; + } +return (nstat); +} + +void +remove_blanks (char *str, int slen) +{ +int i, j, k; + +// Do we have a string to check? +if (slen == 0) return; + +// Handle left- and right-justified fields. +// Assumes no blanks mid-field. +if (isalnum(str[0])) + { + // left-justified + for (i=slen-1; i>0; i--) + { + if (str[i] == ' ') str[i]= '\0'; + } + } +else + { + // right-justified + for (i=0; i= 0; i--) { - - /* Argument and functions. */ - arg = fmod((double)xls[i].nl * el + - (double)xls[i].nlp * elp + - (double)xls[i].nf * f + - (double)xls[i].nd * d + - (double)xls[i].nom * om, D2PI); - sarg = sin(arg); - carg = cos(arg); - - /* Term. */ - dp += (xls[i].sp + xls[i].spt * t) * sarg + xls[i].cp * carg; - de += (xls[i].ce + xls[i].cet * t) * carg + xls[i].se * sarg; - } - -/* Convert from 0.1 microarcsec units to radians. */ - dpsils = dp * U2R; - depsls = de * U2R; - -/* ------------------ */ -/* PLANETARY NUTATION */ -/* ------------------ */ - -/* n.b. The MHB2000 code computes the luni-solar and planetary nutation */ -/* in different functions, using slightly different Delaunay */ -/* arguments in the two cases. This behaviour is faithfully */ -/* reproduced here. Use of the IERS 2003 expressions for both */ -/* cases leads to negligible changes, well below */ -/* 0.1 microarcsecond. */ - -/* Mean anomaly of the Moon (MHB2000). */ - al = fmod(2.35555598 + 8328.6914269554 * t, D2PI); - -/* Mean longitude of the Moon minus that of the ascending node */ -/*(MHB2000). */ - af = fmod(1.627905234 + 8433.466158131 * t, D2PI); - -/* Mean elongation of the Moon from the Sun (MHB2000). */ - ad = fmod(5.198466741 + 7771.3771468121 * t, D2PI); - -/* Mean longitude of the ascending node of the Moon (MHB2000). */ - aom = fmod(2.18243920 - 33.757045 * t, D2PI); - -/* General accumulated precession in longitude (IERS 2003). */ - apa = iauFapa03(t); - -/* Planetary longitudes, Mercury through Uranus (IERS 2003). */ - alme = iauFame03(t); - alve = iauFave03(t); - alea = iauFae03(t); - alma = iauFama03(t); - alju = iauFaju03(t); - alsa = iauFasa03(t); - alur = iauFaur03(t); - -/* Neptune longitude (MHB2000). */ - alne = fmod(5.321159000 + 3.8127774000 * t, D2PI); - -/* Initialize the nutation values. */ - dp = 0.0; - de = 0.0; - -/* Summation of planetary nutation series (in reverse order). */ - for (i = NPL-1; i >= 0; i--) { - - /* Argument and functions. */ - arg = fmod((double)xpl[i].nl * al + - (double)xpl[i].nf * af + - (double)xpl[i].nd * ad + - (double)xpl[i].nom * aom + - (double)xpl[i].nme * alme + - (double)xpl[i].nve * alve + - (double)xpl[i].nea * alea + - (double)xpl[i].nma * alma + - (double)xpl[i].nju * alju + - (double)xpl[i].nsa * alsa + - (double)xpl[i].nur * alur + - (double)xpl[i].nne * alne + - (double)xpl[i].npa * apa, D2PI); - sarg = sin(arg); - carg = cos(arg); - - /* Term. */ - dp += (double)xpl[i].sp * sarg + (double)xpl[i].cp * carg; - de += (double)xpl[i].se * sarg + (double)xpl[i].ce * carg; - - } - -/* Convert from 0.1 microarcsec units to radians. */ - dpsipl = dp * U2R; - depspl = de * U2R; - -/* ------- */ -/* RESULTS */ -/* ------- */ - -/* Add luni-solar and planetary components. */ - *dpsi = dpsils + dpsipl; - *deps = depsls + depspl; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" -#include "sofam.hpp" - -void iauNut06a(double date1, double date2, double *dpsi, double *deps) -/* -** - - - - - - - - - - -** i a u N u t 0 6 a -** - - - - - - - - - - -** -** IAU 2000A nutation with adjustments to match the IAU 2006 -** precession. -** -** Given: -** date1,date2 double TT as a 2-part Julian Date (Note 1) -** -** Returned: -** dpsi,deps double nutation, luni-solar + planetary (Note 2) -** -** Status: canonical model. -** -** Notes: -** -** 1) The TT date date1+date2 is a Julian Date, apportioned in any -** convenient way between the two arguments. For example, -** JD(TT)=2450123.7 could be expressed in any of these ways, -** among others: -** -** date1 date2 -** -** 2450123.7 0.0 (JD method) -** 2451545.0 -1421.3 (J2000 method) -** 2400000.5 50123.2 (MJD method) -** 2450123.5 0.2 (date & time method) -** -** The JD method is the most natural and convenient to use in -** cases where the loss of several decimal digits of resolution -** is acceptable. The J2000 method is best matched to the way -** the argument is handled internally and will deliver the -** optimum resolution. The MJD method and the date & time methods -** are both good compromises between resolution and convenience. -** -** 2) The nutation components in longitude and obliquity are in radians -** and with respect to the mean equinox and ecliptic of date, -** IAU 2006 precession model (Hilton et al. 2006, Capitaine et al. -** 2005). -** -** 3) The function first computes the IAU 2000A nutation, then applies -** adjustments for (i) the consequences of the change in obliquity -** from the IAU 1980 ecliptic to the IAU 2006 ecliptic and (ii) the -** secular variation in the Earth's dynamical form factor J2. -** -** 4) The present function provides classical nutation, complementing -** the IAU 2000 frame bias and IAU 2006 precession. It delivers a -** pole which is at current epochs accurate to a few tens of -** microarcseconds, apart from the free core nutation. -** -** Called: -** iauNut00a nutation, IAU 2000A -** -** References: -** -** Chapront, J., Chapront-Touze, M. & Francou, G. 2002, -** Astron.Astrophys. 387, 700 -** -** Lieske, J.H., Lederle, T., Fricke, W. & Morando, B. 1977, -** Astron.Astrophys. 58, 1-16 -** -** Mathews, P.M., Herring, T.A., Buffet, B.A. 2002, J.Geophys.Res. -** 107, B4. The MHB_2000 code itself was obtained on 9th September -** 2002 from ftp//maia.usno.navy.mil/conv2000/chapter5/IAU2000A. -** -** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., -** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 -** -** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, -** Astron.Astrophys.Supp.Ser. 135, 111 -** -** Wallace, P.T., "Software for Implementing the IAU 2000 -** Resolutions", in IERS Workshop 5.1 (2002) -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double t, fj2, dp, de; - - -/* Interval between fundamental date J2000.0 and given date (JC). */ - t = ((date1 - DJ00) + date2) / DJC; - -/* Factor correcting for secular variation of J2. */ - fj2 = -2.7774e-6 * t; - -/* Obtain IAU 2000A nutation. */ - iauNut00a(date1, date2, &dp, &de); - -/* Apply P03 adjustments (Wallace & Capitaine, 2006, Eqs.5). */ - *dpsi = dp + dp * (0.4697e-6 + fj2); - *deps = de + de * fj2; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" -#include "sofam.hpp" - -double iauObl06(double date1, double date2) -/* -** - - - - - - - - - -** i a u O b l 0 6 -** - - - - - - - - - -** -** Mean obliquity of the ecliptic, IAU 2006 precession model. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: canonical model. -** -** Given: -** date1,date2 double TT as a 2-part Julian Date (Note 1) -** -** Returned (function value): -** double obliquity of the ecliptic (radians, Note 2) -** -** Notes: -** -** 1) The TT date date1+date2 is a Julian Date, apportioned in any -** convenient way between the two arguments. For example, -** JD(TT)=2450123.7 could be expressed in any of these ways, -** among others: -** -** date1 date2 -** -** 2450123.7 0.0 (JD method) -** 2451545.0 -1421.3 (J2000 method) -** 2400000.5 50123.2 (MJD method) -** 2450123.5 0.2 (date & time method) -** -** The JD method is the most natural and convenient to use in -** cases where the loss of several decimal digits of resolution -** is acceptable. The J2000 method is best matched to the way -** the argument is handled internally and will deliver the -** optimum resolution. The MJD method and the date & time methods -** are both good compromises between resolution and convenience. -** -** 2) The result is the angle between the ecliptic and mean equator of -** date date1+date2. -** -** Reference: -** -** Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351 -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double t, eps0; - - -/* Interval between fundamental date J2000.0 and given date (JC). */ - t = ((date1 - DJ00) + date2) / DJC; - -/* Mean obliquity. */ - eps0 = (84381.406 + - (-46.836769 + - ( -0.0001831 + - ( 0.00200340 + - ( -0.000000576 + - ( -0.0000000434) * t) * t) * t) * t) * t) * DAS2R; - - return eps0; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" -#include "sofam.hpp" - -void iauPfw06(double date1, double date2, - double *gamb, double *phib, double *psib, double *epsa) -/* -** - - - - - - - - - -** i a u P f w 0 6 -** - - - - - - - - - -** -** Precession angles, IAU 2006 (Fukushima-Williams 4-angle formulation). -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: canonical model. -** -** Given: -** date1,date2 double TT as a 2-part Julian Date (Note 1) -** -** Returned: -** gamb double F-W angle gamma_bar (radians) -** phib double F-W angle phi_bar (radians) -** psib double F-W angle psi_bar (radians) -** epsa double F-W angle epsilon_A (radians) -** -** Notes: -** -** 1) The TT date date1+date2 is a Julian Date, apportioned in any -** convenient way between the two arguments. For example, -** JD(TT)=2450123.7 could be expressed in any of these ways, -** among others: -** -** date1 date2 -** -** 2450123.7 0.0 (JD method) -** 2451545.0 -1421.3 (J2000 method) -** 2400000.5 50123.2 (MJD method) -** 2450123.5 0.2 (date & time method) -** -** The JD method is the most natural and convenient to use in -** cases where the loss of several decimal digits of resolution -** is acceptable. The J2000 method is best matched to the way -** the argument is handled internally and will deliver the -** optimum resolution. The MJD method and the date & time methods -** are both good compromises between resolution and convenience. -** -** 2) Naming the following points: -** -** e = J2000.0 ecliptic pole, -** p = GCRS pole, -** E = mean ecliptic pole of date, -** and P = mean pole of date, -** -** the four Fukushima-Williams angles are as follows: -** -** gamb = gamma_bar = epE -** phib = phi_bar = pE -** psib = psi_bar = pEP -** epsa = epsilon_A = EP -** -** 3) The matrix representing the combined effects of frame bias and -** precession is: -** -** PxB = R_1(-epsa).R_3(-psib).R_1(phib).R_3(gamb) -** -** 4) The matrix representing the combined effects of frame bias, -** precession and nutation is simply: -** -** NxPxB = R_1(-epsa-dE).R_3(-psib-dP).R_1(phib).R_3(gamb) -** -** where dP and dE are the nutation components with respect to the -** ecliptic of date. -** -** Reference: -** -** Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351 -** -** Called: -** iauObl06 mean obliquity, IAU 2006 -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double t; - - -/* Interval between fundamental date J2000.0 and given date (JC). */ - t = ((date1 - DJ00) + date2) / DJC; - -/* P03 bias+precession angles. */ - *gamb = ( -0.052928 + - ( 10.556378 + - ( 0.4932044 + - ( -0.00031238 + - ( -0.000002788 + - ( 0.0000000260 ) - * t) * t) * t) * t) * t) * DAS2R; - *phib = ( 84381.412819 + - ( -46.811016 + - ( 0.0511268 + - ( 0.00053289 + - ( -0.000000440 + - ( -0.0000000176 ) - * t) * t) * t) * t) * t) * DAS2R; - *psib = ( -0.041775 + - ( 5038.481484 + - ( 1.5584175 + - ( -0.00018522 + - ( -0.000026452 + - ( -0.0000000148 ) - * t) * t) * t) * t) * t) * DAS2R; - *epsa = iauObl06(date1, date2); - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" - -void iauPnm06a(double date1, double date2, double rbpn[3][3]) -/* -** - - - - - - - - - - -** i a u P n m 0 6 a -** - - - - - - - - - - -** -** Form the matrix of precession-nutation for a given date (including -** frame bias), equinox based, IAU 2006 precession and IAU 2000A -** nutation models. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: support function. -** -** Given: -** date1,date2 double TT as a 2-part Julian Date (Note 1) -** -** Returned: -** rbpn double[3][3] bias-precession-nutation matrix (Note 2) -** -** Notes: -** -** 1) The TT date date1+date2 is a Julian Date, apportioned in any -** convenient way between the two arguments. For example, -** JD(TT)=2450123.7 could be expressed in any of these ways, among -** others: -** -** date1 date2 -** -** 2450123.7 0.0 (JD method) -** 2451545.0 -1421.3 (J2000 method) -** 2400000.5 50123.2 (MJD method) -** 2450123.5 0.2 (date & time method) -** -** The JD method is the most natural and convenient to use in -** cases where the loss of several decimal digits of resolution -** is acceptable. The J2000 method is best matched to the way -** the argument is handled internally and will deliver the -** optimum resolution. The MJD method and the date & time methods -** are both good compromises between resolution and convenience. -** -** 2) The matrix operates in the sense V(date) = rbpn * V(GCRS), where -** the p-vector V(date) is with respect to the true equatorial triad -** of date date1+date2 and the p-vector V(GCRS) is with respect to -** the Geocentric Celestial Reference System (IAU, 2000). -** -** Called: -** iauPfw06 bias-precession F-W angles, IAU 2006 -** iauNut06a nutation, IAU 2006/2000A -** iauFw2m F-W angles to r-matrix -** -** Reference: -** -** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855. -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double gamb, phib, psib, epsa, dp, de; - - -/* Fukushima-Williams angles for frame bias and precession. */ - iauPfw06(date1, date2, &gamb, &phib, &psib, &epsa); - -/* Nutation components. */ - iauNut06a(date1, date2, &dp, &de); - -/* Equinox based nutation x precession x bias matrix. */ - iauFw2m(gamb, phib, psib + dp, epsa + de, rbpn); - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" - -void iauPom00(double xp, double yp, double sp, double rpom[3][3]) -/* -** - - - - - - - - - - -** i a u P o m 0 0 -** - - - - - - - - - - -** -** Form the matrix of polar motion for a given date, IAU 2000. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: support function. -** -** Given: -** xp,yp double coordinates of the pole (radians, Note 1) -** sp double the TIO locator s' (radians, Note 2) -** -** Returned: -** rpom double[3][3] polar-motion matrix (Note 3) -** -** Notes: -** -** 1) The arguments xp and yp are the coordinates (in radians) of the -** Celestial Intermediate Pole with respect to the International -** Terrestrial Reference System (see IERS Conventions 2003), -** measured along the meridians 0 and 90 deg west respectively. -** -** 2) The argument sp is the TIO locator s', in radians, which -** positions the Terrestrial Intermediate Origin on the equator. It -** is obtained from polar motion observations by numerical -** integration, and so is in essence unpredictable. However, it is -** dominated by a secular drift of about 47 microarcseconds per -** century, and so can be taken into account by using s' = -47*t, -** where t is centuries since J2000.0. The function iauSp00 -** implements this approximation. -** -** 3) The matrix operates in the sense V(TRS) = rpom * V(CIP), meaning -** that it is the final rotation when computing the pointing -** direction to a celestial source. -** -** Called: -** iauIr initialize r-matrix to identity -** iauRz rotate around Z-axis -** iauRy rotate around Y-axis -** iauRx rotate around X-axis -** -** Reference: -** -** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), -** IERS Technical Note No. 32, BKG (2004) -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - -/* Construct the matrix. */ - iauIr(rpom); - iauRz(sp, rpom); - iauRy(-xp, rpom); - iauRx(-yp, rpom); - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" - -void iauRx(double phi, double r[3][3]) -/* -** - - - - - - -** i a u R x -** - - - - - - -** -** Rotate an r-matrix about the x-axis. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: vector/matrix support function. -** -** Given: -** phi double angle (radians) -** -** Given and returned: -** r double[3][3] r-matrix, rotated -** -** Notes: -** -** 1) Calling this function with positive phi incorporates in the -** supplied r-matrix r an additional rotation, about the x-axis, -** anticlockwise as seen looking towards the origin from positive x. -** -** 2) The additional rotation can be represented by this matrix: -** -** ( 1 0 0 ) -** ( ) -** ( 0 + cos(phi) + sin(phi) ) -** ( ) -** ( 0 - sin(phi) + cos(phi) ) -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double s, c, a10, a11, a12, a20, a21, a22; - - - s = sin(phi); - c = cos(phi); - - a10 = c*r[1][0] + s*r[2][0]; - a11 = c*r[1][1] + s*r[2][1]; - a12 = c*r[1][2] + s*r[2][2]; - a20 = - s*r[1][0] + c*r[2][0]; - a21 = - s*r[1][1] + c*r[2][1]; - a22 = - s*r[1][2] + c*r[2][2]; - - r[1][0] = a10; - r[1][1] = a11; - r[1][2] = a12; - r[2][0] = a20; - r[2][1] = a21; - r[2][2] = a22; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" - -void iauRy(double theta, double r[3][3]) -/* -** - - - - - - -** i a u R y -** - - - - - - -** -** Rotate an r-matrix about the y-axis. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: vector/matrix support function. -** -** Given: -** theta double angle (radians) -** -** Given and returned: -** r double[3][3] r-matrix, rotated -** -** Notes: -** -** 1) Calling this function with positive theta incorporates in the -** supplied r-matrix r an additional rotation, about the y-axis, -** anticlockwise as seen looking towards the origin from positive y. -** -** 2) The additional rotation can be represented by this matrix: -** -** ( + cos(theta) 0 - sin(theta) ) -** ( ) -** ( 0 1 0 ) -** ( ) -** ( + sin(theta) 0 + cos(theta) ) -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double s, c, a00, a01, a02, a20, a21, a22; - - - s = sin(theta); - c = cos(theta); - - a00 = c*r[0][0] - s*r[2][0]; - a01 = c*r[0][1] - s*r[2][1]; - a02 = c*r[0][2] - s*r[2][2]; - a20 = s*r[0][0] + c*r[2][0]; - a21 = s*r[0][1] + c*r[2][1]; - a22 = s*r[0][2] + c*r[2][2]; - - r[0][0] = a00; - r[0][1] = a01; - r[0][2] = a02; - r[2][0] = a20; - r[2][1] = a21; - r[2][2] = a22; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" - -void iauRz(double psi, double r[3][3]) -/* -** - - - - - - -** i a u R z -** - - - - - - -** -** Rotate an r-matrix about the z-axis. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: vector/matrix support function. -** -** Given: -** psi double angle (radians) -** -** Given and returned: -** r double[3][3] r-matrix, rotated -** -** Notes: -** -** 1) Calling this function with positive psi incorporates in the -** supplied r-matrix r an additional rotation, about the z-axis, -** anticlockwise as seen looking towards the origin from positive z. -** -** 2) The additional rotation can be represented by this matrix: -** -** ( + cos(psi) + sin(psi) 0 ) -** ( ) -** ( - sin(psi) + cos(psi) 0 ) -** ( ) -** ( 0 0 1 ) -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double s, c, a00, a01, a02, a10, a11, a12; - - - s = sin(psi); - c = cos(psi); - - a00 = c*r[0][0] + s*r[1][0]; - a01 = c*r[0][1] + s*r[1][1]; - a02 = c*r[0][2] + s*r[1][2]; - a10 = - s*r[0][0] + c*r[1][0]; - a11 = - s*r[0][1] + c*r[1][1]; - a12 = - s*r[0][2] + c*r[1][2]; - - r[0][0] = a00; - r[0][1] = a01; - r[0][2] = a02; - r[1][0] = a10; - r[1][1] = a11; - r[1][2] = a12; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" -#include "sofam.hpp" - -double iauS06(double date1, double date2, double x, double y) -/* -** - - - - - - - -** i a u S 0 6 -** - - - - - - - -** -** The CIO locator s, positioning the Celestial Intermediate Origin on -** the equator of the Celestial Intermediate Pole, given the CIP's X,Y -** coordinates. Compatible with IAU 2006/2000A precession-nutation. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: canonical model. -** -** Given: -** date1,date2 double TT as a 2-part Julian Date (Note 1) -** x,y double CIP coordinates (Note 3) -** -** Returned (function value): -** double the CIO locator s in radians (Note 2) -** -** Notes: -** -** 1) The TT date date1+date2 is a Julian Date, apportioned in any -** convenient way between the two arguments. For example, -** JD(TT)=2450123.7 could be expressed in any of these ways, -** among others: -** -** date1 date2 -** -** 2450123.7 0.0 (JD method) -** 2451545.0 -1421.3 (J2000 method) -** 2400000.5 50123.2 (MJD method) -** 2450123.5 0.2 (date & time method) -** -** The JD method is the most natural and convenient to use in -** cases where the loss of several decimal digits of resolution -** is acceptable. The J2000 method is best matched to the way -** the argument is handled internally and will deliver the -** optimum resolution. The MJD method and the date & time methods -** are both good compromises between resolution and convenience. -** -** 2) The CIO locator s is the difference between the right ascensions -** of the same point in two systems: the two systems are the GCRS -** and the CIP,CIO, and the point is the ascending node of the -** CIP equator. The quantity s remains below 0.1 arcsecond -** throughout 1900-2100. -** -** 3) The series used to compute s is in fact for s+XY/2, where X and Y -** are the x and y components of the CIP unit vector; this series -** is more compact than a direct series for s would be. This -** function requires X,Y to be supplied by the caller, who is -** responsible for providing values that are consistent with the -** supplied date. -** -** 4) The model is consistent with the "P03" precession (Capitaine et -** al. 2003), adopted by IAU 2006 Resolution 1, 2006, and the -** IAU 2000A nutation (with P03 adjustments). -** -** Called: -** iauFal03 mean anomaly of the Moon -** iauFalp03 mean anomaly of the Sun -** iauFaf03 mean argument of the latitude of the Moon -** iauFad03 mean elongation of the Moon from the Sun -** iauFaom03 mean longitude of the Moon's ascending node -** iauFave03 mean longitude of Venus -** iauFae03 mean longitude of Earth -** iauFapa03 general accumulated precession in longitude -** -** References: -** -** Capitaine, N., Wallace, P.T. & Chapront, J., 2003, Astron. -** Astrophys. 432, 355 -** -** McCarthy, D.D., Petit, G. (eds.) 2004, IERS Conventions (2003), -** IERS Technical Note No. 32, BKG -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ -/* Time since J2000.0, in Julian centuries */ - double t; - -/* Miscellaneous */ - int i, j; - double a, w0, w1, w2, w3, w4, w5; - -/* Fundamental arguments */ - double fa[8]; - -/* Returned value */ - double s; - -/* --------------------- */ -/* The series for s+XY/2 */ -/* --------------------- */ - - typedef struct { - int nfa[8]; /* coefficients of l,l',F,D,Om,LVe,LE,pA */ - double s, c; /* sine and cosine coefficients */ - } TERM; - -/* Polynomial coefficients */ - static const double sp[] = { - - /* 1-6 */ - 94.00e-6, - 3808.65e-6, - -122.68e-6, - -72574.11e-6, - 27.98e-6, - 15.62e-6 - }; - -/* Terms of order t^0 */ - static const TERM s0[] = { - - /* 1-10 */ - {{ 0, 0, 0, 0, 1, 0, 0, 0}, -2640.73e-6, 0.39e-6 }, - {{ 0, 0, 0, 0, 2, 0, 0, 0}, -63.53e-6, 0.02e-6 }, - {{ 0, 0, 2, -2, 3, 0, 0, 0}, -11.75e-6, -0.01e-6 }, - {{ 0, 0, 2, -2, 1, 0, 0, 0}, -11.21e-6, -0.01e-6 }, - {{ 0, 0, 2, -2, 2, 0, 0, 0}, 4.57e-6, 0.00e-6 }, - {{ 0, 0, 2, 0, 3, 0, 0, 0}, -2.02e-6, 0.00e-6 }, - {{ 0, 0, 2, 0, 1, 0, 0, 0}, -1.98e-6, 0.00e-6 }, - {{ 0, 0, 0, 0, 3, 0, 0, 0}, 1.72e-6, 0.00e-6 }, - {{ 0, 1, 0, 0, 1, 0, 0, 0}, 1.41e-6, 0.01e-6 }, - {{ 0, 1, 0, 0, -1, 0, 0, 0}, 1.26e-6, 0.01e-6 }, - - /* 11-20 */ - {{ 1, 0, 0, 0, -1, 0, 0, 0}, 0.63e-6, 0.00e-6 }, - {{ 1, 0, 0, 0, 1, 0, 0, 0}, 0.63e-6, 0.00e-6 }, - {{ 0, 1, 2, -2, 3, 0, 0, 0}, -0.46e-6, 0.00e-6 }, - {{ 0, 1, 2, -2, 1, 0, 0, 0}, -0.45e-6, 0.00e-6 }, - {{ 0, 0, 4, -4, 4, 0, 0, 0}, -0.36e-6, 0.00e-6 }, - {{ 0, 0, 1, -1, 1, -8, 12, 0}, 0.24e-6, 0.12e-6 }, - {{ 0, 0, 2, 0, 0, 0, 0, 0}, -0.32e-6, 0.00e-6 }, - {{ 0, 0, 2, 0, 2, 0, 0, 0}, -0.28e-6, 0.00e-6 }, - {{ 1, 0, 2, 0, 3, 0, 0, 0}, -0.27e-6, 0.00e-6 }, - {{ 1, 0, 2, 0, 1, 0, 0, 0}, -0.26e-6, 0.00e-6 }, - - /* 21-30 */ - {{ 0, 0, 2, -2, 0, 0, 0, 0}, 0.21e-6, 0.00e-6 }, - {{ 0, 1, -2, 2, -3, 0, 0, 0}, -0.19e-6, 0.00e-6 }, - {{ 0, 1, -2, 2, -1, 0, 0, 0}, -0.18e-6, 0.00e-6 }, - {{ 0, 0, 0, 0, 0, 8,-13, -1}, 0.10e-6, -0.05e-6 }, - {{ 0, 0, 0, 2, 0, 0, 0, 0}, -0.15e-6, 0.00e-6 }, - {{ 2, 0, -2, 0, -1, 0, 0, 0}, 0.14e-6, 0.00e-6 }, - {{ 0, 1, 2, -2, 2, 0, 0, 0}, 0.14e-6, 0.00e-6 }, - {{ 1, 0, 0, -2, 1, 0, 0, 0}, -0.14e-6, 0.00e-6 }, - {{ 1, 0, 0, -2, -1, 0, 0, 0}, -0.14e-6, 0.00e-6 }, - {{ 0, 0, 4, -2, 4, 0, 0, 0}, -0.13e-6, 0.00e-6 }, - - /* 31-33 */ - {{ 0, 0, 2, -2, 4, 0, 0, 0}, 0.11e-6, 0.00e-6 }, - {{ 1, 0, -2, 0, -3, 0, 0, 0}, -0.11e-6, 0.00e-6 }, - {{ 1, 0, -2, 0, -1, 0, 0, 0}, -0.11e-6, 0.00e-6 } - }; - -/* Terms of order t^1 */ - static const TERM s1[] = { - - /* 1 - 3 */ - {{ 0, 0, 0, 0, 2, 0, 0, 0}, -0.07e-6, 3.57e-6 }, - {{ 0, 0, 0, 0, 1, 0, 0, 0}, 1.73e-6, -0.03e-6 }, - {{ 0, 0, 2, -2, 3, 0, 0, 0}, 0.00e-6, 0.48e-6 } - }; - -/* Terms of order t^2 */ - static const TERM s2[] = { - - /* 1-10 */ - {{ 0, 0, 0, 0, 1, 0, 0, 0}, 743.52e-6, -0.17e-6 }, - {{ 0, 0, 2, -2, 2, 0, 0, 0}, 56.91e-6, 0.06e-6 }, - {{ 0, 0, 2, 0, 2, 0, 0, 0}, 9.84e-6, -0.01e-6 }, - {{ 0, 0, 0, 0, 2, 0, 0, 0}, -8.85e-6, 0.01e-6 }, - {{ 0, 1, 0, 0, 0, 0, 0, 0}, -6.38e-6, -0.05e-6 }, - {{ 1, 0, 0, 0, 0, 0, 0, 0}, -3.07e-6, 0.00e-6 }, - {{ 0, 1, 2, -2, 2, 0, 0, 0}, 2.23e-6, 0.00e-6 }, - {{ 0, 0, 2, 0, 1, 0, 0, 0}, 1.67e-6, 0.00e-6 }, - {{ 1, 0, 2, 0, 2, 0, 0, 0}, 1.30e-6, 0.00e-6 }, - {{ 0, 1, -2, 2, -2, 0, 0, 0}, 0.93e-6, 0.00e-6 }, - - /* 11-20 */ - {{ 1, 0, 0, -2, 0, 0, 0, 0}, 0.68e-6, 0.00e-6 }, - {{ 0, 0, 2, -2, 1, 0, 0, 0}, -0.55e-6, 0.00e-6 }, - {{ 1, 0, -2, 0, -2, 0, 0, 0}, 0.53e-6, 0.00e-6 }, - {{ 0, 0, 0, 2, 0, 0, 0, 0}, -0.27e-6, 0.00e-6 }, - {{ 1, 0, 0, 0, 1, 0, 0, 0}, -0.27e-6, 0.00e-6 }, - {{ 1, 0, -2, -2, -2, 0, 0, 0}, -0.26e-6, 0.00e-6 }, - {{ 1, 0, 0, 0, -1, 0, 0, 0}, -0.25e-6, 0.00e-6 }, - {{ 1, 0, 2, 0, 1, 0, 0, 0}, 0.22e-6, 0.00e-6 }, - {{ 2, 0, 0, -2, 0, 0, 0, 0}, -0.21e-6, 0.00e-6 }, - {{ 2, 0, -2, 0, -1, 0, 0, 0}, 0.20e-6, 0.00e-6 }, - - /* 21-25 */ - {{ 0, 0, 2, 2, 2, 0, 0, 0}, 0.17e-6, 0.00e-6 }, - {{ 2, 0, 2, 0, 2, 0, 0, 0}, 0.13e-6, 0.00e-6 }, - {{ 2, 0, 0, 0, 0, 0, 0, 0}, -0.13e-6, 0.00e-6 }, - {{ 1, 0, 2, -2, 2, 0, 0, 0}, -0.12e-6, 0.00e-6 }, - {{ 0, 0, 2, 0, 0, 0, 0, 0}, -0.11e-6, 0.00e-6 } - }; - -/* Terms of order t^3 */ - static const TERM s3[] = { - - /* 1-4 */ - {{ 0, 0, 0, 0, 1, 0, 0, 0}, 0.30e-6, -23.42e-6 }, - {{ 0, 0, 2, -2, 2, 0, 0, 0}, -0.03e-6, -1.46e-6 }, - {{ 0, 0, 2, 0, 2, 0, 0, 0}, -0.01e-6, -0.25e-6 }, - {{ 0, 0, 0, 0, 2, 0, 0, 0}, 0.00e-6, 0.23e-6 } - }; - -/* Terms of order t^4 */ - static const TERM s4[] = { - - /* 1-1 */ - {{ 0, 0, 0, 0, 1, 0, 0, 0}, -0.26e-6, -0.01e-6 } - }; - -/* Number of terms in the series */ - static const int NS0 = (int) (sizeof s0 / sizeof (TERM)); - static const int NS1 = (int) (sizeof s1 / sizeof (TERM)); - static const int NS2 = (int) (sizeof s2 / sizeof (TERM)); - static const int NS3 = (int) (sizeof s3 / sizeof (TERM)); - static const int NS4 = (int) (sizeof s4 / sizeof (TERM)); - -/* ------------------------------------------------------------------ */ - -/* Interval between fundamental epoch J2000.0 and current date (JC). */ - t = ((date1 - DJ00) + date2) / DJC; - -/* Fundamental Arguments (from IERS Conventions 2003) */ - -/* Mean anomaly of the Moon. */ - fa[0] = iauFal03(t); - -/* Mean anomaly of the Sun. */ - fa[1] = iauFalp03(t); - -/* Mean longitude of the Moon minus that of the ascending node. */ - fa[2] = iauFaf03(t); - -/* Mean elongation of the Moon from the Sun. */ - fa[3] = iauFad03(t); - -/* Mean longitude of the ascending node of the Moon. */ - fa[4] = iauFaom03(t); - -/* Mean longitude of Venus. */ - fa[5] = iauFave03(t); - -/* Mean longitude of Earth. */ - fa[6] = iauFae03(t); - -/* General precession in longitude. */ - fa[7] = iauFapa03(t); - -/* Evaluate s. */ - w0 = sp[0]; - w1 = sp[1]; - w2 = sp[2]; - w3 = sp[3]; - w4 = sp[4]; - w5 = sp[5]; - - for (i = NS0-1; i >= 0; i--) { - a = 0.0; - for (j = 0; j < 8; j++) { - a += (double)s0[i].nfa[j] * fa[j]; - } - w0 += s0[i].s * sin(a) + s0[i].c * cos(a); - } - - for (i = NS1-1; i >= 0; i--) { - a = 0.0; - for (j = 0; j < 8; j++) { - a += (double)s1[i].nfa[j] * fa[j]; - } - w1 += s1[i].s * sin(a) + s1[i].c * cos(a); - } - - for (i = NS2-1; i >= 0; i--) { - a = 0.0; - for (j = 0; j < 8; j++) { - a += (double)s2[i].nfa[j] * fa[j]; - } - w2 += s2[i].s * sin(a) + s2[i].c * cos(a); - } - - for (i = NS3-1; i >= 0; i--) { - a = 0.0; - for (j = 0; j < 8; j++) { - a += (double)s3[i].nfa[j] * fa[j]; - } - w3 += s3[i].s * sin(a) + s3[i].c * cos(a); - } - - for (i = NS4-1; i >= 0; i--) { - a = 0.0; - for (j = 0; j < 8; j++) { - a += (double)s4[i].nfa[j] * fa[j]; - } - w4 += s4[i].s * sin(a) + s4[i].c * cos(a); - } - - s = (w0 + - (w1 + - (w2 + - (w3 + - (w4 + - w5 * t) * t) * t) * t) * t) * DAS2R - x*y/2.0; - - return s; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} -#include "sofa.hpp" -#include "sofam.hpp" - -double iauSp00(double date1, double date2) -/* -** - - - - - - - - -** i a u S p 0 0 -** - - - - - - - - -** -** The TIO locator s', positioning the Terrestrial Intermediate Origin -** on the equator of the Celestial Intermediate Pole. -** -** This function is part of the International Astronomical Union's -** SOFA (Standards Of Fundamental Astronomy) software collection. -** -** Status: canonical model. -** -** Given: -** date1,date2 double TT as a 2-part Julian Date (Note 1) -** -** Returned (function value): -** double the TIO locator s' in radians (Note 2) -** -** Notes: -** -** 1) The TT date date1+date2 is a Julian Date, apportioned in any -** convenient way between the two arguments. For example, -** JD(TT)=2450123.7 could be expressed in any of these ways, -** among others: -** -** date1 date2 -** -** 2450123.7 0.0 (JD method) -** 2451545.0 -1421.3 (J2000 method) -** 2400000.5 50123.2 (MJD method) -** 2450123.5 0.2 (date & time method) -** -** The JD method is the most natural and convenient to use in -** cases where the loss of several decimal digits of resolution -** is acceptable. The J2000 method is best matched to the way -** the argument is handled internally and will deliver the -** optimum resolution. The MJD method and the date & time methods -** are both good compromises between resolution and convenience. -** -** 2) The TIO locator s' is obtained from polar motion observations by -** numerical integration, and so is in essence unpredictable. -** However, it is dominated by a secular drift of about -** 47 microarcseconds per century, which is the approximation -** evaluated by the present function. -** -** Reference: -** -** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), -** IERS Technical Note No. 32, BKG (2004) -** -** This revision: 2021 May 11 -** -** SOFA release 2021-05-12 -** -** Copyright (C) 2021 IAU SOFA Board. See notes at end. -*/ -{ - double t, sp; - - -/* Interval between fundamental epoch J2000.0 and current date (JC). */ - t = ((date1 - DJ00) + date2) / DJC; - -/* Approximate s'. */ - sp = -47e-6 * t * DAS2R; - - return sp; - -/* Finished. */ - -/*---------------------------------------------------------------------- -** -** Copyright (C) 2021 -** Standards Of Fundamental Astronomy Board -** of the International Astronomical Union. -** -** ===================== -** SOFA Software License -** ===================== -** -** NOTICE TO USER: -** -** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND -** CONDITIONS WHICH APPLY TO ITS USE. -** -** 1. The Software is owned by the IAU SOFA Board ("SOFA"). -** -** 2. Permission is granted to anyone to use the SOFA software for any -** purpose, including commercial applications, free of charge and -** without payment of royalties, subject to the conditions and -** restrictions listed below. -** -** 3. You (the user) may copy and distribute SOFA source code to others, -** and use and adapt its code and algorithms in your own software, -** on a world-wide, royalty-free basis. That portion of your -** distribution that does not consist of intact and unchanged copies -** of SOFA source code files is a "derived work" that must comply -** with the following requirements: -** -** a) Your work shall be marked or carry a statement that it -** (i) uses routines and computations derived by you from -** software provided by SOFA under license to you; and -** (ii) does not itself constitute software provided by and/or -** endorsed by SOFA. -** -** b) The source code of your derived work must contain descriptions -** of how the derived work is based upon, contains and/or differs -** from the original SOFA software. -** -** c) The names of all routines in your derived work shall not -** include the prefix "iau" or "sofa" or trivial modifications -** thereof such as changes of case. -** -** d) The origin of the SOFA components of your derived work must -** not be misrepresented; you must not claim that you wrote the -** original software, nor file a patent application for SOFA -** software or algorithms embedded in the SOFA software. -** -** e) These requirements must be reproduced intact in any source -** distribution and shall apply to anyone to whom you have -** granted a further right to modify the source code of your -** derived work. -** -** Note that, as originally distributed, the SOFA software is -** intended to be a definitive implementation of the IAU standards, -** and consequently third-party modifications are discouraged. All -** variations, no matter how minor, must be explicitly marked as -** such, as explained above. -** -** 4. You shall not cause the SOFA software to be brought into -** disrepute, either by misuse, or use for inappropriate tasks, or -** by inappropriate modification. -** -** 5. The SOFA software is provided "as is" and SOFA makes no warranty -** as to its use or performance. SOFA does not and cannot warrant -** the performance or results which the user may obtain by using the -** SOFA software. SOFA makes no warranties, express or implied, as -** to non-infringement of third party rights, merchantability, or -** fitness for any particular purpose. In no event will SOFA be -** liable to the user for any consequential, incidental, or special -** damages, including any lost profits or lost savings, even if a -** SOFA representative has been advised of such damages, or for any -** claim by any third party. -** -** 6. The provision of any version of the SOFA software under the terms -** and conditions specified herein does not imply that future -** versions will also be made available under the same terms and -** conditions. -* -** In any published work or commercial product which uses the SOFA -** software directly, acknowledgement (see www.iausofa.org) is -** appreciated. -** -** Correspondence concerning SOFA software should be addressed as -** follows: -** -** By email: sofa@ukho.gov.uk -** By post: IAU SOFA Center -** HM Nautical Almanac Office -** UK Hydrographic Office -** Admiralty Way, Taunton -** Somerset, TA1 2DN -** United Kingdom -** -**--------------------------------------------------------------------*/ -} diff --git a/src/cpp/3rdparty/sofa/src/a2af.c b/src/cpp/3rdparty/sofa/src/a2af.c new file mode 100644 index 000000000..41043f28f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/a2af.c @@ -0,0 +1,171 @@ +#include "sofa.h" +#include "sofam.h" + +void iauA2af(int ndp, double angle, char *sign, int idmsf[4]) +/* +** - - - - - - - - +** i a u A 2 a f +** - - - - - - - - +** +** Decompose radians into degrees, arcminutes, arcseconds, fraction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** ndp int resolution (Note 1) +** angle double angle in radians +** +** Returned: +** sign char* '+' or '-' +** idmsf int[4] degrees, arcminutes, arcseconds, fraction +** +** Notes: +** +** 1) The argument ndp is interpreted as follows: +** +** ndp resolution +** : ...0000 00 00 +** -7 1000 00 00 +** -6 100 00 00 +** -5 10 00 00 +** -4 1 00 00 +** -3 0 10 00 +** -2 0 01 00 +** -1 0 00 10 +** 0 0 00 01 +** 1 0 00 00.1 +** 2 0 00 00.01 +** 3 0 00 00.001 +** : 0 00 00.000... +** +** 2) The largest positive useful value for ndp is determined by the +** size of angle, the format of doubles on the target platform, and +** the risk of overflowing idmsf[3]. On a typical platform, for +** angle up to 2pi, the available floating-point precision might +** correspond to ndp=12. However, the practical limit is typically +** ndp=9, set by the capacity of a 32-bit int, or ndp=4 if int is +** only 16 bits. +** +** 3) The absolute value of angle may exceed 2pi. In cases where it +** does not, it is up to the caller to test for and handle the +** case where angle is very nearly 2pi and rounds up to 360 degrees, +** by testing for idmsf[0]=360 and setting idmsf[0-3] to zero. +** +** Called: +** iauD2tf decompose days to hms +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Hours to degrees * radians to turns */ + const double F = 15.0 / D2PI; + + +/* Scale then use days to h,m,s function. */ + iauD2tf(ndp, angle*F, sign, idmsf); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/a2tf.c b/src/cpp/3rdparty/sofa/src/a2tf.c new file mode 100644 index 000000000..7286bda91 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/a2tf.c @@ -0,0 +1,167 @@ +#include "sofa.h" +#include "sofam.h" + +void iauA2tf(int ndp, double angle, char *sign, int ihmsf[4]) +/* +** - - - - - - - - +** i a u A 2 t f +** - - - - - - - - +** +** Decompose radians into hours, minutes, seconds, fraction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** ndp int resolution (Note 1) +** angle double angle in radians +** +** Returned: +** sign char* '+' or '-' +** ihmsf int[4] hours, minutes, seconds, fraction +** +** Notes: +** +** 1) The argument ndp is interpreted as follows: +** +** ndp resolution +** : ...0000 00 00 +** -7 1000 00 00 +** -6 100 00 00 +** -5 10 00 00 +** -4 1 00 00 +** -3 0 10 00 +** -2 0 01 00 +** -1 0 00 10 +** 0 0 00 01 +** 1 0 00 00.1 +** 2 0 00 00.01 +** 3 0 00 00.001 +** : 0 00 00.000... +** +** 2) The largest positive useful value for ndp is determined by the +** size of angle, the format of doubles on the target platform, and +** the risk of overflowing ihmsf[3]. On a typical platform, for +** angle up to 2pi, the available floating-point precision might +** correspond to ndp=12. However, the practical limit is typically +** ndp=9, set by the capacity of a 32-bit int, or ndp=4 if int is +** only 16 bits. +** +** 3) The absolute value of angle may exceed 2pi. In cases where it +** does not, it is up to the caller to test for and handle the +** case where angle is very nearly 2pi and rounds up to 24 hours, +** by testing for ihmsf[0]=24 and setting ihmsf[0-3] to zero. +** +** Called: +** iauD2tf decompose days to hms +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Scale then use days to h,m,s function. */ + iauD2tf(ndp, angle/D2PI, sign, ihmsf); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ab.c b/src/cpp/3rdparty/sofa/src/ab.c new file mode 100644 index 000000000..229278cef --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ab.c @@ -0,0 +1,179 @@ +#include "sofa.h" +#include "sofam.h" + +void iauAb(double pnat[3], double v[3], double s, double bm1, + double ppr[3]) +/* +** - - - - - - +** i a u A b +** - - - - - - +** +** Apply aberration to transform natural direction into proper +** direction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** pnat double[3] natural direction to the source (unit vector) +** v double[3] observer barycentric velocity in units of c +** s double distance between the Sun and the observer (au) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** +** Returned: +** ppr double[3] proper direction to source (unit vector) +** +** Notes: +** +** 1) The algorithm is based on Expr. (7.40) in the Explanatory +** Supplement (Urban & Seidelmann 2013), but with the following +** changes: +** +** o Rigorous rather than approximate normalization is applied. +** +** o The gravitational potential term from Expr. (7) in +** Klioner (2003) is added, taking into account only the Sun's +** contribution. This has a maximum effect of about +** 0.4 microarcsecond. +** +** 2) In almost all cases, the maximum accuracy will be limited by the +** supplied velocity. For example, if the SOFA iauEpv00 function is +** used, errors of up to 5 microarcseconds could occur. +** +** References: +** +** Urban, S. & Seidelmann, P. K. (eds), Explanatory Supplement to +** the Astronomical Almanac, 3rd ed., University Science Books +** (2013). +** +** Klioner, Sergei A., "A practical relativistic model for micro- +** arcsecond astrometry in space", Astr. J. 125, 1580-1597 (2003). +** +** Called: +** iauPdp scalar product of two p-vectors +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int i; + double pdv, w1, w2, r2, w, p[3], r; + + + pdv = iauPdp(pnat, v); + w1 = 1.0 + pdv/(1.0 + bm1); + w2 = SRS/s; + r2 = 0.0; + for (i = 0; i < 3; i++) { + w = pnat[i]*bm1 + w1*v[i] + w2*(v[i] - pdv*pnat[i]); + p[i] = w; + r2 = r2 + w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + ppr[i] = p[i]/r; + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ae2hd.c b/src/cpp/3rdparty/sofa/src/ae2hd.c new file mode 100644 index 000000000..ec2bbc5c5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ae2hd.c @@ -0,0 +1,185 @@ +#include "sofa.h" + +void iauAe2hd (double az, double el, double phi, + double *ha, double *dec) +/* +** - - - - - - - - - +** i a u A e 2 h d +** - - - - - - - - - +** +** Horizon to equatorial coordinates: transform azimuth and altitude +** to hour angle and declination. +** +** Given: +** az double azimuth +** el double altitude (informally, elevation) +** phi double site latitude +** +** Returned: +** ha double hour angle (local) +** dec double declination +** +** Notes: +** +** 1) All the arguments are angles in radians. +** +** 2) The sign convention for azimuth is north zero, east +pi/2. +** +** 3) HA is returned in the range +/-pi. Declination is returned in +** the range +/-pi/2. +** +** 4) The latitude phi is pi/2 minus the angle between the Earth's +** rotation axis and the adopted zenith. In many applications it +** will be sufficient to use the published geodetic latitude of the +** site. In very precise (sub-arcsecond) applications, phi can be +** corrected for polar motion. +** +** 5) The azimuth az must be with respect to the rotational north pole, +** as opposed to the ITRS pole, and an azimuth with respect to north +** on a map of the Earth's surface will need to be adjusted for +** polar motion if sub-arcsecond accuracy is required. +** +** 6) Should the user wish to work with respect to the astronomical +** zenith rather than the geodetic zenith, phi will need to be +** adjusted for deflection of the vertical (often tens of +** arcseconds), and the zero point of ha will also be affected. +** +** 7) The transformation is the same as Ve = Ry(phi-pi/2)*Rz(pi)*Vh, +** where Ve and Vh are lefthanded unit vectors in the (ha,dec) and +** (az,el) systems respectively and Rz and Ry are rotations about +** first the z-axis and then the y-axis. (n.b. Rz(pi) simply +** reverses the signs of the x and y components.) For efficiency, +** the algorithm is written out rather than calling other utility +** functions. For applications that require even greater +** efficiency, additional savings are possible if constant terms +** such as functions of latitude are computed once and for all. +** +** 8) Again for efficiency, no range checking of arguments is carried +** out. +** +** Last revision: 2017 September 12 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double sa, ca, se, ce, sp, cp, x, y, z, r; + + +/* Useful trig functions. */ + sa = sin(az); + ca = cos(az); + se = sin(el); + ce = cos(el); + sp = sin(phi); + cp = cos(phi); + +/* HA,Dec unit vector. */ + x = - ca*ce*sp + se*cp; + y = - sa*ce; + z = ca*ce*cp + se*sp; + +/* To spherical. */ + r = sqrt(x*x + y*y); + *ha = (r != 0.0) ? atan2(y,x) : 0.0; + *dec = atan2(z,r); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/af2a.c b/src/cpp/3rdparty/sofa/src/af2a.c new file mode 100644 index 000000000..e267cb2bf --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/af2a.c @@ -0,0 +1,160 @@ +#include "sofa.h" +#include "sofam.h" +#include + +int iauAf2a(char s, int ideg, int iamin, double asec, double *rad) +/* +** - - - - - - - - +** i a u A f 2 a +** - - - - - - - - +** +** Convert degrees, arcminutes, arcseconds to radians. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** s char sign: '-' = negative, otherwise positive +** ideg int degrees +** iamin int arcminutes +** asec double arcseconds +** +** Returned: +** rad double angle in radians +** +** Returned (function value): +** int status: 0 = OK +** 1 = ideg outside range 0-359 +** 2 = iamin outside range 0-59 +** 3 = asec outside range 0-59.999... +** +** Notes: +** +** 1) The result is computed even if any of the range checks fail. +** +** 2) Negative ideg, iamin and/or asec produce a warning status, but +** the absolute value is used in the conversion. +** +** 3) If there are multiple errors, the status value reflects only the +** first, the smallest taking precedence. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Compute the interval. */ + *rad = ( s == '-' ? -1.0 : 1.0 ) * + ( 60.0 * ( 60.0 * ( (double) abs(ideg) ) + + ( (double) abs(iamin) ) ) + + fabs(asec) ) * DAS2R; + +/* Validate arguments and return status. */ + if ( ideg < 0 || ideg > 359 ) return 1; + if ( iamin < 0 || iamin > 59 ) return 2; + if ( asec < 0.0 || asec >= 60.0 ) return 3; + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/anp.c b/src/cpp/3rdparty/sofa/src/anp.c new file mode 100644 index 000000000..cd7a7bdf0 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/anp.c @@ -0,0 +1,135 @@ +#include "sofa.h" +#include "sofam.h" + +double iauAnp(double a) +/* +** - - - - - - - +** i a u A n p +** - - - - - - - +** +** Normalize angle into the range 0 <= a < 2pi. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double angle (radians) +** +** Returned (function value): +** double angle in range 0-2pi +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double w; + + + w = fmod(a, D2PI); + if (w < 0) w += D2PI; + + return w; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/anpm.c b/src/cpp/3rdparty/sofa/src/anpm.c new file mode 100644 index 000000000..379a04038 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/anpm.c @@ -0,0 +1,135 @@ +#include "sofa.h" +#include "sofam.h" + +double iauAnpm(double a) +/* +** - - - - - - - - +** i a u A n p m +** - - - - - - - - +** +** Normalize angle into the range -pi <= a < +pi. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double angle (radians) +** +** Returned (function value): +** double angle in range +/-pi +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double w; + + + w = fmod(a, D2PI); + if (fabs(w) >= DPI) w -= dsign(D2PI, a); + + return w; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apcg.c b/src/cpp/3rdparty/sofa/src/apcg.c new file mode 100644 index 000000000..1df861e0d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apcg.c @@ -0,0 +1,222 @@ +#include "sofa.h" + +void iauApcg(double date1, double date2, + double ebpv[2][3], double ehp[3], + iauASTROM *astrom) +/* +** - - - - - - - - +** i a u A p c g +** - - - - - - - - +** +** For a geocentric observer, prepare star-independent astrometry +** parameters for transformations between ICRS and GCRS coordinates. +** The Earth ephemeris is supplied by the caller. +** +** The parameters produced by this function are required in the +** parallax, light deflection and aberration parts of the astrometric +** transformation chain. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** ebpv double[2][3] Earth barycentric pos/vel (au, au/day) +** ehp double[3] Earth heliocentric position (au) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double unchanged +** refa double unchanged +** refb double unchanged +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) All the vectors are with respect to BCRS axes. +** +** 3) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 4) The context structure astrom produced by this function is used by +** iauAtciq* and iauAticq*. +** +** Called: +** iauApcs astrometry parameters, ICRS-GCRS, space observer +** +** This revision: 2013 October 9 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Geocentric observer */ + double pv[2][3] = { { 0.0, 0.0, 0.0 }, + { 0.0, 0.0, 0.0 } }; + + +/* Compute the star-independent astrometry parameters. */ + iauApcs(date1, date2, pv, ebpv, ehp, astrom); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apcg13.c b/src/cpp/3rdparty/sofa/src/apcg13.c new file mode 100644 index 000000000..3fc654823 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apcg13.c @@ -0,0 +1,225 @@ +#include "sofa.h" + +void iauApcg13(double date1, double date2, iauASTROM *astrom) +/* +** - - - - - - - - - - +** i a u A p c g 1 3 +** - - - - - - - - - - +** +** For a geocentric observer, prepare star-independent astrometry +** parameters for transformations between ICRS and GCRS coordinates. +** The caller supplies the date, and SOFA models are used to predict +** the Earth ephemeris. +** +** The parameters produced by this function are required in the +** parallax, light deflection and aberration parts of the astrometric +** transformation chain. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double unchanged +** refa double unchanged +** refb double unchanged +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) All the vectors are with respect to BCRS axes. +** +** 3) In cases where the caller wishes to supply his own Earth +** ephemeris, the function iauApcg can be used instead of the present +** function. +** +** 4) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 5) The context structure astrom produced by this function is used by +** iauAtciq* and iauAticq*. +** +** Called: +** iauEpv00 Earth position and velocity +** iauApcg astrometry parameters, ICRS-GCRS, geocenter +** +** This revision: 2013 October 9 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double ehpv[2][3], ebpv[2][3]; + + +/* Earth barycentric & heliocentric position/velocity (au, au/d). */ + (void) iauEpv00(date1, date2, ehpv, ebpv); + +/* Compute the star-independent astrometry parameters. */ + iauApcg(date1, date2, ebpv, ehpv[0], astrom); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apci.c b/src/cpp/3rdparty/sofa/src/apci.c new file mode 100644 index 000000000..86c475491 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apci.c @@ -0,0 +1,231 @@ +#include "sofa.h" + +void iauApci(double date1, double date2, + double ebpv[2][3], double ehp[3], + double x, double y, double s, + iauASTROM *astrom) +/* +** - - - - - - - - +** i a u A p c i +** - - - - - - - - +** +** For a terrestrial observer, prepare star-independent astrometry +** parameters for transformations between ICRS and geocentric CIRS +** coordinates. The Earth ephemeris and CIP/CIO are supplied by the +** caller. +** +** The parameters produced by this function are required in the +** parallax, light deflection, aberration, and bias-precession-nutation +** parts of the astrometric transformation chain. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** ebpv double[2][3] Earth barycentric position/velocity (au, au/day) +** ehp double[3] Earth heliocentric position (au) +** x,y double CIP X,Y (components of unit vector) +** s double the CIO locator s (radians) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double unchanged +** refa double unchanged +** refb double unchanged +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) All the vectors are with respect to BCRS axes. +** +** 3) In cases where the caller does not wish to provide the Earth +** ephemeris and CIP/CIO, the function iauApci13 can be used instead +** of the present function. This computes the required quantities +** using other SOFA functions. +** +** 4) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 5) The context structure astrom produced by this function is used by +** iauAtciq* and iauAticq*. +** +** Called: +** iauApcg astrometry parameters, ICRS-GCRS, geocenter +** iauC2ixys celestial-to-intermediate matrix, given X,Y and s +** +** This revision: 2013 September 25 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Star-independent astrometry parameters for geocenter. */ + iauApcg(date1, date2, ebpv, ehp, astrom); + +/* CIO based BPN matrix. */ + iauC2ixys(x, y, s, astrom->bpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apci13.c b/src/cpp/3rdparty/sofa/src/apci13.c new file mode 100644 index 000000000..ea5cf5672 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apci13.c @@ -0,0 +1,243 @@ +#include "sofa.h" + +void iauApci13(double date1, double date2, + iauASTROM *astrom, double *eo) +/* +** - - - - - - - - - - +** i a u A p c i 1 3 +** - - - - - - - - - - +** +** For a terrestrial observer, prepare star-independent astrometry +** parameters for transformations between ICRS and geocentric CIRS +** coordinates. The caller supplies the date, and SOFA models are used +** to predict the Earth ephemeris and CIP/CIO. +** +** The parameters produced by this function are required in the +** parallax, light deflection, aberration, and bias-precession-nutation +** parts of the astrometric transformation chain. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double unchanged +** refa double unchanged +** refb double unchanged +** eo double* equation of the origins (ERA-GST) +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) All the vectors are with respect to BCRS axes. +** +** 3) In cases where the caller wishes to supply his own Earth +** ephemeris and CIP/CIO, the function iauApci can be used instead +** of the present function. +** +** 4) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 5) The context structure astrom produced by this function is used by +** iauAtciq* and iauAticq*. +** +** Called: +** iauEpv00 Earth position and velocity +** iauPnm06a classical NPB matrix, IAU 2006/2000A +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS06 the CIO locator s, given X,Y, IAU 2006 +** iauApci astrometry parameters, ICRS-CIRS +** iauEors equation of the origins, given NPB matrix and s +** +** This revision: 2013 October 9 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double ehpv[2][3], ebpv[2][3], r[3][3], x, y, s; + + +/* Earth barycentric & heliocentric position/velocity (au, au/d). */ + (void) iauEpv00(date1, date2, ehpv, ebpv); + +/* Form the equinox based BPN matrix, IAU 2006/2000A. */ + iauPnm06a(date1, date2, r); + +/* Extract CIP X,Y. */ + iauBpn2xy(r, &x, &y); + +/* Obtain CIO locator s. */ + s = iauS06(date1, date2, x, y); + +/* Compute the star-independent astrometry parameters. */ + iauApci(date1, date2, ebpv, ehpv[0], x, y, s, astrom); + +/* Equation of the origins. */ + *eo = iauEors(r, s); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apco.c b/src/cpp/3rdparty/sofa/src/apco.c new file mode 100644 index 000000000..f5b9d655c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apco.c @@ -0,0 +1,325 @@ +#include "sofa.h" +#include "sofam.h" + +void iauApco(double date1, double date2, + double ebpv[2][3], double ehp[3], + double x, double y, double s, double theta, + double elong, double phi, double hm, + double xp, double yp, double sp, + double refa, double refb, + iauASTROM *astrom) +/* +** - - - - - - - - +** i a u A p c o +** - - - - - - - - +** +** For a terrestrial observer, prepare star-independent astrometry +** parameters for transformations between ICRS and observed +** coordinates. The caller supplies the Earth ephemeris, the Earth +** rotation information and the refraction constants as well as the +** site coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** ebpv double[2][3] Earth barycentric PV (au, au/day, Note 2) +** ehp double[3] Earth heliocentric P (au, Note 2) +** x,y double CIP X,Y (components of unit vector) +** s double the CIO locator s (radians) +** theta double Earth rotation angle (radians) +** elong double longitude (radians, east +ve, Note 3) +** phi double latitude (geodetic, radians, Note 3) +** hm double height above ellipsoid (m, geodetic, Note 3) +** xp,yp double polar motion coordinates (radians, Note 4) +** sp double the TIO locator s' (radians, Note 4) +** refa double refraction constant A (radians, Note 5) +** refb double refraction constant B (radians, Note 5) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double adjusted longitude (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) The vectors eb, eh, and all the astrom vectors, are with respect +** to BCRS axes. +** +** 3) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN +** CONVENTION: the longitude required by the present function is +** right-handed, i.e. east-positive, in accordance with geographical +** convention. +** +** The adjusted longitude stored in the astrom array takes into +** account the TIO locator and polar motion. +** +** 4) xp and yp are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions), measured along the +** meridians 0 and 90 deg west respectively. sp is the TIO locator +** s', in radians, which positions the Terrestrial Intermediate +** Origin on the equator. For many applications, xp, yp and +** (especially) sp can be set to zero. +** +** Internally, the polar motion is stored in a form rotated onto the +** local meridian. +** +** 5) The refraction constants refa and refb are for use in a +** dZ = A*tan(Z)+B*tan^3(Z) model, where Z is the observed +** (i.e. refracted) zenith distance and dZ is the amount of +** refraction. +** +** 6) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** 7) In cases where the caller does not wish to provide the Earth +** Ephemeris, the Earth rotation information and refraction +** constants, the function iauApco13 can be used instead of the +** present function. This starts from UTC and weather readings etc. +** and computes suitable values using other SOFA functions. +** +** 8) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 9) The context structure astrom produced by this function is used by +** iauAtioq, iauAtoiq, iauAtciq* and iauAticq*. +** +** Called: +** iauIr initialize r-matrix to identity +** iauRz rotate around Z-axis +** iauRy rotate around Y-axis +** iauRx rotate around X-axis +** iauAnpm normalize angle into range +/- pi +** iauC2ixys celestial-to-intermediate matrix, given X,Y and s +** iauPvtob position/velocity of terrestrial station +** iauTrxpv product of transpose of r-matrix and pv-vector +** iauApcs astrometry parameters, ICRS-GCRS, space observer +** iauCr copy r-matrix +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r[3][3], a, b, eral, c, pvc[2][3], pv[2][3]; + + +/* Form the rotation matrix, CIRS to apparent [HA,Dec]. */ + iauIr(r); + iauRz(theta+sp, r); + iauRy(-xp, r); + iauRx(-yp, r); + iauRz(elong, r); + +/* Solve for local Earth rotation angle. */ + a = r[0][0]; + b = r[0][1]; + eral = ( a != 0.0 || b != 0.0 ) ? atan2(b, a) : 0.0; + astrom->eral = eral; + +/* Solve for polar motion [X,Y] with respect to local meridian. */ + a = r[0][0]; + c = r[0][2]; + astrom->xpl = atan2(c, sqrt(a*a+b*b)); + a = r[1][2]; + b = r[2][2]; + astrom->ypl = ( a != 0.0 || b != 0.0 ) ? -atan2(a, b) : 0.0; + +/* Adjusted longitude. */ + astrom->along = iauAnpm(eral - theta); + +/* Functions of latitude. */ + astrom->sphi = sin(phi); + astrom->cphi = cos(phi); + +/* Refraction constants. */ + astrom->refa = refa; + astrom->refb = refb; + +/* Disable the (redundant) diurnal aberration step. */ + astrom->diurab = 0.0; + +/* CIO based BPN matrix. */ + iauC2ixys(x, y, s, r); + +/* Observer's geocentric position and velocity (m, m/s, CIRS). */ + iauPvtob(elong, phi, hm, xp, yp, sp, theta, pvc); + +/* Rotate into GCRS. */ + iauTrxpv(r, pvc, pv); + +/* ICRS <-> GCRS parameters. */ + iauApcs(date1, date2, pv, ebpv, ehp, astrom); + +/* Store the CIO based BPN matrix. */ + iauCr(r, astrom->bpn ); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apco13.c b/src/cpp/3rdparty/sofa/src/apco13.c new file mode 100644 index 000000000..a5e69b143 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apco13.c @@ -0,0 +1,329 @@ +#include "sofa.h" +#include "sofam.h" + +int iauApco13(double utc1, double utc2, double dut1, + double elong, double phi, double hm, double xp, double yp, + double phpa, double tc, double rh, double wl, + iauASTROM *astrom, double *eo) +/* +** - - - - - - - - - - +** i a u A p c o 1 3 +** - - - - - - - - - - +** +** For a terrestrial observer, prepare star-independent astrometry +** parameters for transformations between ICRS and observed +** coordinates. The caller supplies UTC, site coordinates, ambient air +** conditions and observing wavelength, and SOFA models are used to +** obtain the Earth ephemeris, CIP/CIO and refraction constants. +** +** The parameters produced by this function are required in the +** parallax, light deflection, aberration, and bias-precession-nutation +** parts of the ICRS/CIRS transformations. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** utc1 double UTC as a 2-part... +** utc2 double ...quasi Julian Date (Notes 1,2) +** dut1 double UT1-UTC (seconds, Note 3) +** elong double longitude (radians, east +ve, Note 4) +** phi double latitude (geodetic, radians, Note 4) +** hm double height above ellipsoid (m, geodetic, Notes 4,6) +** xp,yp double polar motion coordinates (radians, Note 5) +** phpa double pressure at the observer (hPa = mB, Note 6) +** tc double ambient temperature at the observer (deg C) +** rh double relative humidity at the observer (range 0-1) +** wl double wavelength (micrometers, Note 7) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** eo double* equation of the origins (ERA-GST) +** +** Returned (function value): +** int status: +1 = dubious year (Note 2) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** However, JD cannot unambiguously represent UTC during a leap +** second unless special measures are taken. The convention in the +** present function is that the JD day represents UTC days whether +** the length is 86399, 86400 or 86401 SI seconds. +** +** Applications should use the function iauDtf2d to convert from +** calendar date and time of day into 2-part quasi Julian Date, as +** it implements the leap-second-ambiguity convention just +** described. +** +** 2) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the +** future to be trusted. See iauDat for further details. +** +** 3) UT1-UTC is tabulated in IERS bulletins. It increases by exactly +** one second at the end of each positive UTC leap second, +** introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This +** practice is under review, and in the future UT1-UTC may grow +** essentially without limit. +** +** 4) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the +** longitude required by the present function is east-positive +** (i.e. right-handed), in accordance with geographical convention. +** +** 5) The polar motion xp,yp can be obtained from IERS bulletins. The +** values are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions 2003), measured along the +** meridians 0 and 90 deg west respectively. For many +** applications, xp and yp can be set to zero. +** +** Internally, the polar motion is stored in a form rotated onto +** the local meridian. +** +** 6) If hm, the height above the ellipsoid of the observing station +** in meters, is not known but phpa, the pressure in hPa (=mB), is +** available, an adequate estimate of hm can be obtained from the +** expression +** +** hm = -29.3 * tsl * log ( phpa / 1013.25 ); +** +** where tsl is the approximate sea-level air temperature in K +** (See Astrophysical Quantities, C.W.Allen, 3rd edition, section +** 52). Similarly, if the pressure phpa is not known, it can be +** estimated from the height of the observing station, hm, as +** follows: +** +** phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) ); +** +** Note, however, that the refraction is nearly proportional to +** the pressure and that an accurate phpa value is important for +** precise work. +** +** 7) The argument wl specifies the observing wavelength in +** micrometers. The transition from optical to radio is assumed to +** occur at 100 micrometers (about 3000 GHz). +** +** 8) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** 9) In cases where the caller wishes to supply his own Earth +** ephemeris, Earth rotation information and refraction constants, +** the function iauApco can be used instead of the present function. +** +** 10) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 11) The context structure astrom produced by this function is used +** by iauAtioq, iauAtoiq, iauAtciq* and iauAticq*. +** +** Called: +** iauUtctai UTC to TAI +** iauTaitt TAI to TT +** iauUtcut1 UTC to UT1 +** iauEpv00 Earth position and velocity +** iauPnm06a classical NPB matrix, IAU 2006/2000A +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS06 the CIO locator s, given X,Y, IAU 2006 +** iauEra00 Earth rotation angle, IAU 2000 +** iauSp00 the TIO locator s', IERS 2000 +** iauRefco refraction constants for given ambient conditions +** iauApco astrometry parameters, ICRS-observed +** iauEors equation of the origins, given NPB matrix and s +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + double tai1, tai2, tt1, tt2, ut11, ut12, ehpv[2][3], ebpv[2][3], + r[3][3], x, y, s, theta, sp, refa, refb; + + +/* UTC to other time scales. */ + j = iauUtctai(utc1, utc2, &tai1, &tai2); + if ( j < 0 ) return -1; + j = iauTaitt(tai1, tai2, &tt1, &tt2); + j = iauUtcut1(utc1, utc2, dut1, &ut11, &ut12); + if ( j < 0 ) return -1; + +/* Earth barycentric & heliocentric position/velocity (au, au/d). */ + (void) iauEpv00(tt1, tt2, ehpv, ebpv); + +/* Form the equinox based BPN matrix, IAU 2006/2000A. */ + iauPnm06a(tt1, tt2, r); + +/* Extract CIP X,Y. */ + iauBpn2xy(r, &x, &y); + +/* Obtain CIO locator s. */ + s = iauS06(tt1, tt2, x, y); + +/* Earth rotation angle. */ + theta = iauEra00(ut11, ut12); + +/* TIO locator s'. */ + sp = iauSp00(tt1, tt2); + +/* Refraction constants A and B. */ + iauRefco(phpa, tc, rh, wl, &refa, &refb); + +/* Compute the star-independent astrometry parameters. */ + iauApco(tt1, tt2, ebpv, ehpv[0], x, y, s, theta, + elong, phi, hm, xp, yp, sp, refa, refb, astrom); + +/* Equation of the origins. */ + *eo = iauEors(r, s); + +/* Return any warning status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apcs.c b/src/cpp/3rdparty/sofa/src/apcs.c new file mode 100644 index 000000000..6f9f58cc5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apcs.c @@ -0,0 +1,275 @@ +#include "sofa.h" +#include "sofam.h" + +void iauApcs(double date1, double date2, double pv[2][3], + double ebpv[2][3], double ehp[3], + iauASTROM *astrom) +/* +** - - - - - - - - +** i a u A p c s +** - - - - - - - - +** +** For an observer whose geocentric position and velocity are known, +** prepare star-independent astrometry parameters for transformations +** between ICRS and GCRS. The Earth ephemeris is supplied by the +** caller. +** +** The parameters produced by this function are required in the space +** motion, parallax, light deflection and aberration parts of the +** astrometric transformation chain. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** pv double[2][3] observer's geocentric pos/vel (m, m/s) +** ebpv double[2][3] Earth barycentric PV (au, au/day) +** ehp double[3] Earth heliocentric P (au) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double unchanged +** refa double unchanged +** refb double unchanged +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) All the vectors are with respect to BCRS axes. +** +** 3) Providing separate arguments for (i) the observer's geocentric +** position and velocity and (ii) the Earth ephemeris is done for +** convenience in the geocentric, terrestrial and Earth orbit cases. +** For deep space applications it maybe more convenient to specify +** zero geocentric position and velocity and to supply the +** observer's position and velocity information directly instead of +** with respect to the Earth. However, note the different units: +** m and m/s for the geocentric vectors, au and au/day for the +** heliocentric and barycentric vectors. +** +** 4) In cases where the caller does not wish to provide the Earth +** ephemeris, the function iauApcs13 can be used instead of the +** present function. This computes the Earth ephemeris using the +** SOFA function iauEpv00. +** +** 5) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 6) The context structure astrom produced by this function is used by +** iauAtciq* and iauAticq*. +** +** Called: +** iauCp copy p-vector +** iauPm modulus of p-vector +** iauPn decompose p-vector into modulus and direction +** iauIr initialize r-matrix to identity +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* au/d to m/s */ + const double AUDMS = DAU/DAYSEC; + +/* Light time for 1 au (day) */ + const double CR = AULT/DAYSEC; + + int i; + double dp, dv, pb[3], vb[3], ph[3], v2, w; + + +/* Time since reference epoch, years (for proper motion calculation). */ + astrom->pmt = ( (date1 - DJ00) + date2 ) / DJY; + +/* Adjust Earth ephemeris to observer. */ + for (i = 0; i < 3; i++) { + dp = pv[0][i] / DAU; + dv = pv[1][i] / AUDMS; + pb[i] = ebpv[0][i] + dp; + vb[i] = ebpv[1][i] + dv; + ph[i] = ehp[i] + dp; + } + +/* Barycentric position of observer (au). */ + iauCp(pb, astrom->eb); + +/* Heliocentric direction and distance (unit vector and au). */ + iauPn(ph, &astrom->em, astrom->eh); + +/* Barycentric vel. in units of c, and reciprocal of Lorenz factor. */ + v2 = 0.0; + for (i = 0; i < 3; i++) { + w = vb[i] * CR; + astrom->v[i] = w; + v2 += w*w; + } + astrom->bm1 = sqrt(1.0 - v2); + +/* Reset the NPB matrix. */ + iauIr(astrom->bpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apcs13.c b/src/cpp/3rdparty/sofa/src/apcs13.c new file mode 100644 index 000000000..0d713ff61 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apcs13.c @@ -0,0 +1,232 @@ +#include "sofa.h" + +void iauApcs13(double date1, double date2, double pv[2][3], + iauASTROM *astrom) +/* +** - - - - - - - - - - +** i a u A p c s 1 3 +** - - - - - - - - - - +** +** For an observer whose geocentric position and velocity are known, +** prepare star-independent astrometry parameters for transformations +** between ICRS and GCRS. The Earth ephemeris is from SOFA models. +** +** The parameters produced by this function are required in the space +** motion, parallax, light deflection and aberration parts of the +** astrometric transformation chain. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** pv double[2][3] observer's geocentric pos/vel (Note 3) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double unchanged +** refa double unchanged +** refb double unchanged +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) All the vectors are with respect to BCRS axes. +** +** 3) The observer's position and velocity pv are geocentric but with +** respect to BCRS axes, and in units of m and m/s. No assumptions +** are made about proximity to the Earth, and the function can be +** used for deep space applications as well as Earth orbit and +** terrestrial. +** +** 4) In cases where the caller wishes to supply his own Earth +** ephemeris, the function iauApcs can be used instead of the present +** function. +** +** 5) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 6) The context structure astrom produced by this function is used by +** iauAtciq* and iauAticq*. +** +** Called: +** iauEpv00 Earth position and velocity +** iauApcs astrometry parameters, ICRS-GCRS, space observer +** +** This revision: 2013 October 9 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double ehpv[2][3], ebpv[2][3]; + + +/* Earth barycentric & heliocentric position/velocity (au, au/d). */ + (void) iauEpv00(date1, date2, ehpv, ebpv); + +/* Compute the star-independent astrometry parameters. */ + iauApcs(date1, date2, pv, ebpv, ehpv[0], astrom); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/aper.c b/src/cpp/3rdparty/sofa/src/aper.c new file mode 100644 index 000000000..e5d2edd16 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/aper.c @@ -0,0 +1,203 @@ +#include "sofa.h" + +void iauAper(double theta, iauASTROM *astrom) +/* +** - - - - - - - - +** i a u A p e r +** - - - - - - - - +** +** In the star-independent astrometry parameters, update only the +** Earth rotation angle, supplied by the caller explicitly. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** theta double Earth rotation angle (radians, Note 2) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double not used +** eb double[3] not used +** eh double[3] not used +** em double not used +** v double[3] not used +** bm1 double not used +** bpn double[3][3] not used +** along double longitude + s' (radians) +** xpl double not used +** ypl double not used +** sphi double not used +** cphi double not used +** diurab double not used +** eral double not used +** refa double not used +** refb double not used +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double unchanged +** eb double[3] unchanged +** eh double[3] unchanged +** em double unchanged +** v double[3] unchanged +** bm1 double unchanged +** bpn double[3][3] unchanged +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double "local" Earth rotation angle (radians) +** refa double unchanged +** refb double unchanged +** +** Notes: +** +** 1) This function exists to enable sidereal-tracking applications to +** avoid wasteful recomputation of the bulk of the astrometry +** parameters: only the Earth rotation is updated. +** +** 2) For targets expressed as equinox based positions, such as +** classical geocentric apparent (RA,Dec), the supplied theta can be +** Greenwich apparent sidereal time rather than Earth rotation +** angle. +** +** 3) The function iauAper13 can be used instead of the present +** function, and starts from UT1 rather than ERA itself. +** +** 4) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** This revision: 2013 September 25 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + astrom->eral = theta + astrom->along; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/aper13.c b/src/cpp/3rdparty/sofa/src/aper13.c new file mode 100644 index 000000000..f270771ca --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/aper13.c @@ -0,0 +1,222 @@ +#include "sofa.h" + +void iauAper13(double ut11, double ut12, iauASTROM *astrom) +/* +** - - - - - - - - - - +** i a u A p e r 1 3 +** - - - - - - - - - - +** +** In the star-independent astrometry parameters, update only the +** Earth rotation angle. The caller provides UT1, (n.b. not UTC). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ut11 double UT1 as a 2-part... +** ut12 double ...Julian Date (Note 1) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double not used +** eb double[3] not used +** eh double[3] not used +** em double not used +** v double[3] not used +** bm1 double not used +** bpn double[3][3] not used +** along double longitude + s' (radians) +** xpl double not used +** ypl double not used +** sphi double not used +** cphi double not used +** diurab double not used +** eral double not used +** refa double not used +** refb double not used +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double unchanged +** eb double[3] unchanged +** eh double[3] unchanged +** em double unchanged +** v double[3] unchanged +** bm1 double unchanged +** bpn double[3][3] unchanged +** along double unchanged +** xpl double unchanged +** ypl double unchanged +** sphi double unchanged +** cphi double unchanged +** diurab double unchanged +** eral double "local" Earth rotation angle (radians) +** refa double unchanged +** refb double unchanged +** +** Notes: +** +** 1) The UT1 date (n.b. not UTC) ut11+ut12 is a Julian Date, +** apportioned in any convenient way between the arguments ut11 and +** ut12. For example, JD(UT1)=2450123.7 could be expressed in any +** of these ways, among others: +** +** ut11 ut12 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. The date & time method is +** best matched to the algorithm used: maximum precision is +** delivered when the ut11 argument is for 0hrs UT1 on the day in +** question and the ut12 argument lies in the range 0 to 1, or vice +** versa. +** +** 2) If the caller wishes to provide the Earth rotation angle itself, +** the function iauAper can be used instead. One use of this +** technique is to substitute Greenwich apparent sidereal time and +** thereby to support equinox based transformations directly. +** +** 3) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** Called: +** iauAper astrometry parameters: update ERA +** iauEra00 Earth rotation angle, IAU 2000 +** +** This revision: 2013 September 25 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauAper(iauEra00(ut11,ut12), astrom); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apio.c b/src/cpp/3rdparty/sofa/src/apio.c new file mode 100644 index 000000000..827472c22 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apio.c @@ -0,0 +1,271 @@ +#include "sofa.h" +#include "sofam.h" + +void iauApio(double sp, double theta, + double elong, double phi, double hm, double xp, double yp, + double refa, double refb, + iauASTROM *astrom) +/* +** - - - - - - - - +** i a u A p i o +** - - - - - - - - +** +** For a terrestrial observer, prepare star-independent astrometry +** parameters for transformations between CIRS and observed +** coordinates. The caller supplies the Earth orientation information +** and the refraction constants as well as the site coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** sp double the TIO locator s' (radians, Note 1) +** theta double Earth rotation angle (radians) +** elong double longitude (radians, east +ve, Note 2) +** phi double geodetic latitude (radians, Note 2) +** hm double height above ellipsoid (m, geodetic Note 2) +** xp,yp double polar motion coordinates (radians, Note 3) +** refa double refraction constant A (radians, Note 4) +** refb double refraction constant B (radians, Note 4) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double unchanged +** eb double[3] unchanged +** eh double[3] unchanged +** em double unchanged +** v double[3] unchanged +** bm1 double unchanged +** bpn double[3][3] unchanged +** along double adjusted longitude (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Notes: +** +** 1) sp, the TIO locator s', is a tiny quantity needed only by the +** most precise applications. It can either be set to zero or +** predicted using the SOFA function iauSp00. +** +** 2) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the +** longitude required by the present function is east-positive +** (i.e. right-handed), in accordance with geographical convention. +** +** 3) The polar motion xp,yp can be obtained from IERS bulletins. The +** values are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions 2003), measured along the +** meridians 0 and 90 deg west respectively. For many applications, +** xp and yp can be set to zero. +** +** Internally, the polar motion is stored in a form rotated onto the +** local meridian. +** +** 4) The refraction constants refa and refb are for use in a +** dZ = A*tan(Z)+B*tan^3(Z) model, where Z is the observed +** (i.e. refracted) zenith distance and dZ is the amount of +** refraction. +** +** 5) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** 6) In cases where the caller does not wish to provide the Earth +** rotation information and refraction constants, the function +** iauApio13 can be used instead of the present function. This +** starts from UTC and weather readings etc. and computes suitable +** values using other SOFA functions. +** +** 7) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 8) The context structure astrom produced by this function is used by +** iauAtioq and iauAtoiq. +** +** Called: +** iauIr initialize r-matrix to identity +** iauRz rotate around Z-axis +** iauRy rotate around Y-axis +** iauRx rotate around X-axis +** iauAnpm normalize angle into range +/- pi +** iauPvtob position/velocity of terrestrial station +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r[3][3], a, b, eral, c, pv[2][3]; + + +/* Form the rotation matrix, CIRS to apparent [HA,Dec]. */ + iauIr(r); + iauRz(theta+sp, r); + iauRy(-xp, r); + iauRx(-yp, r); + iauRz(elong, r); + +/* Solve for local Earth rotation angle. */ + a = r[0][0]; + b = r[0][1]; + eral = ( a != 0.0 || b != 0.0 ) ? atan2(b, a) : 0.0; + astrom->eral = eral; + +/* Solve for polar motion [X,Y] with respect to local meridian. */ + a = r[0][0]; + c = r[0][2]; + astrom->xpl = atan2(c, sqrt(a*a+b*b)); + a = r[1][2]; + b = r[2][2]; + astrom->ypl = ( a != 0.0 || b != 0.0 ) ? -atan2(a, b) : 0.0; + +/* Adjusted longitude. */ + astrom->along = iauAnpm(eral - theta); + +/* Functions of latitude. */ + astrom->sphi = sin(phi); + astrom->cphi = cos(phi); + +/* Observer's geocentric position and velocity (m, m/s, CIRS). */ + iauPvtob(elong, phi, hm, xp, yp, sp, theta, pv); + +/* Magnitude of diurnal aberration vector. */ + astrom->diurab = sqrt(pv[1][0]*pv[1][0]+pv[1][1]*pv[1][1]) / CMPS; + +/* Refraction constants. */ + astrom->refa = refa; + astrom->refb = refb; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/apio13.c b/src/cpp/3rdparty/sofa/src/apio13.c new file mode 100644 index 000000000..0f9a99745 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/apio13.c @@ -0,0 +1,301 @@ +#include "sofa.h" +#include "sofam.h" + +int iauApio13(double utc1, double utc2, double dut1, + double elong, double phi, double hm, double xp, double yp, + double phpa, double tc, double rh, double wl, + iauASTROM *astrom) +/* +** - - - - - - - - - - +** i a u A p i o 1 3 +** - - - - - - - - - - +** +** For a terrestrial observer, prepare star-independent astrometry +** parameters for transformations between CIRS and observed +** coordinates. The caller supplies UTC, site coordinates, ambient air +** conditions and observing wavelength. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** utc1 double UTC as a 2-part... +** utc2 double ...quasi Julian Date (Notes 1,2) +** dut1 double UT1-UTC (seconds) +** elong double longitude (radians, east +ve, Note 3) +** phi double geodetic latitude (radians, Note 3) +** hm double height above ellipsoid (m, geodetic Notes 4,6) +** xp,yp double polar motion coordinates (radians, Note 5) +** phpa double pressure at the observer (hPa = mB, Note 6) +** tc double ambient temperature at the observer (deg C) +** rh double relative humidity at the observer (range 0-1) +** wl double wavelength (micrometers, Note 7) +** +** Returned: +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double unchanged +** eb double[3] unchanged +** eh double[3] unchanged +** em double unchanged +** v double[3] unchanged +** bm1 double unchanged +** bpn double[3][3] unchanged +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Returned (function value): +** int status: +1 = dubious year (Note 2) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** However, JD cannot unambiguously represent UTC during a leap +** second unless special measures are taken. The convention in the +** present function is that the JD day represents UTC days whether +** the length is 86399, 86400 or 86401 SI seconds. +** +** Applications should use the function iauDtf2d to convert from +** calendar date and time of day into 2-part quasi Julian Date, as +** it implements the leap-second-ambiguity convention just +** described. +** +** 2) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the future +** to be trusted. See iauDat for further details. +** +** 3) UT1-UTC is tabulated in IERS bulletins. It increases by exactly +** one second at the end of each positive UTC leap second, +** introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This +** practice is under review, and in the future UT1-UTC may grow +** essentially without limit. +** +** 4) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the +** longitude required by the present function is east-positive +** (i.e. right-handed), in accordance with geographical convention. +** +** 5) The polar motion xp,yp can be obtained from IERS bulletins. The +** values are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions 2003), measured along the +** meridians 0 and 90 deg west respectively. For many applications, +** xp and yp can be set to zero. +** +** Internally, the polar motion is stored in a form rotated onto +** the local meridian. +** +** 6) If hm, the height above the ellipsoid of the observing station +** in meters, is not known but phpa, the pressure in hPa (=mB), is +** available, an adequate estimate of hm can be obtained from the +** expression +** +** hm = -29.3 * tsl * log ( phpa / 1013.25 ); +** +** where tsl is the approximate sea-level air temperature in K +** (See Astrophysical Quantities, C.W.Allen, 3rd edition, section +** 52). Similarly, if the pressure phpa is not known, it can be +** estimated from the height of the observing station, hm, as +** follows: +** +** phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) ); +** +** Note, however, that the refraction is nearly proportional to the +** pressure and that an accurate phpa value is important for +** precise work. +** +** 7) The argument wl specifies the observing wavelength in +** micrometers. The transition from optical to radio is assumed to +** occur at 100 micrometers (about 3000 GHz). +** +** 8) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** 9) In cases where the caller wishes to supply his own Earth +** rotation information and refraction constants, the function +** iauApc can be used instead of the present function. +** +** 10) This is one of several functions that inserts into the astrom +** structure star-independent parameters needed for the chain of +** astrometric transformations ICRS <-> GCRS <-> CIRS <-> observed. +** +** The various functions support different classes of observer and +** portions of the transformation chain: +** +** functions observer transformation +** +** iauApcg iauApcg13 geocentric ICRS <-> GCRS +** iauApci iauApci13 terrestrial ICRS <-> CIRS +** iauApco iauApco13 terrestrial ICRS <-> observed +** iauApcs iauApcs13 space ICRS <-> GCRS +** iauAper iauAper13 terrestrial update Earth rotation +** iauApio iauApio13 terrestrial CIRS <-> observed +** +** Those with names ending in "13" use contemporary SOFA models to +** compute the various ephemerides. The others accept ephemerides +** supplied by the caller. +** +** The transformation from ICRS to GCRS covers space motion, +** parallax, light deflection, and aberration. From GCRS to CIRS +** comprises frame bias and precession-nutation. From CIRS to +** observed takes account of Earth rotation, polar motion, diurnal +** aberration and parallax (unless subsumed into the ICRS <-> GCRS +** transformation), and atmospheric refraction. +** +** 11) The context structure astrom produced by this function is used +** by iauAtioq and iauAtoiq. +** +** Called: +** iauUtctai UTC to TAI +** iauTaitt TAI to TT +** iauUtcut1 UTC to UT1 +** iauSp00 the TIO locator s', IERS 2000 +** iauEra00 Earth rotation angle, IAU 2000 +** iauRefco refraction constants for given ambient conditions +** iauApio astrometry parameters, CIRS-observed +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + double tai1, tai2, tt1, tt2, ut11, ut12, sp, theta, refa, refb; + + +/* UTC to other time scales. */ + j = iauUtctai(utc1, utc2, &tai1, &tai2); + if ( j < 0 ) return -1; + j = iauTaitt(tai1, tai2, &tt1, &tt2); + j = iauUtcut1(utc1, utc2, dut1, &ut11, &ut12); + if ( j < 0 ) return -1; + +/* TIO locator s'. */ + sp = iauSp00(tt1, tt2); + +/* Earth rotation angle. */ + theta = iauEra00(ut11, ut12); + +/* Refraction constants A and B. */ + iauRefco(phpa, tc, rh, wl, &refa, &refb); + +/* CIRS <-> observed astrometry parameters. */ + iauApio(sp, theta, elong, phi, hm, xp, yp, refa, refb, astrom); + +/* Return any warning status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atcc13.c b/src/cpp/3rdparty/sofa/src/atcc13.c new file mode 100644 index 000000000..bc1c8e212 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atcc13.c @@ -0,0 +1,185 @@ +#include "sofa.h" + +void iauAtcc13(double rc, double dc, + double pr, double pd, double px, double rv, + double date1, double date2, + double *ra, double *da) +/* +** - - - - - - - - - - +** i a u A t c c 1 3 +** - - - - - - - - - - +** +** Transform a star's ICRS catalog entry (epoch J2000.0) into ICRS +** astrometric place. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc double ICRS right ascension at J2000.0 (radians, Note 1) +** dc double ICRS declination at J2000.0 (radians, Note 1) +** pr double RA proper motion (radians/year, Note 2) +** pd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, +ve if receding) +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 3) +** +** Returned: +** ra,da double* ICRS astrometric RA,Dec (radians) +** +** Notes: +** +** 1) Star data for an epoch other than J2000.0 (for example from the +** Hipparcos catalog, which has an epoch of J1991.25) will require a +** preliminary call to iauPmsafe before use. +** +** 2) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** 3) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** Called: +** iauApci13 astrometry parameters, ICRS-CIRS, 2013 +** iauAtccq quick catalog ICRS to astrometric +** +** This revision: 2021 April 18 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Star-independent astrometry parameters */ + iauASTROM astrom; + + double w; + + +/* The transformation parameters. */ + iauApci13(date1, date2, &astrom, &w); + +/* Catalog ICRS (epoch J2000.0) to astrometric. */ + iauAtccq(rc, dc, pr, pd, px, rv, &astrom, ra, da); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atccq.c b/src/cpp/3rdparty/sofa/src/atccq.c new file mode 100644 index 000000000..2908d0445 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atccq.c @@ -0,0 +1,184 @@ +#include "sofa.h" + +void iauAtccq(double rc, double dc, + double pr, double pd, double px, double rv, + iauASTROM *astrom, double *ra, double *da) +/* +** - - - - - - - - - +** i a u A t c c q +** - - - - - - - - - +** +** Quick transformation of a star's ICRS catalog entry (epoch J2000.0) +** into ICRS astrometric place, given precomputed star-independent +** astrometry parameters. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are to be transformed for one date. The +** star-independent parameters can be obtained by calling one of the +** functions iauApci[13], iauApcg[13], iauApco[13] or iauApcs[13]. +** +** If the parallax and proper motions are zero the transformation has +** no effect. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc,dc double ICRS RA,Dec at J2000.0 (radians) +** pr double RA proper motion (radians/year, Note 3) +** pd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, +ve if receding) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Returned: +** ra,da double* ICRS astrometric RA,Dec (radians) +** +** Notes: +** +** 1) All the vectors are with respect to BCRS axes. +** +** 2) Star data for an epoch other than J2000.0 (for example from the +** Hipparcos catalog, which has an epoch of J1991.25) will require a +** preliminary call to iauPmsafe before use. +** +** 3) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** Called: +** iauPmpx proper motion and parallax +** iauC2s p-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** This revision: 2021 April 18 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double p[3], w; + + +/* Proper motion and parallax, giving BCRS coordinate direction. */ + iauPmpx(rc, dc, pr, pd, px, rv, astrom->pmt, astrom->eb, p); + +/* ICRS astrometric RA,Dec. */ + iauC2s(p, &w, da); + *ra = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atci13.c b/src/cpp/3rdparty/sofa/src/atci13.c new file mode 100644 index 000000000..f25d12558 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atci13.c @@ -0,0 +1,200 @@ +#include "sofa.h" + +void iauAtci13(double rc, double dc, + double pr, double pd, double px, double rv, + double date1, double date2, + double *ri, double *di, double *eo) +/* +** - - - - - - - - - - +** i a u A t c i 1 3 +** - - - - - - - - - - +** +** Transform ICRS star data, epoch J2000.0, to CIRS. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc double ICRS right ascension at J2000.0 (radians, Note 1) +** dc double ICRS declination at J2000.0 (radians, Note 1) +** pr double RA proper motion (radians/year, Note 2) +** pd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, +ve if receding) +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 3) +** +** Returned: +** ri,di double* CIRS geocentric RA,Dec (radians) +** eo double* equation of the origins (ERA-GST, Note 5) +** +** Notes: +** +** 1) Star data for an epoch other than J2000.0 (for example from the +** Hipparcos catalog, which has an epoch of J1991.25) will require a +** preliminary call to iauPmsafe before use. +** +** 2) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** 3) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 4) The available accuracy is better than 1 milliarcsecond, limited +** mainly by the precession-nutation model that is used, namely +** IAU 2000A/2006. Very close to solar system bodies, additional +** errors of up to several milliarcseconds can occur because of +** unmodeled light deflection; however, the Sun's contribution is +** taken into account, to first order. The accuracy limitations of +** the SOFA function iauEpv00 (used to compute Earth position and +** velocity) can contribute aberration errors of up to +** 5 microarcseconds. Light deflection at the Sun's limb is +** uncertain at the 0.4 mas level. +** +** 5) Should the transformation to (equinox based) apparent place be +** required rather than (CIO based) intermediate place, subtract the +** equation of the origins from the returned right ascension: +** RA = RI - EO. (The iauAnp function can then be applied, as +** required, to keep the result in the conventional 0-2pi range.) +** +** Called: +** iauApci13 astrometry parameters, ICRS-CIRS, 2013 +** iauAtciq quick ICRS to CIRS +** +** This revision: 2021 April 3 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Star-independent astrometry parameters */ + iauASTROM astrom; + + +/* The transformation parameters. */ + iauApci13(date1, date2, &astrom, eo); + +/* ICRS (epoch J2000.0) to CIRS. */ + iauAtciq(rc, dc, pr, pd, px, rv, &astrom, ri, di); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atciq.c b/src/cpp/3rdparty/sofa/src/atciq.c new file mode 100644 index 000000000..8a4871edd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atciq.c @@ -0,0 +1,193 @@ +#include "sofa.h" + +void iauAtciq(double rc, double dc, + double pr, double pd, double px, double rv, + iauASTROM *astrom, double *ri, double *di) +/* +** - - - - - - - - - +** i a u A t c i q +** - - - - - - - - - +** +** Quick ICRS, epoch J2000.0, to CIRS transformation, given precomputed +** star-independent astrometry parameters. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are to be transformed for one date. The +** star-independent parameters can be obtained by calling one of the +** functions iauApci[13], iauApcg[13], iauApco[13] or iauApcs[13]. +** +** If the parallax and proper motions are zero the iauAtciqz function +** can be used instead. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc,dc double ICRS RA,Dec at J2000.0 (radians, Note 1) +** pr double RA proper motion (radians/year, Note 2) +** pd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, +ve if receding) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Returned: +** ri,di double CIRS RA,Dec (radians) +** +** Notes: +** +** 1) Star data for an epoch other than J2000.0 (for example from the +** Hipparcos catalog, which has an epoch of J1991.25) will require a +** preliminary call to iauPmsafe before use. +** +** 2) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** Called: +** iauPmpx proper motion and parallax +** iauLdsun light deflection by the Sun +** iauAb stellar aberration +** iauRxp product of r-matrix and pv-vector +** iauC2s p-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** This revision: 2021 April 19 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double pco[3], pnat[3], ppr[3], pi[3], w; + + +/* Proper motion and parallax, giving BCRS coordinate direction. */ + iauPmpx(rc, dc, pr, pd, px, rv, astrom->pmt, astrom->eb, pco); + +/* Light deflection by the Sun, giving BCRS natural direction. */ + iauLdsun(pco, astrom->eh, astrom->em, pnat); + +/* Aberration, giving GCRS proper direction. */ + iauAb(pnat, astrom->v, astrom->em, astrom->bm1, ppr); + +/* Bias-precession-nutation, giving CIRS proper direction. */ + iauRxp(astrom->bpn, ppr, pi); + +/* CIRS RA,Dec. */ + iauC2s(pi, &w, di); + *ri = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atciqn.c b/src/cpp/3rdparty/sofa/src/atciqn.c new file mode 100644 index 000000000..9c0da8623 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atciqn.c @@ -0,0 +1,232 @@ +#include "sofa.h" + +void iauAtciqn(double rc, double dc, double pr, double pd, + double px, double rv, iauASTROM *astrom, + int n, iauLDBODY b[], double *ri, double *di) +/* +** - - - - - - - - - - +** i a u A t c i q n +** - - - - - - - - - - +** +** Quick ICRS, epoch J2000.0, to CIRS transformation, given precomputed +** star-independent astrometry parameters plus a list of light- +** deflecting bodies. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are to be transformed for one date. The +** star-independent parameters can be obtained by calling one of the +** functions iauApci[13], iauApcg[13], iauApco[13] or iauApcs[13]. +** +** +** If the only light-deflecting body to be taken into account is the +** Sun, the iauAtciq function can be used instead. If in addition the +** parallax and proper motions are zero, the iauAtciqz function can be +** used. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc,dc double ICRS RA,Dec at J2000.0 (radians) +** pr double RA proper motion (radians/year, Note 3) +** pd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, +ve if receding) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** n int number of bodies (Note 3) +** b iauLDBODY[n] data for each of the n bodies (Notes 3,4): +** bm double mass of the body (solar masses, Note 5) +** dl double deflection limiter (Note 6) +** pv [2][3] barycentric PV of the body (au, au/day) +** +** Returned: +** ri,di double CIRS RA,Dec (radians) +** +** Notes: +** +** 1) Star data for an epoch other than J2000.0 (for example from the +** Hipparcos catalog, which has an epoch of J1991.25) will require a +** preliminary call to iauPmsafe before use. +** +** 2) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** 3) The struct b contains n entries, one for each body to be +** considered. If n = 0, no gravitational light deflection will be +** applied, not even for the Sun. +** +** 4) The struct b should include an entry for the Sun as well as for +** any planet or other body to be taken into account. The entries +** should be in the order in which the light passes the body. +** +** 5) In the entry in the b struct for body i, the mass parameter +** b[i].bm can, as required, be adjusted in order to allow for such +** effects as quadrupole field. +** +** 6) The deflection limiter parameter b[i].dl is phi^2/2, where phi is +** the angular separation (in radians) between star and body at +** which limiting is applied. As phi shrinks below the chosen +** threshold, the deflection is artificially reduced, reaching zero +** for phi = 0. Example values suitable for a terrestrial +** observer, together with masses, are as follows: +** +** body i b[i].bm b[i].dl +** +** Sun 1.0 6e-6 +** Jupiter 0.00095435 3e-9 +** Saturn 0.00028574 3e-10 +** +** 7) For efficiency, validation of the contents of the b array is +** omitted. The supplied masses must be greater than zero, the +** position and velocity vectors must be right, and the deflection +** limiter greater than zero. +** +** Called: +** iauPmpx proper motion and parallax +** iauLdn light deflection by n bodies +** iauAb stellar aberration +** iauRxp product of r-matrix and pv-vector +** iauC2s p-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** This revision: 2021 April 3 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double pco[3], pnat[3], ppr[3], pi[3], w; + + +/* Proper motion and parallax, giving BCRS coordinate direction. */ + iauPmpx(rc, dc, pr, pd, px, rv, astrom->pmt, astrom->eb, pco); + +/* Light deflection, giving BCRS natural direction. */ + iauLdn(n, b, astrom->eb, pco, pnat); + +/* Aberration, giving GCRS proper direction. */ + iauAb(pnat, astrom->v, astrom->em, astrom->bm1, ppr); + +/* Bias-precession-nutation, giving CIRS proper direction. */ + iauRxp(astrom->bpn, ppr, pi); + +/* CIRS RA,Dec. */ + iauC2s(pi, &w, di); + *ri = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atciqz.c b/src/cpp/3rdparty/sofa/src/atciqz.c new file mode 100644 index 000000000..80146db81 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atciqz.c @@ -0,0 +1,194 @@ +#include "sofa.h" + +void iauAtciqz(double rc, double dc, iauASTROM *astrom, + double *ri, double *di) +/* +** - - - - - - - - - - +** i a u A t c i q z +** - - - - - - - - - - +** +** Quick ICRS to CIRS transformation, given precomputed star- +** independent astrometry parameters, and assuming zero parallax and +** proper motion. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are to be transformed for one date. The +** star-independent parameters can be obtained by calling one of the +** functions iauApci[13], iauApcg[13], iauApco[13] or iauApcs[13]. +** +** The corresponding function for the case of non-zero parallax and +** proper motion is iauAtciq. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc,dc double ICRS astrometric RA,Dec (radians) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Returned: +** ri,di double CIRS RA,Dec (radians) +** +** Note: +** +** All the vectors are with respect to BCRS axes. +** +** References: +** +** Urban, S. & Seidelmann, P. K. (eds), Explanatory Supplement to +** the Astronomical Almanac, 3rd ed., University Science Books +** (2013). +** +** Klioner, Sergei A., "A practical relativistic model for micro- +** arcsecond astrometry in space", Astr. J. 125, 1580-1597 (2003). +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauLdsun light deflection due to Sun +** iauAb stellar aberration +** iauRxp product of r-matrix and p-vector +** iauC2s p-vector to spherical +** iauAnp normalize angle into range +/- pi +** +** This revision: 2013 October 9 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double pco[3], pnat[3], ppr[3], pi[3], w; + + +/* BCRS coordinate direction (unit vector). */ + iauS2c(rc, dc, pco); + +/* Light deflection by the Sun, giving BCRS natural direction. */ + iauLdsun(pco, astrom->eh, astrom->em, pnat); + +/* Aberration, giving GCRS proper direction. */ + iauAb(pnat, astrom->v, astrom->em, astrom->bm1, ppr); + +/* Bias-precession-nutation, giving CIRS proper direction. */ + iauRxp(astrom->bpn, ppr, pi); + +/* CIRS RA,Dec. */ + iauC2s(pi, &w, di); + *ri = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atco13.c b/src/cpp/3rdparty/sofa/src/atco13.c new file mode 100644 index 000000000..291d9f739 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atco13.c @@ -0,0 +1,285 @@ +#include "sofa.h" +#include "sofam.h" + +int iauAtco13(double rc, double dc, + double pr, double pd, double px, double rv, + double utc1, double utc2, double dut1, + double elong, double phi, double hm, double xp, double yp, + double phpa, double tc, double rh, double wl, + double *aob, double *zob, double *hob, + double *dob, double *rob, double *eo) +/* +** - - - - - - - - - - +** i a u A t c o 1 3 +** - - - - - - - - - - +** +** ICRS RA,Dec to observed place. The caller supplies UTC, site +** coordinates, ambient air conditions and observing wavelength. +** +** SOFA models are used for the Earth ephemeris, bias-precession- +** nutation, Earth orientation and refraction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc,dc double ICRS right ascension at J2000.0 (radians, Note 1) +** pr double RA proper motion (radians/year, Note 2) +** pd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, +ve if receding) +** utc1 double UTC as a 2-part... +** utc2 double ...quasi Julian Date (Notes 3-4) +** dut1 double UT1-UTC (seconds, Note 5) +** elong double longitude (radians, east +ve, Note 6) +** phi double latitude (geodetic, radians, Note 6) +** hm double height above ellipsoid (m, geodetic, Notes 6,8) +** xp,yp double polar motion coordinates (radians, Note 7) +** phpa double pressure at the observer (hPa = mB, Note 8) +** tc double ambient temperature at the observer (deg C) +** rh double relative humidity at the observer (range 0-1) +** wl double wavelength (micrometers, Note 9) +** +** Returned: +** aob double* observed azimuth (radians: N=0,E=90) +** zob double* observed zenith distance (radians) +** hob double* observed hour angle (radians) +** dob double* observed declination (radians) +** rob double* observed right ascension (CIO-based, radians) +** eo double* equation of the origins (ERA-GST) +** +** Returned (function value): +** int status: +1 = dubious year (Note 4) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) Star data for an epoch other than J2000.0 (for example from the +** Hipparcos catalog, which has an epoch of J1991.25) will require +** a preliminary call to iauPmsafe before use. +** +** 2) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** 3) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** However, JD cannot unambiguously represent UTC during a leap +** second unless special measures are taken. The convention in the +** present function is that the JD day represents UTC days whether +** the length is 86399, 86400 or 86401 SI seconds. +** +** Applications should use the function iauDtf2d to convert from +** calendar date and time of day into 2-part quasi Julian Date, as +** it implements the leap-second-ambiguity convention just +** described. +** +** 4) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the +** future to be trusted. See iauDat for further details. +** +** 5) UT1-UTC is tabulated in IERS bulletins. It increases by exactly +** one second at the end of each positive UTC leap second, +** introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This +** practice is under review, and in the future UT1-UTC may grow +** essentially without limit. +** +** 6) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the +** longitude required by the present function is east-positive +** (i.e. right-handed), in accordance with geographical convention. +** +** 7) The polar motion xp,yp can be obtained from IERS bulletins. The +** values are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions 2003), measured along the +** meridians 0 and 90 deg west respectively. For many +** applications, xp and yp can be set to zero. +** +** 8) If hm, the height above the ellipsoid of the observing station +** in meters, is not known but phpa, the pressure in hPa (=mB), +** is available, an adequate estimate of hm can be obtained from +** the expression +** +** hm = -29.3 * tsl * log ( phpa / 1013.25 ); +** +** where tsl is the approximate sea-level air temperature in K +** (See Astrophysical Quantities, C.W.Allen, 3rd edition, section +** 52). Similarly, if the pressure phpa is not known, it can be +** estimated from the height of the observing station, hm, as +** follows: +** +** phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) ); +** +** Note, however, that the refraction is nearly proportional to +** the pressure and that an accurate phpa value is important for +** precise work. +** +** 9) The argument wl specifies the observing wavelength in +** micrometers. The transition from optical to radio is assumed to +** occur at 100 micrometers (about 3000 GHz). +** +** 10) The accuracy of the result is limited by the corrections for +** refraction, which use a simple A*tan(z) + B*tan^3(z) model. +** Providing the meteorological parameters are known accurately and +** there are no gross local effects, the predicted observed +** coordinates should be within 0.05 arcsec (optical) or 1 arcsec +** (radio) for a zenith distance of less than 70 degrees, better +** than 30 arcsec (optical or radio) at 85 degrees and better +** than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. +** +** Without refraction, the complementary functions iauAtco13 and +** iauAtoc13 are self-consistent to better than 1 microarcsecond +** all over the celestial sphere. With refraction included, +** consistency falls off at high zenith distances, but is still +** better than 0.05 arcsec at 85 degrees. +** +** 11) "Observed" Az,ZD means the position that would be seen by a +** perfect geodetically aligned theodolite. (Zenith distance is +** used rather than altitude in order to reflect the fact that no +** allowance is made for depression of the horizon.) This is +** related to the observed HA,Dec via the standard rotation, using +** the geodetic latitude (corrected for polar motion), while the +** observed HA and RA are related simply through the Earth rotation +** angle and the site longitude. "Observed" RA,Dec or HA,Dec thus +** means the position that would be seen by a perfect equatorial +** with its polar axis aligned to the Earth's axis of rotation. +** +** 12) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** Called: +** iauApco13 astrometry parameters, ICRS-observed, 2013 +** iauAtciq quick ICRS to CIRS +** iauAtioq quick CIRS to observed +** +** This revision: 2021 April 3 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + iauASTROM astrom; + double ri, di; + + +/* Star-independent astrometry parameters. */ + j = iauApco13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom, eo); + +/* Abort if bad UTC. */ + if ( j < 0 ) return j; + +/* Transform ICRS to CIRS. */ + iauAtciq(rc, dc, pr, pd, px, rv, &astrom, &ri, &di); + +/* Transform CIRS to observed. */ + iauAtioq(ri, di, &astrom, aob, zob, hob, dob, rob); + +/* Return OK/warning status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atic13.c b/src/cpp/3rdparty/sofa/src/atic13.c new file mode 100644 index 000000000..4e810536e --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atic13.c @@ -0,0 +1,193 @@ +#include "sofa.h" + +void iauAtic13(double ri, double di, double date1, double date2, + double *rc, double *dc, double *eo) +/* +** - - - - - - - - - - +** i a u A t i c 1 3 +** - - - - - - - - - - +** +** Transform star RA,Dec from geocentric CIRS to ICRS astrometric. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ri,di double CIRS geocentric RA,Dec (radians) +** date1 double TDB as a 2-part... +** date2 double ...Julian Date (Note 1) +** +** Returned: +** rc,dc double ICRS astrometric RA,Dec (radians) +** eo double equation of the origins (ERA-GST, Note 4) +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. For most +** applications of this function the choice will not be at all +** critical. +** +** TT can be used instead of TDB without any significant impact on +** accuracy. +** +** 2) Iterative techniques are used for the aberration and light +** deflection corrections so that the functions iauAtic13 (or +** iauAticq) and iauAtci13 (or iauAtciq) are accurate inverses; +** even at the edge of the Sun's disk the discrepancy is only about +** 1 nanoarcsecond. +** +** 3) The available accuracy is better than 1 milliarcsecond, limited +** mainly by the precession-nutation model that is used, namely +** IAU 2000A/2006. Very close to solar system bodies, additional +** errors of up to several milliarcseconds can occur because of +** unmodeled light deflection; however, the Sun's contribution is +** taken into account, to first order. The accuracy limitations of +** the SOFA function iauEpv00 (used to compute Earth position and +** velocity) can contribute aberration errors of up to +** 5 microarcseconds. Light deflection at the Sun's limb is +** uncertain at the 0.4 mas level. +** +** 4) Should the transformation to (equinox based) J2000.0 mean place +** be required rather than (CIO based) ICRS coordinates, subtract the +** equation of the origins from the returned right ascension: +** RA = RI - EO. (The iauAnp function can then be applied, as +** required, to keep the result in the conventional 0-2pi range.) +** +** Called: +** iauApci13 astrometry parameters, ICRS-CIRS, 2013 +** iauAticq quick CIRS to ICRS astrometric +** +** This revision: 2013 October 9 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Star-independent astrometry parameters */ + iauASTROM astrom; + + +/* Star-independent astrometry parameters. */ + iauApci13(date1, date2, &astrom, eo); + +/* CIRS to ICRS astrometric. */ + iauAticq(ri, di, &astrom, rc, dc); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/aticq.c b/src/cpp/3rdparty/sofa/src/aticq.c new file mode 100644 index 000000000..6a1544f8c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/aticq.c @@ -0,0 +1,240 @@ +#include "sofa.h" + +void iauAticq(double ri, double di, iauASTROM *astrom, + double *rc, double *dc) +/* +** - - - - - - - - - +** i a u A t i c q +** - - - - - - - - - +** +** Quick CIRS RA,Dec to ICRS astrometric place, given the star- +** independent astrometry parameters. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are all to be transformed for one date. +** The star-independent astrometry parameters can be obtained by +** calling one of the functions iauApci[13], iauApcg[13], iauApco[13] +** or iauApcs[13]. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ri,di double CIRS RA,Dec (radians) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Returned: +** rc,dc double ICRS astrometric RA,Dec (radians) +** +** Notes: +** +** 1) Only the Sun is taken into account in the light deflection +** correction. +** +** 2) Iterative techniques are used for the aberration and light +** deflection corrections so that the functions iauAtic13 (or +** iauAticq) and iauAtci13 (or iauAtciq) are accurate inverses; +** even at the edge of the Sun's disk the discrepancy is only about +** 1 nanoarcsecond. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauTrxp product of transpose of r-matrix and p-vector +** iauZp zero p-vector +** iauAb stellar aberration +** iauLdsun light deflection by the Sun +** iauC2s p-vector to spherical +** iauAnp normalize angle into range +/- pi +** +** This revision: 2013 October 9 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j, i; + double pi[3], ppr[3], pnat[3], pco[3], w, d[3], before[3], r2, r, + after[3]; + + +/* CIRS RA,Dec to Cartesian. */ + iauS2c(ri, di, pi); + +/* Bias-precession-nutation, giving GCRS proper direction. */ + iauTrxp(astrom->bpn, pi, ppr); + +/* Aberration, giving GCRS natural direction. */ + iauZp(d); + for (j = 0; j < 2; j++) { + r2 = 0.0; + for (i = 0; i < 3; i++) { + w = ppr[i] - d[i]; + before[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + before[i] /= r; + } + iauAb(before, astrom->v, astrom->em, astrom->bm1, after); + r2 = 0.0; + for (i = 0; i < 3; i++) { + d[i] = after[i] - before[i]; + w = ppr[i] - d[i]; + pnat[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + pnat[i] /= r; + } + } + +/* Light deflection by the Sun, giving BCRS coordinate direction. */ + iauZp(d); + for (j = 0; j < 5; j++) { + r2 = 0.0; + for (i = 0; i < 3; i++) { + w = pnat[i] - d[i]; + before[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + before[i] /= r; + } + iauLdsun(before, astrom->eh, astrom->em, after); + r2 = 0.0; + for (i = 0; i < 3; i++) { + d[i] = after[i] - before[i]; + w = pnat[i] - d[i]; + pco[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + pco[i] /= r; + } + } + +/* ICRS astrometric RA,Dec. */ + iauC2s(pco, &w, dc); + *rc = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/aticqn.c b/src/cpp/3rdparty/sofa/src/aticqn.c new file mode 100644 index 000000000..9e48cabdb --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/aticqn.c @@ -0,0 +1,278 @@ +#include "sofa.h" + +void iauAticqn(double ri, double di, iauASTROM *astrom, + int n, iauLDBODY b[], double *rc, double *dc) +/* +** - - - - - - - - - - +** i a u A t i c q n +** - - - - - - - - - - +** +** Quick CIRS to ICRS astrometric place transformation, given the star- +** independent astrometry parameters plus a list of light-deflecting +** bodies. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are all to be transformed for one date. +** The star-independent astrometry parameters can be obtained by +** calling one of the functions iauApci[13], iauApcg[13], iauApco[13] +** or iauApcs[13]. +* +* If the only light-deflecting body to be taken into account is the +* Sun, the iauAticq function can be used instead. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ri,di double CIRS RA,Dec (radians) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** n int number of bodies (Note 3) +** b iauLDBODY[n] data for each of the n bodies (Notes 3,4): +** bm double mass of the body (solar masses, Note 5) +** dl double deflection limiter (Note 6) +** pv [2][3] barycentric PV of the body (au, au/day) +** +** Returned: +** rc,dc double ICRS astrometric RA,Dec (radians) +** +** Notes: +** +** 1) Iterative techniques are used for the aberration and light +** deflection corrections so that the functions iauAticqn and +** iauAtciqn are accurate inverses; even at the edge of the Sun's +** disk the discrepancy is only about 1 nanoarcsecond. +** +** 2) If the only light-deflecting body to be taken into account is the +** Sun, the iauAticq function can be used instead. +** +** 3) The struct b contains n entries, one for each body to be +** considered. If n = 0, no gravitational light deflection will be +** applied, not even for the Sun. +** +** 4) The struct b should include an entry for the Sun as well as for +** any planet or other body to be taken into account. The entries +** should be in the order in which the light passes the body. +** +** 5) In the entry in the b struct for body i, the mass parameter +** b[i].bm can, as required, be adjusted in order to allow for such +** effects as quadrupole field. +** +** 6) The deflection limiter parameter b[i].dl is phi^2/2, where phi is +** the angular separation (in radians) between star and body at +** which limiting is applied. As phi shrinks below the chosen +** threshold, the deflection is artificially reduced, reaching zero +** for phi = 0. Example values suitable for a terrestrial +** observer, together with masses, are as follows: +** +** body i b[i].bm b[i].dl +** +** Sun 1.0 6e-6 +** Jupiter 0.00095435 3e-9 +** Saturn 0.00028574 3e-10 +** +** 7) For efficiency, validation of the contents of the b array is +** omitted. The supplied masses must be greater than zero, the +** position and velocity vectors must be right, and the deflection +** limiter greater than zero. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauTrxp product of transpose of r-matrix and p-vector +** iauZp zero p-vector +** iauAb stellar aberration +** iauLdn light deflection by n bodies +** iauC2s p-vector to spherical +** iauAnp normalize angle into range +/- pi +** +** This revision: 2021 January 6 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j, i; + double pi[3], ppr[3], pnat[3], pco[3], w, d[3], before[3], r2, r, + after[3]; + + +/* CIRS RA,Dec to Cartesian. */ + iauS2c(ri, di, pi); + +/* Bias-precession-nutation, giving GCRS proper direction. */ + iauTrxp(astrom->bpn, pi, ppr); + +/* Aberration, giving GCRS natural direction. */ + iauZp(d); + for (j = 0; j < 2; j++) { + r2 = 0.0; + for (i = 0; i < 3; i++) { + w = ppr[i] - d[i]; + before[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + before[i] /= r; + } + iauAb(before, astrom->v, astrom->em, astrom->bm1, after); + r2 = 0.0; + for (i = 0; i < 3; i++) { + d[i] = after[i] - before[i]; + w = ppr[i] - d[i]; + pnat[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + pnat[i] /= r; + } + } + +/* Light deflection, giving BCRS coordinate direction. */ + iauZp(d); + for (j = 0; j < 5; j++) { + r2 = 0.0; + for (i = 0; i < 3; i++) { + w = pnat[i] - d[i]; + before[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + before[i] /= r; + } + iauLdn(n, b, astrom->eb, before, after); + r2 = 0.0; + for (i = 0; i < 3; i++) { + d[i] = after[i] - before[i]; + w = pnat[i] - d[i]; + pco[i] = w; + r2 += w*w; + } + r = sqrt(r2); + for (i = 0; i < 3; i++) { + pco[i] /= r; + } + } + +/* ICRS astrometric RA,Dec. */ + iauC2s(pco, &w, dc); + *rc = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atio13.c b/src/cpp/3rdparty/sofa/src/atio13.c new file mode 100644 index 000000000..1debc877f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atio13.c @@ -0,0 +1,264 @@ +#include "sofa.h" +#include "sofam.h" + +int iauAtio13(double ri, double di, + double utc1, double utc2, double dut1, + double elong, double phi, double hm, double xp, double yp, + double phpa, double tc, double rh, double wl, + double *aob, double *zob, double *hob, + double *dob, double *rob) +/* +** - - - - - - - - - - +** i a u A t i o 1 3 +** - - - - - - - - - - +** +** CIRS RA,Dec to observed place. The caller supplies UTC, site +** coordinates, ambient air conditions and observing wavelength. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ri double CIRS right ascension (CIO-based, radians) +** di double CIRS declination (radians) +** utc1 double UTC as a 2-part... +** utc2 double ...quasi Julian Date (Notes 1,2) +** dut1 double UT1-UTC (seconds, Note 3) +** elong double longitude (radians, east +ve, Note 4) +** phi double geodetic latitude (radians, Note 4) +** hm double height above ellipsoid (m, geodetic Notes 4,6) +** xp,yp double polar motion coordinates (radians, Note 5) +** phpa double pressure at the observer (hPa = mB, Note 6) +** tc double ambient temperature at the observer (deg C) +** rh double relative humidity at the observer (range 0-1) +** wl double wavelength (micrometers, Note 7) +** +** Returned: +** aob double* observed azimuth (radians: N=0,E=90) +** zob double* observed zenith distance (radians) +** hob double* observed hour angle (radians) +** dob double* observed declination (radians) +** rob double* observed right ascension (CIO-based, radians) +** +** Returned (function value): +** int status: +1 = dubious year (Note 2) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** However, JD cannot unambiguously represent UTC during a leap +** second unless special measures are taken. The convention in the +** present function is that the JD day represents UTC days whether +** the length is 86399, 86400 or 86401 SI seconds. +** +** Applications should use the function iauDtf2d to convert from +** calendar date and time of day into 2-part quasi Julian Date, as +** it implements the leap-second-ambiguity convention just +** described. +** +** 2) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the +** future to be trusted. See iauDat for further details. +** +** 3) UT1-UTC is tabulated in IERS bulletins. It increases by exactly +** one second at the end of each positive UTC leap second, +** introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This +** practice is under review, and in the future UT1-UTC may grow +** essentially without limit. +** +** 4) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the +** longitude required by the present function is east-positive +** (i.e. right-handed), in accordance with geographical convention. +** +** 5) The polar motion xp,yp can be obtained from IERS bulletins. The +** values are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions 2003), measured along the +** meridians 0 and 90 deg west respectively. For many +** applications, xp and yp can be set to zero. +** +** 6) If hm, the height above the ellipsoid of the observing station +** in meters, is not known but phpa, the pressure in hPa (=mB), is +** available, an adequate estimate of hm can be obtained from the +** expression +** +** hm = -29.3 * tsl * log ( phpa / 1013.25 ); +** +** where tsl is the approximate sea-level air temperature in K +** (See Astrophysical Quantities, C.W.Allen, 3rd edition, section +** 52). Similarly, if the pressure phpa is not known, it can be +** estimated from the height of the observing station, hm, as +** follows: +** +** phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) ); +** +** Note, however, that the refraction is nearly proportional to +** the pressure and that an accurate phpa value is important for +** precise work. +** +** 7) The argument wl specifies the observing wavelength in +** micrometers. The transition from optical to radio is assumed to +** occur at 100 micrometers (about 3000 GHz). +** +** 8) "Observed" Az,ZD means the position that would be seen by a +** perfect geodetically aligned theodolite. (Zenith distance is +** used rather than altitude in order to reflect the fact that no +** allowance is made for depression of the horizon.) This is +** related to the observed HA,Dec via the standard rotation, using +** the geodetic latitude (corrected for polar motion), while the +** observed HA and RA are related simply through the Earth rotation +** angle and the site longitude. "Observed" RA,Dec or HA,Dec thus +** means the position that would be seen by a perfect equatorial +** with its polar axis aligned to the Earth's axis of rotation. +** +** 9) The accuracy of the result is limited by the corrections for +** refraction, which use a simple A*tan(z) + B*tan^3(z) model. +** Providing the meteorological parameters are known accurately and +** there are no gross local effects, the predicted astrometric +** coordinates should be within 0.05 arcsec (optical) or 1 arcsec +** (radio) for a zenith distance of less than 70 degrees, better +** than 30 arcsec (optical or radio) at 85 degrees and better +** than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. +** +** 10) The complementary functions iauAtio13 and iauAtoi13 are self- +** consistent to better than 1 microarcsecond all over the +** celestial sphere. +** +** 11) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** Called: +** iauApio13 astrometry parameters, CIRS-observed, 2013 +** iauAtioq quick CIRS to observed +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + iauASTROM astrom; + + +/* Star-independent astrometry parameters for CIRS->observed. */ + j = iauApio13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom); + +/* Abort if bad UTC. */ + if ( j < 0 ) return j; + +/* Transform CIRS to observed. */ + iauAtioq(ri, di, &astrom, aob, zob, hob, dob, rob); + +/* Return OK/warning status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atioq.c b/src/cpp/3rdparty/sofa/src/atioq.c new file mode 100644 index 000000000..0f34ffe80 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atioq.c @@ -0,0 +1,288 @@ +#include "sofa.h" + +void iauAtioq(double ri, double di, iauASTROM *astrom, + double *aob, double *zob, + double *hob, double *dob, double *rob) +/* +** - - - - - - - - - +** i a u A t i o q +** - - - - - - - - - +** +** Quick CIRS to observed place transformation. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are all to be transformed for one date. +** The star-independent astrometry parameters can be obtained by +** calling iauApio[13] or iauApco[13]. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ri double CIRS right ascension +** di double CIRS declination +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Returned: +** aob double* observed azimuth (radians: N=0,E=90) +** zob double* observed zenith distance (radians) +** hob double* observed hour angle (radians) +** dob double* observed declination (radians) +** rob double* observed right ascension (CIO-based, radians) +** +** Notes: +** +** 1) This function returns zenith distance rather than altitude in +** order to reflect the fact that no allowance is made for +** depression of the horizon. +** +** 2) The accuracy of the result is limited by the corrections for +** refraction, which use a simple A*tan(z) + B*tan^3(z) model. +** Providing the meteorological parameters are known accurately and +** there are no gross local effects, the predicted observed +** coordinates should be within 0.05 arcsec (optical) or 1 arcsec +** (radio) for a zenith distance of less than 70 degrees, better +** than 30 arcsec (optical or radio) at 85 degrees and better +** than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. +** +** Without refraction, the complementary functions iauAtioq and +** iauAtoiq are self-consistent to better than 1 microarcsecond all +** over the celestial sphere. With refraction included, consistency +** falls off at high zenith distances, but is still better than +** 0.05 arcsec at 85 degrees. +** +** 3) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** 4) The CIRS RA,Dec is obtained from a star catalog mean place by +** allowing for space motion, parallax, the Sun's gravitational lens +** effect, annual aberration and precession-nutation. For star +** positions in the ICRS, these effects can be applied by means of +** the iauAtci13 (etc.) functions. Starting from classical "mean +** place" systems, additional transformations will be needed first. +** +** 5) "Observed" Az,El means the position that would be seen by a +** perfect geodetically aligned theodolite. This is obtained from +** the CIRS RA,Dec by allowing for Earth orientation and diurnal +** aberration, rotating from equator to horizon coordinates, and +** then adjusting for refraction. The HA,Dec is obtained by +** rotating back into equatorial coordinates, and is the position +** that would be seen by a perfect equatorial with its polar axis +** aligned to the Earth's axis of rotation. Finally, the RA is +** obtained by subtracting the HA from the local ERA. +** +** 6) The star-independent CIRS-to-observed-place parameters in ASTROM +** may be computed with iauApio[13] or iauApco[13]. If nothing has +** changed significantly except the time, iauAper[13] may be used to +** perform the requisite adjustment to the astrom structure. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauC2s p-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** This revision: 2020 December 7 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Minimum cos(alt) and sin(alt) for refraction purposes */ + const double CELMIN = 1e-6; + const double SELMIN = 0.05; + + double v[3], x, y, z, sx, cx, sy, cy, xhd, yhd, zhd, f, + xhdt, yhdt, zhdt, xaet, yaet, zaet, azobs, r, tz, w, del, + cosdel, xaeo, yaeo, zaeo, zdobs, hmobs, dcobs, raobs; + + +/* CIRS RA,Dec to Cartesian -HA,Dec. */ + iauS2c(ri-astrom->eral, di, v); + x = v[0]; + y = v[1]; + z = v[2]; + +/* Polar motion. */ + sx = sin(astrom->xpl); + cx = cos(astrom->xpl); + sy = sin(astrom->ypl); + cy = cos(astrom->ypl); + xhd = cx*x + sx*z; + yhd = sx*sy*x + cy*y - cx*sy*z; + zhd = -sx*cy*x + sy*y + cx*cy*z; + +/* Diurnal aberration. */ + f = ( 1.0 - astrom->diurab*yhd ); + xhdt = f * xhd; + yhdt = f * ( yhd + astrom->diurab ); + zhdt = f * zhd; + +/* Cartesian -HA,Dec to Cartesian Az,El (S=0,E=90). */ + xaet = astrom->sphi*xhdt - astrom->cphi*zhdt; + yaet = yhdt; + zaet = astrom->cphi*xhdt + astrom->sphi*zhdt; + +/* Azimuth (N=0,E=90). */ + azobs = ( xaet != 0.0 || yaet != 0.0 ) ? atan2(yaet,-xaet) : 0.0; + +/* ---------- */ +/* Refraction */ +/* ---------- */ + +/* Cosine and sine of altitude, with precautions. */ + r = sqrt(xaet*xaet + yaet*yaet); + r = r > CELMIN ? r : CELMIN; + z = zaet > SELMIN ? zaet : SELMIN; + +/* A*tan(z)+B*tan^3(z) model, with Newton-Raphson correction. */ + tz = r/z; + w = astrom->refb*tz*tz; + del = ( astrom->refa + w ) * tz / + ( 1.0 + ( astrom->refa + 3.0*w ) / ( z*z ) ); + +/* Apply the change, giving observed vector. */ + cosdel = 1.0 - del*del/2.0; + f = cosdel - del*z/r; + xaeo = xaet*f; + yaeo = yaet*f; + zaeo = cosdel*zaet + del*r; + +/* Observed ZD. */ + zdobs = atan2(sqrt(xaeo*xaeo+yaeo*yaeo), zaeo); + +/* Az/El vector to HA,Dec vector (both right-handed). */ + v[0] = astrom->sphi*xaeo + astrom->cphi*zaeo; + v[1] = yaeo; + v[2] = - astrom->cphi*xaeo + astrom->sphi*zaeo; + +/* To spherical -HA,Dec. */ + iauC2s ( v, &hmobs, &dcobs ); + +/* Right ascension (with respect to CIO). */ + raobs = astrom->eral + hmobs; + +/* Return the results. */ + *aob = iauAnp(azobs); + *zob = zdobs; + *hob = -hmobs; + *dob = dcobs; + *rob = iauAnp(raobs); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atoc13.c b/src/cpp/3rdparty/sofa/src/atoc13.c new file mode 100644 index 000000000..b49a309b7 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atoc13.c @@ -0,0 +1,275 @@ +#include "sofa.h" +#include "sofam.h" + +int iauAtoc13(const char *type, double ob1, double ob2, + double utc1, double utc2, double dut1, + double elong, double phi, double hm, double xp, double yp, + double phpa, double tc, double rh, double wl, + double *rc, double *dc) +/* +** - - - - - - - - - - +** i a u A t o c 1 3 +** - - - - - - - - - - +** +** Observed place at a groundbased site to to ICRS astrometric RA,Dec. +** The caller supplies UTC, site coordinates, ambient air conditions +** and observing wavelength. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** type char[] type of coordinates - "R", "H" or "A" (Notes 1,2) +** ob1 double observed Az, HA or RA (radians; Az is N=0,E=90) +** ob2 double observed ZD or Dec (radians) +** utc1 double UTC as a 2-part... +** utc2 double ...quasi Julian Date (Notes 3,4) +** dut1 double UT1-UTC (seconds, Note 5) +** elong double longitude (radians, east +ve, Note 6) +** phi double geodetic latitude (radians, Note 6) +** hm double height above ellipsoid (m, geodetic Notes 6,8) +** xp,yp double polar motion coordinates (radians, Note 7) +** phpa double pressure at the observer (hPa = mB, Note 8) +** tc double ambient temperature at the observer (deg C) +** rh double relative humidity at the observer (range 0-1) +** wl double wavelength (micrometers, Note 9) +** +** Returned: +** rc,dc double ICRS astrometric RA,Dec (radians) +** +** Returned (function value): +** int status: +1 = dubious year (Note 4) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) "Observed" Az,ZD means the position that would be seen by a +** perfect geodetically aligned theodolite. (Zenith distance is +** used rather than altitude in order to reflect the fact that no +** allowance is made for depression of the horizon.) This is +** related to the observed HA,Dec via the standard rotation, using +** the geodetic latitude (corrected for polar motion), while the +** observed HA and RA are related simply through the Earth rotation +** angle and the site longitude. "Observed" RA,Dec or HA,Dec thus +** means the position that would be seen by a perfect equatorial +** with its polar axis aligned to the Earth's axis of rotation. +** +** 2) Only the first character of the type argument is significant. +** "R" or "r" indicates that ob1 and ob2 are the observed right +** ascension and declination; "H" or "h" indicates that they are +** hour angle (west +ve) and declination; anything else ("A" or +** "a" is recommended) indicates that ob1 and ob2 are azimuth +** (north zero, east 90 deg) and zenith distance. +** +** 3) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** However, JD cannot unambiguously represent UTC during a leap +** second unless special measures are taken. The convention in the +** present function is that the JD day represents UTC days whether +** the length is 86399, 86400 or 86401 SI seconds. +** +** Applications should use the function iauDtf2d to convert from +** calendar date and time of day into 2-part quasi Julian Date, as +** it implements the leap-second-ambiguity convention just +** described. +** +** 4) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the +** future to be trusted. See iauDat for further details. +** +** 5) UT1-UTC is tabulated in IERS bulletins. It increases by exactly +** one second at the end of each positive UTC leap second, +** introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This +** practice is under review, and in the future UT1-UTC may grow +** essentially without limit. +** +** 6) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the +** longitude required by the present function is east-positive +** (i.e. right-handed), in accordance with geographical convention. +** +** 7) The polar motion xp,yp can be obtained from IERS bulletins. The +** values are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions 2003), measured along the +** meridians 0 and 90 deg west respectively. For many +** applications, xp and yp can be set to zero. +** +** 8) If hm, the height above the ellipsoid of the observing station +** in meters, is not known but phpa, the pressure in hPa (=mB), is +** available, an adequate estimate of hm can be obtained from the +** expression +** +** hm = -29.3 * tsl * log ( phpa / 1013.25 ); +** +** where tsl is the approximate sea-level air temperature in K +** (See Astrophysical Quantities, C.W.Allen, 3rd edition, section +** 52). Similarly, if the pressure phpa is not known, it can be +** estimated from the height of the observing station, hm, as +** follows: +** +** phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) ); +** +** Note, however, that the refraction is nearly proportional to +** the pressure and that an accurate phpa value is important for +** precise work. +** +** 9) The argument wl specifies the observing wavelength in +** micrometers. The transition from optical to radio is assumed to +** occur at 100 micrometers (about 3000 GHz). +** +** 10) The accuracy of the result is limited by the corrections for +** refraction, which use a simple A*tan(z) + B*tan^3(z) model. +** Providing the meteorological parameters are known accurately and +** there are no gross local effects, the predicted astrometric +** coordinates should be within 0.05 arcsec (optical) or 1 arcsec +** (radio) for a zenith distance of less than 70 degrees, better +** than 30 arcsec (optical or radio) at 85 degrees and better +** than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. +** +** Without refraction, the complementary functions iauAtco13 and +** iauAtoc13 are self-consistent to better than 1 microarcsecond +** all over the celestial sphere. With refraction included, +** consistency falls off at high zenith distances, but is still +** better than 0.05 arcsec at 85 degrees. +** +** 11) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** Called: +** iauApco13 astrometry parameters, ICRS-observed +** iauAtoiq quick observed to CIRS +** iauAticq quick CIRS to ICRS +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + iauASTROM astrom; + double eo, ri, di; + + +/* Star-independent astrometry parameters. */ + j = iauApco13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom, &eo); + +/* Abort if bad UTC. */ + if ( j < 0 ) return j; + +/* Transform observed to CIRS. */ + iauAtoiq(type, ob1, ob2, &astrom, &ri, &di); + +/* Transform CIRS to ICRS. */ + iauAticq(ri, di, &astrom, rc, dc); + +/* Return OK/warning status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atoi13.c b/src/cpp/3rdparty/sofa/src/atoi13.c new file mode 100644 index 000000000..e9de3a818 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atoi13.c @@ -0,0 +1,270 @@ +#include "sofa.h" +#include "sofam.h" + +int iauAtoi13(const char *type, double ob1, double ob2, + double utc1, double utc2, double dut1, + double elong, double phi, double hm, double xp, double yp, + double phpa, double tc, double rh, double wl, + double *ri, double *di) +/* +** - - - - - - - - - - +** i a u A t o i 1 3 +** - - - - - - - - - - +** +** Observed place to CIRS. The caller supplies UTC, site coordinates, +** ambient air conditions and observing wavelength. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** type char[] type of coordinates - "R", "H" or "A" (Notes 1,2) +** ob1 double observed Az, HA or RA (radians; Az is N=0,E=90) +** ob2 double observed ZD or Dec (radians) +** utc1 double UTC as a 2-part... +** utc2 double ...quasi Julian Date (Notes 3,4) +** dut1 double UT1-UTC (seconds, Note 5) +** elong double longitude (radians, east +ve, Note 6) +** phi double geodetic latitude (radians, Note 6) +** hm double height above the ellipsoid (meters, Notes 6,8) +** xp,yp double polar motion coordinates (radians, Note 7) +** phpa double pressure at the observer (hPa = mB, Note 8) +** tc double ambient temperature at the observer (deg C) +** rh double relative humidity at the observer (range 0-1) +** wl double wavelength (micrometers, Note 9) +** +** Returned: +** ri double* CIRS right ascension (CIO-based, radians) +** di double* CIRS declination (radians) +** +** Returned (function value): +** int status: +1 = dubious year (Note 2) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) "Observed" Az,ZD means the position that would be seen by a +** perfect geodetically aligned theodolite. (Zenith distance is +** used rather than altitude in order to reflect the fact that no +** allowance is made for depression of the horizon.) This is +** related to the observed HA,Dec via the standard rotation, using +** the geodetic latitude (corrected for polar motion), while the +** observed HA and RA are related simply through the Earth rotation +** angle and the site longitude. "Observed" RA,Dec or HA,Dec thus +** means the position that would be seen by a perfect equatorial +** with its polar axis aligned to the Earth's axis of rotation. +** +** 2) Only the first character of the type argument is significant. +** "R" or "r" indicates that ob1 and ob2 are the observed right +** ascension and declination; "H" or "h" indicates that they are +** hour angle (west +ve) and declination; anything else ("A" or +** "a" is recommended) indicates that ob1 and ob2 are azimuth +** (north zero, east 90 deg) and zenith distance. +** +** 3) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** However, JD cannot unambiguously represent UTC during a leap +** second unless special measures are taken. The convention in the +** present function is that the JD day represents UTC days whether +** the length is 86399, 86400 or 86401 SI seconds. +** +** Applications should use the function iauDtf2d to convert from +** calendar date and time of day into 2-part quasi Julian Date, as +** it implements the leap-second-ambiguity convention just +** described. +** +** 4) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the +** future to be trusted. See iauDat for further details. +** +** 5) UT1-UTC is tabulated in IERS bulletins. It increases by exactly +** one second at the end of each positive UTC leap second, +** introduced in order to keep UT1-UTC within +/- 0.9s. n.b. This +** practice is under review, and in the future UT1-UTC may grow +** essentially without limit. +** +** 6) The geographical coordinates are with respect to the WGS84 +** reference ellipsoid. TAKE CARE WITH THE LONGITUDE SIGN: the +** longitude required by the present function is east-positive +** (i.e. right-handed), in accordance with geographical convention. +** +** 7) The polar motion xp,yp can be obtained from IERS bulletins. The +** values are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions 2003), measured along the +** meridians 0 and 90 deg west respectively. For many +** applications, xp and yp can be set to zero. +** +** 8) If hm, the height above the ellipsoid of the observing station +** in meters, is not known but phpa, the pressure in hPa (=mB), is +** available, an adequate estimate of hm can be obtained from the +** expression +** +** hm = -29.3 * tsl * log ( phpa / 1013.25 ); +** +** where tsl is the approximate sea-level air temperature in K +** (See Astrophysical Quantities, C.W.Allen, 3rd edition, section +** 52). Similarly, if the pressure phpa is not known, it can be +** estimated from the height of the observing station, hm, as +** follows: +** +** phpa = 1013.25 * exp ( -hm / ( 29.3 * tsl ) ); +** +** Note, however, that the refraction is nearly proportional to +** the pressure and that an accurate phpa value is important for +** precise work. +** +** 9) The argument wl specifies the observing wavelength in +** micrometers. The transition from optical to radio is assumed to +** occur at 100 micrometers (about 3000 GHz). +** +** 10) The accuracy of the result is limited by the corrections for +** refraction, which use a simple A*tan(z) + B*tan^3(z) model. +** Providing the meteorological parameters are known accurately and +** there are no gross local effects, the predicted astrometric +** coordinates should be within 0.05 arcsec (optical) or 1 arcsec +** (radio) for a zenith distance of less than 70 degrees, better +** than 30 arcsec (optical or radio) at 85 degrees and better +** than 20 arcmin (optical) or 30 arcmin (radio) at the horizon. +** +** Without refraction, the complementary functions iauAtio13 and +** iauAtoi13 are self-consistent to better than 1 microarcsecond +** all over the celestial sphere. With refraction included, +** consistency falls off at high zenith distances, but is still +** better than 0.05 arcsec at 85 degrees. +** +** 12) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** Called: +** iauApio13 astrometry parameters, CIRS-observed, 2013 +** iauAtoiq quick observed to CIRS +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + iauASTROM astrom; + + +/* Star-independent astrometry parameters for CIRS->observed. */ + j = iauApio13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom); + +/* Abort if bad UTC. */ + if ( j < 0 ) return j; + +/* Transform observed to CIRS. */ + iauAtoiq(type, ob1, ob2, &astrom, ri, di); + +/* Return OK/warning status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/atoiq.c b/src/cpp/3rdparty/sofa/src/atoiq.c new file mode 100644 index 000000000..c9b7ac357 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/atoiq.c @@ -0,0 +1,302 @@ +#include "sofa.h" + +void iauAtoiq(const char *type, + double ob1, double ob2, iauASTROM *astrom, + double *ri, double *di) +/* +** - - - - - - - - - +** i a u A t o i q +** - - - - - - - - - +** +** Quick observed place to CIRS, given the star-independent astrometry +** parameters. +** +** Use of this function is appropriate when efficiency is important and +** where many star positions are all to be transformed for one date. +** The star-independent astrometry parameters can be obtained by +** calling iauApio[13] or iauApco[13]. +** +** Status: support function. +** +** Given: +** type char[] type of coordinates: "R", "H" or "A" (Note 1) +** ob1 double observed Az, HA or RA (radians; Az is N=0,E=90) +** ob2 double observed ZD or Dec (radians) +** astrom iauASTROM* star-independent astrometry parameters: +** pmt double PM time interval (SSB, Julian years) +** eb double[3] SSB to observer (vector, au) +** eh double[3] Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** v double[3] barycentric observer velocity (vector, c) +** bm1 double sqrt(1-|v|^2): reciprocal of Lorenz factor +** bpn double[3][3] bias-precession-nutation matrix +** along double longitude + s' (radians) +** xpl double polar motion xp wrt local meridian (radians) +** ypl double polar motion yp wrt local meridian (radians) +** sphi double sine of geodetic latitude +** cphi double cosine of geodetic latitude +** diurab double magnitude of diurnal aberration vector +** eral double "local" Earth rotation angle (radians) +** refa double refraction constant A (radians) +** refb double refraction constant B (radians) +** +** Returned: +** ri double* CIRS right ascension (CIO-based, radians) +** di double* CIRS declination (radians) +** +** Notes: +** +** 1) "Observed" Az,El means the position that would be seen by a +** perfect geodetically aligned theodolite. This is related to +** the observed HA,Dec via the standard rotation, using the geodetic +** latitude (corrected for polar motion), while the observed HA and +** RA are related simply through the Earth rotation angle and the +** site longitude. "Observed" RA,Dec or HA,Dec thus means the +** position that would be seen by a perfect equatorial with its +** polar axis aligned to the Earth's axis of rotation. By removing +** from the observed place the effects of atmospheric refraction and +** diurnal aberration, the CIRS RA,Dec is obtained. +** +** 2) Only the first character of the type argument is significant. +** "R" or "r" indicates that ob1 and ob2 are the observed right +** ascension and declination; "H" or "h" indicates that they are +** hour angle (west +ve) and declination; anything else ("A" or +** "a" is recommended) indicates that ob1 and ob2 are azimuth (north +** zero, east 90 deg) and zenith distance. (Zenith distance is used +** rather than altitude in order to reflect the fact that no +** allowance is made for depression of the horizon.) +** +** 3) The accuracy of the result is limited by the corrections for +** refraction, which use a simple A*tan(z) + B*tan^3(z) model. +** Providing the meteorological parameters are known accurately and +** there are no gross local effects, the predicted intermediate +** coordinates should be within 0.05 arcsec (optical) or 1 arcsec +** (radio) for a zenith distance of less than 70 degrees, better +** than 30 arcsec (optical or radio) at 85 degrees and better than +** 20 arcmin (optical) or 25 arcmin (radio) at the horizon. +** +** Without refraction, the complementary functions iauAtioq and +** iauAtoiq are self-consistent to better than 1 microarcsecond all +** over the celestial sphere. With refraction included, consistency +** falls off at high zenith distances, but is still better than +** 0.05 arcsec at 85 degrees. +** +** 4) It is advisable to take great care with units, as even unlikely +** values of the input parameters are accepted and processed in +** accordance with the models used. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauC2s p-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** This revision: 2020 December 7 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Minimum sin(alt) for refraction purposes */ + const double SELMIN = 0.05; + + int c; + double c1, c2, sphi, cphi, ce, xaeo, yaeo, zaeo, v[3], + xmhdo, ymhdo, zmhdo, az, sz, zdo, refa, refb, tz, dref, + zdt, xaet, yaet, zaet, xmhda, ymhda, zmhda, + f, xhd, yhd, zhd, sx, cx, sy, cy, hma; + + +/* Coordinate type. */ + c = (int) type[0]; + +/* Coordinates. */ + c1 = ob1; + c2 = ob2; + +/* Sin, cos of latitude. */ + sphi = astrom->sphi; + cphi = astrom->cphi; + +/* Standardize coordinate type. */ + if ( c == 'r' || c == 'R' ) { + c = 'R'; + } else if ( c == 'h' || c == 'H' ) { + c = 'H'; + } else { + c = 'A'; + } + +/* If Az,ZD, convert to Cartesian (S=0,E=90). */ + if ( c == 'A' ) { + ce = sin(c2); + xaeo = - cos(c1) * ce; + yaeo = sin(c1) * ce; + zaeo = cos(c2); + + } else { + + /* If RA,Dec, convert to HA,Dec. */ + if ( c == 'R' ) c1 = astrom->eral - c1; + + /* To Cartesian -HA,Dec. */ + iauS2c ( -c1, c2, v ); + xmhdo = v[0]; + ymhdo = v[1]; + zmhdo = v[2]; + + /* To Cartesian Az,El (S=0,E=90). */ + xaeo = sphi*xmhdo - cphi*zmhdo; + yaeo = ymhdo; + zaeo = cphi*xmhdo + sphi*zmhdo; + } + +/* Azimuth (S=0,E=90). */ + az = ( xaeo != 0.0 || yaeo != 0.0 ) ? atan2(yaeo,xaeo) : 0.0; + +/* Sine of observed ZD, and observed ZD. */ + sz = sqrt ( xaeo*xaeo + yaeo*yaeo ); + zdo = atan2 ( sz, zaeo ); + +/* +** Refraction +** ---------- +*/ + +/* Fast algorithm using two constant model. */ + refa = astrom->refa; + refb = astrom->refb; + tz = sz / ( zaeo > SELMIN ? zaeo : SELMIN ); + dref = ( refa + refb*tz*tz ) * tz; + zdt = zdo + dref; + +/* To Cartesian Az,ZD. */ + ce = sin(zdt); + xaet = cos(az) * ce; + yaet = sin(az) * ce; + zaet = cos(zdt); + +/* Cartesian Az,ZD to Cartesian -HA,Dec. */ + xmhda = sphi*xaet + cphi*zaet; + ymhda = yaet; + zmhda = - cphi*xaet + sphi*zaet; + +/* Diurnal aberration. */ + f = ( 1.0 + astrom->diurab*ymhda ); + xhd = f * xmhda; + yhd = f * ( ymhda - astrom->diurab ); + zhd = f * zmhda; + +/* Polar motion. */ + sx = sin(astrom->xpl); + cx = cos(astrom->xpl); + sy = sin(astrom->ypl); + cy = cos(astrom->ypl); + v[0] = cx*xhd + sx*sy*yhd - sx*cy*zhd; + v[1] = cy*yhd + sy*zhd; + v[2] = sx*xhd - cx*sy*yhd + cx*cy*zhd; + +/* To spherical -HA,Dec. */ + iauC2s(v, &hma, di); + +/* Right ascension. */ + *ri = iauAnp(astrom->eral + hma); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/bi00.c b/src/cpp/3rdparty/sofa/src/bi00.c new file mode 100644 index 000000000..5048666c3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/bi00.c @@ -0,0 +1,168 @@ +#include "sofa.h" +#include "sofam.h" + +void iauBi00(double *dpsibi, double *depsbi, double *dra) +/* +** - - - - - - - - +** i a u B i 0 0 +** - - - - - - - - +** +** Frame bias components of IAU 2000 precession-nutation models; part +** of the Mathews-Herring-Buffett (MHB2000) nutation series, with +** additions. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Returned: +** dpsibi,depsbi double longitude and obliquity corrections +** dra double the ICRS RA of the J2000.0 mean equinox +** +** Notes: +** +** 1) The frame bias corrections in longitude and obliquity (radians) +** are required in order to correct for the offset between the GCRS +** pole and the mean J2000.0 pole. They define, with respect to the +** GCRS frame, a J2000.0 mean pole that is consistent with the rest +** of the IAU 2000A precession-nutation model. +** +** 2) In addition to the displacement of the pole, the complete +** description of the frame bias requires also an offset in right +** ascension. This is not part of the IAU 2000A model, and is from +** Chapront et al. (2002). It is returned in radians. +** +** 3) This is a supplemented implementation of one aspect of the IAU +** 2000A nutation model, formally adopted by the IAU General +** Assembly in 2000, namely MHB2000 (Mathews et al. 2002). +** +** References: +** +** Chapront, J., Chapront-Touze, M. & Francou, G., Astron. +** Astrophys., 387, 700, 2002. +** +** Mathews, P.M., Herring, T.A., Buffet, B.A., "Modeling of nutation +** and precession: New nutation series for nonrigid Earth and +** insights into the Earth's interior", J.Geophys.Res., 107, B4, +** 2002. The MHB2000 code itself was obtained on 2002 September 9 +** from ftp://maia.usno.navy.mil/conv2000/chapter5/IAU2000A. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* The frame bias corrections in longitude and obliquity */ + const double DPBIAS = -0.041775 * DAS2R, + DEBIAS = -0.0068192 * DAS2R; + +/* The ICRS RA of the J2000.0 equinox (Chapront et al., 2002) */ + const double DRA0 = -0.0146 * DAS2R; + + +/* Return the results (which are fixed). */ + *dpsibi = DPBIAS; + *depsbi = DEBIAS; + *dra = DRA0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/bp00.c b/src/cpp/3rdparty/sofa/src/bp00.c new file mode 100644 index 000000000..5c3f82ba0 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/bp00.c @@ -0,0 +1,223 @@ +#include "sofa.h" +#include "sofam.h" + +void iauBp00(double date1, double date2, + double rb[3][3], double rp[3][3], double rbp[3][3]) +/* +** - - - - - - - - +** i a u B p 0 0 +** - - - - - - - - +** +** Frame bias and precession, IAU 2000. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rb double[3][3] frame bias matrix (Note 2) +** rp double[3][3] precession matrix (Note 3) +** rbp double[3][3] bias-precession matrix (Note 4) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix rb transforms vectors from GCRS to mean J2000.0 by +** applying frame bias. +** +** 3) The matrix rp transforms vectors from J2000.0 mean equator and +** equinox to mean equator and equinox of date by applying +** precession. +** +** 4) The matrix rbp transforms vectors from GCRS to mean equator and +** equinox of date by applying frame bias then precession. It is +** the product rp x rb. +** +** 5) It is permissible to re-use the same array in the returned +** arguments. The arrays are filled in the order given. +** +** Called: +** iauBi00 frame bias components, IAU 2000 +** iauPr00 IAU 2000 precession adjustments +** iauIr initialize r-matrix to identity +** iauRx rotate around X-axis +** iauRy rotate around Y-axis +** iauRz rotate around Z-axis +** iauCr copy r-matrix +** iauRxr product of two r-matrices +** +** Reference: +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* J2000.0 obliquity (Lieske et al. 1977) */ + const double EPS0 = 84381.448 * DAS2R; + + double t, dpsibi, depsbi, dra0, psia77, oma77, chia, + dpsipr, depspr, psia, oma, rbw[3][3]; + + +/* Interval between fundamental epoch J2000.0 and current date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Frame bias. */ + iauBi00(&dpsibi, &depsbi, &dra0); + +/* Precession angles (Lieske et al. 1977) */ + psia77 = (5038.7784 + (-1.07259 + (-0.001147) * t) * t) * t * DAS2R; + oma77 = EPS0 + ((0.05127 + (-0.007726) * t) * t) * t * DAS2R; + chia = ( 10.5526 + (-2.38064 + (-0.001125) * t) * t) * t * DAS2R; + +/* Apply IAU 2000 precession corrections. */ + iauPr00(date1, date2, &dpsipr, &depspr); + psia = psia77 + dpsipr; + oma = oma77 + depspr; + +/* Frame bias matrix: GCRS to J2000.0. */ + iauIr(rbw); + iauRz(dra0, rbw); + iauRy(dpsibi*sin(EPS0), rbw); + iauRx(-depsbi, rbw); + iauCr(rbw, rb); + +/* Precession matrix: J2000.0 to mean of date. */ + iauIr(rp); + iauRx(EPS0, rp); + iauRz(-psia, rp); + iauRx(-oma, rp); + iauRz(chia, rp); + +/* Bias-precession matrix: GCRS to mean of date. */ + iauRxr(rp, rbw, rbp); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/bp06.c b/src/cpp/3rdparty/sofa/src/bp06.c new file mode 100644 index 000000000..4223ec744 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/bp06.c @@ -0,0 +1,194 @@ +#include "sofa.h" +#include "sofam.h" + +void iauBp06(double date1, double date2, + double rb[3][3], double rp[3][3], double rbp[3][3]) +/* +** - - - - - - - - +** i a u B p 0 6 +** - - - - - - - - +** +** Frame bias and precession, IAU 2006. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rb double[3][3] frame bias matrix (Note 2) +** rp double[3][3] precession matrix (Note 3) +** rbp double[3][3] bias-precession matrix (Note 4) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix rb transforms vectors from GCRS to mean J2000.0 by +** applying frame bias. +** +** 3) The matrix rp transforms vectors from mean J2000.0 to mean of +** date by applying precession. +** +** 4) The matrix rbp transforms vectors from GCRS to mean of date by +** applying frame bias then precession. It is the product rp x rb. +** +** 5) It is permissible to re-use the same array in the returned +** arguments. The arrays are filled in the order given. +** +** Called: +** iauPfw06 bias-precession F-W angles, IAU 2006 +** iauFw2m F-W angles to r-matrix +** iauPmat06 PB matrix, IAU 2006 +** iauTr transpose r-matrix +** iauRxr product of two r-matrices +** iauCr copy r-matrix +** +** References: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gamb, phib, psib, epsa, rbpw[3][3], rbt[3][3]; + + +/* B matrix. */ + iauPfw06(DJM0, DJM00, &gamb, &phib, &psib, &epsa); + iauFw2m(gamb, phib, psib, epsa, rb); + +/* PxB matrix (temporary). */ + iauPmat06(date1, date2, rbpw); + +/* P matrix. */ + iauTr(rb, rbt); + iauRxr(rbpw, rbt, rp); + +/* PxB matrix. */ + iauCr(rbpw, rbp); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/bpn2xy.c b/src/cpp/3rdparty/sofa/src/bpn2xy.c new file mode 100644 index 000000000..bc450b6e6 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/bpn2xy.c @@ -0,0 +1,150 @@ +#include "sofa.h" + +void iauBpn2xy(double rbpn[3][3], double *x, double *y) +/* +** - - - - - - - - - - +** i a u B p n 2 x y +** - - - - - - - - - - +** +** Extract from the bias-precession-nutation matrix the X,Y coordinates +** of the Celestial Intermediate Pole. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rbpn double[3][3] celestial-to-true matrix (Note 1) +** +** Returned: +** x,y double Celestial Intermediate Pole (Note 2) +** +** Notes: +** +** 1) The matrix rbpn transforms vectors from GCRS to true equator (and +** CIO or equinox) of date, and therefore the Celestial Intermediate +** Pole unit vector is the bottom row of the matrix. +** +** 2) The arguments x,y are components of the Celestial Intermediate +** Pole unit vector in the Geocentric Celestial Reference System. +** +** Reference: +** +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 +** (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Extract the X,Y coordinates. */ + *x = rbpn[2][0]; + *y = rbpn[2][1]; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2i00a.c b/src/cpp/3rdparty/sofa/src/c2i00a.c new file mode 100644 index 000000000..9fe8a7bbc --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2i00a.c @@ -0,0 +1,189 @@ +#include "sofa.h" + +void iauC2i00a(double date1, double date2, double rc2i[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 i 0 0 a +** - - - - - - - - - - +** +** Form the celestial-to-intermediate matrix for a given date using the +** IAU 2000A precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rc2i double[3][3] celestial-to-intermediate matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix rc2i is the first stage in the transformation from +** celestial to terrestrial coordinates: +** +** [TRS] = RPOM * R_3(ERA) * rc2i * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), ERA is the Earth +** Rotation Angle and RPOM is the polar motion matrix. +** +** 3) A faster, but slightly less accurate, result (about 1 mas) can be +** obtained by using instead the iauC2i00b function. +** +** Called: +** iauPnm00a classical NPB matrix, IAU 2000A +** iauC2ibpn celestial-to-intermediate matrix, given NPB matrix +** +** References: +** +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 +** (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3]; + + +/* Obtain the celestial-to-true matrix (IAU 2000A). */ + iauPnm00a(date1, date2, rbpn); + +/* Form the celestial-to-intermediate matrix. */ + iauC2ibpn(date1, date2, rbpn, rc2i); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2i00b.c b/src/cpp/3rdparty/sofa/src/c2i00b.c new file mode 100644 index 000000000..f4aa40a1e --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2i00b.c @@ -0,0 +1,189 @@ +#include "sofa.h" + +void iauC2i00b(double date1, double date2, double rc2i[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 i 0 0 b +** - - - - - - - - - - +** +** Form the celestial-to-intermediate matrix for a given date using the +** IAU 2000B precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rc2i double[3][3] celestial-to-intermediate matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix rc2i is the first stage in the transformation from +** celestial to terrestrial coordinates: +** +** [TRS] = RPOM * R_3(ERA) * rc2i * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), ERA is the Earth +** Rotation Angle and RPOM is the polar motion matrix. +** +** 3) The present function is faster, but slightly less accurate (about +** 1 mas), than the iauC2i00a function. +** +** Called: +** iauPnm00b classical NPB matrix, IAU 2000B +** iauC2ibpn celestial-to-intermediate matrix, given NPB matrix +** +** References: +** +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 +** (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3]; + + +/* Obtain the celestial-to-true matrix (IAU 2000B). */ + iauPnm00b(date1, date2, rbpn); + +/* Form the celestial-to-intermediate matrix. */ + iauC2ibpn(date1, date2, rbpn, rc2i); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2i06a.c b/src/cpp/3rdparty/sofa/src/c2i06a.c new file mode 100644 index 000000000..a199fff9c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2i06a.c @@ -0,0 +1,186 @@ +#include "sofa.h" + +void iauC2i06a(double date1, double date2, double rc2i[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 i 0 6 a +** - - - - - - - - - - +** +** Form the celestial-to-intermediate matrix for a given date using the +** IAU 2006 precession and IAU 2000A nutation models. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rc2i double[3][3] celestial-to-intermediate matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix rc2i is the first stage in the transformation from +** celestial to terrestrial coordinates: +** +** [TRS] = RPOM * R_3(ERA) * rc2i * [CRS] +** +** = RC2T * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), ERA is the Earth +** Rotation Angle and RPOM is the polar motion matrix. +** +** Called: +** iauPnm06a classical NPB matrix, IAU 2006/2000A +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS06 the CIO locator s, given X,Y, IAU 2006 +** iauC2ixys celestial-to-intermediate matrix, given X,Y and s +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), 2004, IERS Conventions (2003), +** IERS Technical Note No. 32, BKG +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3], x, y, s; + + +/* Obtain the celestial-to-true matrix (IAU 2006/2000A). */ + iauPnm06a(date1, date2, rbpn); + +/* Extract the X,Y coordinates. */ + iauBpn2xy(rbpn, &x, &y); + +/* Obtain the CIO locator. */ + s = iauS06(date1, date2, x, y); + +/* Form the celestial-to-intermediate matrix. */ + iauC2ixys(x, y, s, rc2i); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2ibpn.c b/src/cpp/3rdparty/sofa/src/c2ibpn.c new file mode 100644 index 000000000..cdfe59f5c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2ibpn.c @@ -0,0 +1,192 @@ +#include "sofa.h" + +void iauC2ibpn(double date1, double date2, double rbpn[3][3], + double rc2i[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 i b p n +** - - - - - - - - - - +** +** Form the celestial-to-intermediate matrix for a given date given +** the bias-precession-nutation matrix. IAU 2000. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** rbpn double[3][3] celestial-to-true matrix (Note 2) +** +** Returned: +** rc2i double[3][3] celestial-to-intermediate matrix (Note 3) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix rbpn transforms vectors from GCRS to true equator (and +** CIO or equinox) of date. Only the CIP (bottom row) is used. +** +** 3) The matrix rc2i is the first stage in the transformation from +** celestial to terrestrial coordinates: +** +** [TRS] = RPOM * R_3(ERA) * rc2i * [CRS] +** +** = RC2T * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), ERA is the Earth +** Rotation Angle and RPOM is the polar motion matrix. +** +** 4) Although its name does not include "00", This function is in fact +** specific to the IAU 2000 models. +** +** Called: +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauC2ixy celestial-to-intermediate matrix, given X,Y +** +** References: +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y; + + +/* Extract the X,Y coordinates. */ + iauBpn2xy(rbpn, &x, &y); + +/* Form the celestial-to-intermediate matrix (n.b. IAU 2000 specific). */ + iauC2ixy(date1, date2, x, y, rc2i); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2ixy.c b/src/cpp/3rdparty/sofa/src/c2ixy.c new file mode 100644 index 000000000..f066f939e --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2ixy.c @@ -0,0 +1,181 @@ +#include "sofa.h" + +void iauC2ixy(double date1, double date2, double x, double y, + double rc2i[3][3]) +/* +** - - - - - - - - - +** i a u C 2 i x y +** - - - - - - - - - +** +** Form the celestial to intermediate-frame-of-date matrix for a given +** date when the CIP X,Y coordinates are known. IAU 2000. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** x,y double Celestial Intermediate Pole (Note 2) +** +** Returned: +** rc2i double[3][3] celestial-to-intermediate matrix (Note 3) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The Celestial Intermediate Pole coordinates are the x,y components +** of the unit vector in the Geocentric Celestial Reference System. +** +** 3) The matrix rc2i is the first stage in the transformation from +** celestial to terrestrial coordinates: +** +** [TRS] = RPOM * R_3(ERA) * rc2i * [CRS] +** +** = RC2T * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), ERA is the Earth +** Rotation Angle and RPOM is the polar motion matrix. +** +** 4) Although its name does not include "00", This function is in fact +** specific to the IAU 2000 models. +** +** Called: +** iauC2ixys celestial-to-intermediate matrix, given X,Y and s +** iauS00 the CIO locator s, given X,Y, IAU 2000A +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ + +{ +/* Compute s and then the matrix. */ + iauC2ixys(x, y, iauS00(date1, date2, x, y), rc2i); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2ixys.c b/src/cpp/3rdparty/sofa/src/c2ixys.c new file mode 100644 index 000000000..18746becd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2ixys.c @@ -0,0 +1,173 @@ +#include "sofa.h" + +void iauC2ixys(double x, double y, double s, double rc2i[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 i x y s +** - - - - - - - - - - +** +** Form the celestial to intermediate-frame-of-date matrix given the CIP +** X,Y and the CIO locator s. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** x,y double Celestial Intermediate Pole (Note 1) +** s double the CIO locator s (Note 2) +** +** Returned: +** rc2i double[3][3] celestial-to-intermediate matrix (Note 3) +** +** Notes: +** +** 1) The Celestial Intermediate Pole coordinates are the x,y +** components of the unit vector in the Geocentric Celestial +** Reference System. +** +** 2) The CIO locator s (in radians) positions the Celestial +** Intermediate Origin on the equator of the CIP. +** +** 3) The matrix rc2i is the first stage in the transformation from +** celestial to terrestrial coordinates: +** +** [TRS] = RPOM * R_3(ERA) * rc2i * [CRS] +** +** = RC2T * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), ERA is the Earth +** Rotation Angle and RPOM is the polar motion matrix. +** +** Called: +** iauIr initialize r-matrix to identity +** iauRz rotate around Z-axis +** iauRy rotate around Y-axis +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r2, e, d; + + +/* Obtain the spherical angles E and d. */ + r2 = x*x + y*y; + e = (r2 > 0.0) ? atan2(y, x) : 0.0; + d = atan(sqrt(r2 / (1.0 - r2))); + +/* Form the matrix. */ + iauIr(rc2i); + iauRz(e, rc2i); + iauRy(d, rc2i); + iauRz(-(e+s), rc2i); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2s.c b/src/cpp/3rdparty/sofa/src/c2s.c new file mode 100644 index 000000000..006a80a3a --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2s.c @@ -0,0 +1,146 @@ +#include "sofa.h" + +void iauC2s(double p[3], double *theta, double *phi) +/* +** - - - - - - - +** i a u C 2 s +** - - - - - - - +** +** P-vector to spherical coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** p double[3] p-vector +** +** Returned: +** theta double longitude angle (radians) +** phi double latitude angle (radians) +** +** Notes: +** +** 1) The vector p can have any magnitude; only its direction is used. +** +** 2) If p is null, zero theta and phi are returned. +** +** 3) At either pole, zero theta is returned. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y, z, d2; + + + x = p[0]; + y = p[1]; + z = p[2]; + d2 = x*x + y*y; + + *theta = (d2 == 0.0) ? 0.0 : atan2(y, x); + *phi = (z == 0.0) ? 0.0 : atan2(z, sqrt(d2)); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2t00a.c b/src/cpp/3rdparty/sofa/src/c2t00a.c new file mode 100644 index 000000000..eea8194d1 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2t00a.c @@ -0,0 +1,204 @@ +#include "sofa.h" + +void iauC2t00a(double tta, double ttb, double uta, double utb, + double xp, double yp, double rc2t[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 t 0 0 a +** - - - - - - - - - - +** +** Form the celestial to terrestrial matrix given the date, the UT1 and +** the polar motion, using the IAU 2000A precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** tta,ttb double TT as a 2-part Julian Date (Note 1) +** uta,utb double UT1 as a 2-part Julian Date (Note 1) +** xp,yp double CIP coordinates (radians, Note 2) +** +** Returned: +** rc2t double[3][3] celestial-to-terrestrial matrix (Note 3) +** +** Notes: +** +** 1) The TT and UT1 dates tta+ttb and uta+utb are Julian Dates, +** apportioned in any convenient way between the arguments uta and +** utb. For example, JD(UT1)=2450123.7 could be expressed in any of +** these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. In the case of uta,utb, the +** date & time method is best matched to the Earth rotation angle +** algorithm used: maximum precision is delivered when the uta +** argument is for 0hrs UT1 on the day in question and the utb +** argument lies in the range 0 to 1, or vice versa. +** +** 2) The arguments xp and yp are the coordinates (in radians) of the +** Celestial Intermediate Pole with respect to the International +** Terrestrial Reference System (see IERS Conventions 2003), +** measured along the meridians 0 and 90 deg west respectively. +** +** 3) The matrix rc2t transforms from celestial to terrestrial +** coordinates: +** +** [TRS] = RPOM * R_3(ERA) * RC2I * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), RC2I is the +** celestial-to-intermediate matrix, ERA is the Earth rotation +** angle and RPOM is the polar motion matrix. +** +** 4) A faster, but slightly less accurate, result (about 1 mas) can +** be obtained by using instead the iauC2t00b function. +** +** Called: +** iauC2i00a celestial-to-intermediate matrix, IAU 2000A +** iauEra00 Earth rotation angle, IAU 2000 +** iauSp00 the TIO locator s', IERS 2000 +** iauPom00 polar motion matrix +** iauC2tcio form CIO-based celestial-to-terrestrial matrix +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rc2i[3][3], era, sp, rpom[3][3]; + + +/* Form the celestial-to-intermediate matrix for this TT (IAU 2000A). */ + iauC2i00a(tta, ttb, rc2i ); + +/* Predict the Earth rotation angle for this UT1. */ + era = iauEra00(uta, utb); + +/* Estimate s'. */ + sp = iauSp00(tta, ttb); + +/* Form the polar motion matrix. */ + iauPom00(xp, yp, sp, rpom); + +/* Combine to form the celestial-to-terrestrial matrix. */ + iauC2tcio(rc2i, era, rpom, rc2t); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2t00b.c b/src/cpp/3rdparty/sofa/src/c2t00b.c new file mode 100644 index 000000000..939208a6d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2t00b.c @@ -0,0 +1,200 @@ +#include "sofa.h" + +void iauC2t00b(double tta, double ttb, double uta, double utb, + double xp, double yp, double rc2t[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 t 0 0 b +** - - - - - - - - - - +** +** Form the celestial to terrestrial matrix given the date, the UT1 and +** the polar motion, using the IAU 2000B precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** tta,ttb double TT as a 2-part Julian Date (Note 1) +** uta,utb double UT1 as a 2-part Julian Date (Note 1) +** xp,yp double coordinates of the pole (radians, Note 2) +** +** Returned: +** rc2t double[3][3] celestial-to-terrestrial matrix (Note 3) +** +** Notes: +** +** 1) The TT and UT1 dates tta+ttb and uta+utb are Julian Dates, +** apportioned in any convenient way between the arguments uta and +** utb. For example, JD(UT1)=2450123.7 could be expressed in any of +** these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. In the case of uta,utb, the +** date & time method is best matched to the Earth rotation angle +** algorithm used: maximum precision is delivered when the uta +** argument is for 0hrs UT1 on the day in question and the utb +** argument lies in the range 0 to 1, or vice versa. +** +** 2) The arguments xp and yp are the coordinates (in radians) of the +** Celestial Intermediate Pole with respect to the International +** Terrestrial Reference System (see IERS Conventions 2003), +** measured along the meridians 0 and 90 deg west respectively. +** +** 3) The matrix rc2t transforms from celestial to terrestrial +** coordinates: +** +** [TRS] = RPOM * R_3(ERA) * RC2I * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), RC2I is the +** celestial-to-intermediate matrix, ERA is the Earth rotation +** angle and RPOM is the polar motion matrix. +** +** 4) The present function is faster, but slightly less accurate (about +** 1 mas), than the iauC2t00a function. +** +** Called: +** iauC2i00b celestial-to-intermediate matrix, IAU 2000B +** iauEra00 Earth rotation angle, IAU 2000 +** iauPom00 polar motion matrix +** iauC2tcio form CIO-based celestial-to-terrestrial matrix +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rc2i[3][3], era, rpom[3][3]; + + +/* Form the celestial-to-intermediate matrix for this TT (IAU 2000B). */ + iauC2i00b(tta, ttb, rc2i); + +/* Predict the Earth rotation angle for this UT1. */ + era = iauEra00(uta, utb); + +/* Form the polar motion matrix (neglecting s'). */ + iauPom00(xp, yp, 0.0, rpom); + +/* Combine to form the celestial-to-terrestrial matrix. */ + iauC2tcio(rc2i, era, rpom, rc2t); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2t06a.c b/src/cpp/3rdparty/sofa/src/c2t06a.c new file mode 100644 index 000000000..cdf431333 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2t06a.c @@ -0,0 +1,202 @@ +#include "sofa.h" + +void iauC2t06a(double tta, double ttb, double uta, double utb, + double xp, double yp, double rc2t[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 t 0 6 a +** - - - - - - - - - - +** +** Form the celestial to terrestrial matrix given the date, the UT1 and +** the polar motion, using the IAU 2006/2000A precession-nutation +** model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** tta,ttb double TT as a 2-part Julian Date (Note 1) +** uta,utb double UT1 as a 2-part Julian Date (Note 1) +** xp,yp double coordinates of the pole (radians, Note 2) +** +** Returned: +** rc2t double[3][3] celestial-to-terrestrial matrix (Note 3) +** +** Notes: +** +** 1) The TT and UT1 dates tta+ttb and uta+utb are Julian Dates, +** apportioned in any convenient way between the arguments uta and +** utb. For example, JD(UT1)=2450123.7 could be expressed in any of +** these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. In the case of uta,utb, the +** date & time method is best matched to the Earth rotation angle +** algorithm used: maximum precision is delivered when the uta +** argument is for 0hrs UT1 on the day in question and the utb +** argument lies in the range 0 to 1, or vice versa. +** +** 2) The arguments xp and yp are the coordinates (in radians) of the +** Celestial Intermediate Pole with respect to the International +** Terrestrial Reference System (see IERS Conventions 2003), +** measured along the meridians 0 and 90 deg west respectively. +** +** 3) The matrix rc2t transforms from celestial to terrestrial +** coordinates: +** +** [TRS] = RPOM * R_3(ERA) * RC2I * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), RC2I is the +** celestial-to-intermediate matrix, ERA is the Earth rotation +** angle and RPOM is the polar motion matrix. +** +** Called: +** iauC2i06a celestial-to-intermediate matrix, IAU 2006/2000A +** iauEra00 Earth rotation angle, IAU 2000 +** iauSp00 the TIO locator s', IERS 2000 +** iauPom00 polar motion matrix +** iauC2tcio form CIO-based celestial-to-terrestrial matrix +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), 2004, IERS Conventions (2003), +** IERS Technical Note No. 32, BKG +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rc2i[3][3], era, sp, rpom[3][3]; + + +/* Form the celestial-to-intermediate matrix for this TT. */ + iauC2i06a(tta, ttb, rc2i); + +/* Predict the Earth rotation angle for this UT1. */ + era = iauEra00(uta, utb); + +/* Estimate s'. */ + sp = iauSp00(tta, ttb); + +/* Form the polar motion matrix. */ + iauPom00(xp, yp, sp, rpom); + +/* Combine to form the celestial-to-terrestrial matrix. */ + iauC2tcio(rc2i, era, rpom, rc2t); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2tcio.c b/src/cpp/3rdparty/sofa/src/c2tcio.c new file mode 100644 index 000000000..f2ca15251 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2tcio.c @@ -0,0 +1,172 @@ +#include "sofa.h" + +void iauC2tcio(double rc2i[3][3], double era, double rpom[3][3], + double rc2t[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 t c i o +** - - - - - - - - - - +** +** Assemble the celestial to terrestrial matrix from CIO-based +** components (the celestial-to-intermediate matrix, the Earth Rotation +** Angle and the polar motion matrix). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc2i double[3][3] celestial-to-intermediate matrix +** era double Earth rotation angle (radians) +** rpom double[3][3] polar-motion matrix +** +** Returned: +** rc2t double[3][3] celestial-to-terrestrial matrix +** +** Notes: +** +** 1) This function constructs the rotation matrix that transforms +** vectors in the celestial system into vectors in the terrestrial +** system. It does so starting from precomputed components, namely +** the matrix which rotates from celestial coordinates to the +** intermediate frame, the Earth rotation angle and the polar motion +** matrix. One use of the present function is when generating a +** series of celestial-to-terrestrial matrices where only the Earth +** Rotation Angle changes, avoiding the considerable overhead of +** recomputing the precession-nutation more often than necessary to +** achieve given accuracy objectives. +** +** 2) The relationship between the arguments is as follows: +** +** [TRS] = RPOM * R_3(ERA) * rc2i * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003). +** +** Called: +** iauCr copy r-matrix +** iauRz rotate around Z-axis +** iauRxr product of two r-matrices +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), 2004, IERS Conventions (2003), +** IERS Technical Note No. 32, BKG +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r[3][3]; + + +/* Construct the matrix. */ + iauCr(rc2i, r); + iauRz(era, r); + iauRxr(rpom, r, rc2t); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2teqx.c b/src/cpp/3rdparty/sofa/src/c2teqx.c new file mode 100644 index 000000000..f6803cc1f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2teqx.c @@ -0,0 +1,172 @@ +#include "sofa.h" + +void iauC2teqx(double rbpn[3][3], double gst, double rpom[3][3], + double rc2t[3][3]) +/* +** - - - - - - - - - - +** i a u C 2 t e q x +** - - - - - - - - - - +** +** Assemble the celestial to terrestrial matrix from equinox-based +** components (the celestial-to-true matrix, the Greenwich Apparent +** Sidereal Time and the polar motion matrix). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rbpn double[3][3] celestial-to-true matrix +** gst double Greenwich (apparent) Sidereal Time (radians) +** rpom double[3][3] polar-motion matrix +** +** Returned: +** rc2t double[3][3] celestial-to-terrestrial matrix (Note 2) +** +** Notes: +** +** 1) This function constructs the rotation matrix that transforms +** vectors in the celestial system into vectors in the terrestrial +** system. It does so starting from precomputed components, namely +** the matrix which rotates from celestial coordinates to the +** true equator and equinox of date, the Greenwich Apparent Sidereal +** Time and the polar motion matrix. One use of the present function +** is when generating a series of celestial-to-terrestrial matrices +** where only the Sidereal Time changes, avoiding the considerable +** overhead of recomputing the precession-nutation more often than +** necessary to achieve given accuracy objectives. +** +** 2) The relationship between the arguments is as follows: +** +** [TRS] = rpom * R_3(gst) * rbpn * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003). +** +** Called: +** iauCr copy r-matrix +** iauRz rotate around Z-axis +** iauRxr product of two r-matrices +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r[3][3]; + + +/* Construct the matrix. */ + iauCr(rbpn, r); + iauRz(gst, r); + iauRxr(rpom, r, rc2t); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2tpe.c b/src/cpp/3rdparty/sofa/src/c2tpe.c new file mode 100644 index 000000000..cf525aa4c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2tpe.c @@ -0,0 +1,217 @@ +#include "sofa.h" + +void iauC2tpe(double tta, double ttb, double uta, double utb, + double dpsi, double deps, double xp, double yp, + double rc2t[3][3]) +/* +** - - - - - - - - - +** i a u C 2 t p e +** - - - - - - - - - +** +** Form the celestial to terrestrial matrix given the date, the UT1, +** the nutation and the polar motion. IAU 2000. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** tta,ttb double TT as a 2-part Julian Date (Note 1) +** uta,utb double UT1 as a 2-part Julian Date (Note 1) +** dpsi,deps double nutation (Note 2) +** xp,yp double coordinates of the pole (radians, Note 3) +** +** Returned: +** rc2t double[3][3] celestial-to-terrestrial matrix (Note 4) +** +** Notes: +** +** 1) The TT and UT1 dates tta+ttb and uta+utb are Julian Dates, +** apportioned in any convenient way between the arguments uta and +** utb. For example, JD(UT1)=2450123.7 could be expressed in any of +** these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. In the case of uta,utb, the +** date & time method is best matched to the Earth rotation angle +** algorithm used: maximum precision is delivered when the uta +** argument is for 0hrs UT1 on the day in question and the utb +** argument lies in the range 0 to 1, or vice versa. +** +** 2) The caller is responsible for providing the nutation components; +** they are in longitude and obliquity, in radians and are with +** respect to the equinox and ecliptic of date. For high-accuracy +** applications, free core nutation should be included as well as +** any other relevant corrections to the position of the CIP. +** +** 3) The arguments xp and yp are the coordinates (in radians) of the +** Celestial Intermediate Pole with respect to the International +** Terrestrial Reference System (see IERS Conventions 2003), +** measured along the meridians 0 and 90 deg west respectively. +** +** 4) The matrix rc2t transforms from celestial to terrestrial +** coordinates: +** +** [TRS] = RPOM * R_3(GST) * RBPN * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), RBPN is the +** bias-precession-nutation matrix, GST is the Greenwich (apparent) +** Sidereal Time and RPOM is the polar motion matrix. +** +** 5) Although its name does not include "00", This function is in fact +** specific to the IAU 2000 models. +** +** Called: +** iauPn00 bias/precession/nutation results, IAU 2000 +** iauGmst00 Greenwich mean sidereal time, IAU 2000 +** iauSp00 the TIO locator s', IERS 2000 +** iauEe00 equation of the equinoxes, IAU 2000 +** iauPom00 polar motion matrix +** iauC2teqx form equinox-based celestial-to-terrestrial matrix +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double epsa, rb[3][3], rp[3][3], rbp[3][3], rn[3][3], + rbpn[3][3], gmst, ee, sp, rpom[3][3]; + + +/* Form the celestial-to-true matrix for this TT. */ + iauPn00(tta, ttb, dpsi, deps, &epsa, rb, rp, rbp, rn, rbpn); + +/* Predict the Greenwich Mean Sidereal Time for this UT1 and TT. */ + gmst = iauGmst00(uta, utb, tta, ttb); + +/* Predict the equation of the equinoxes given TT and nutation. */ + ee = iauEe00(tta, ttb, epsa, dpsi); + +/* Estimate s'. */ + sp = iauSp00(tta, ttb); + +/* Form the polar motion matrix. */ + iauPom00(xp, yp, sp, rpom); + +/* Combine to form the celestial-to-terrestrial matrix. */ + iauC2teqx(rbpn, gmst + ee, rpom, rc2t); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/c2txy.c b/src/cpp/3rdparty/sofa/src/c2txy.c new file mode 100644 index 000000000..e0a27b130 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/c2txy.c @@ -0,0 +1,209 @@ +#include "sofa.h" + +void iauC2txy(double tta, double ttb, double uta, double utb, + double x, double y, double xp, double yp, + double rc2t[3][3]) +/* +** - - - - - - - - - +** i a u C 2 t x y +** - - - - - - - - - +** +** Form the celestial to terrestrial matrix given the date, the UT1, +** the CIP coordinates and the polar motion. IAU 2000. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** tta,ttb double TT as a 2-part Julian Date (Note 1) +** uta,utb double UT1 as a 2-part Julian Date (Note 1) +** x,y double Celestial Intermediate Pole (Note 2) +** xp,yp double coordinates of the pole (radians, Note 3) +** +** Returned: +** rc2t double[3][3] celestial-to-terrestrial matrix (Note 4) +** +** Notes: +** +** 1) The TT and UT1 dates tta+ttb and uta+utb are Julian Dates, +** apportioned in any convenient way between the arguments uta and +** utb. For example, JD(UT1)=2450123.7 could be expressed in any o +** these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. In the case of uta,utb, the +** date & time method is best matched to the Earth rotation angle +** algorithm used: maximum precision is delivered when the uta +** argument is for 0hrs UT1 on the day in question and the utb +** argument lies in the range 0 to 1, or vice versa. +** +** 2) The Celestial Intermediate Pole coordinates are the x,y +** components of the unit vector in the Geocentric Celestial +** Reference System. +** +** 3) The arguments xp and yp are the coordinates (in radians) of the +** Celestial Intermediate Pole with respect to the International +** Terrestrial Reference System (see IERS Conventions 2003), +** measured along the meridians 0 and 90 deg west respectively. +** +** 4) The matrix rc2t transforms from celestial to terrestrial +** coordinates: +** +** [TRS] = RPOM * R_3(ERA) * RC2I * [CRS] +** +** = rc2t * [CRS] +** +** where [CRS] is a vector in the Geocentric Celestial Reference +** System and [TRS] is a vector in the International Terrestrial +** Reference System (see IERS Conventions 2003), ERA is the Earth +** Rotation Angle and RPOM is the polar motion matrix. +** +** 5) Although its name does not include "00", This function is in fact +** specific to the IAU 2000 models. +** +** Called: +** iauC2ixy celestial-to-intermediate matrix, given X,Y +** iauEra00 Earth rotation angle, IAU 2000 +** iauSp00 the TIO locator s', IERS 2000 +** iauPom00 polar motion matrix +** iauC2tcio form CIO-based celestial-to-terrestrial matrix +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rc2i[3][3], era, sp, rpom[3][3]; + + +/* Form the celestial-to-intermediate matrix for this TT. */ + iauC2ixy(tta, ttb, x, y, rc2i); + +/* Predict the Earth rotation angle for this UT1. */ + era = iauEra00(uta, utb); + +/* Estimate s'. */ + sp = iauSp00(tta, ttb); + +/* Form the polar motion matrix. */ + iauPom00(xp, yp, sp, rpom); + +/* Combine to form the celestial-to-terrestrial matrix. */ + iauC2tcio(rc2i, era, rpom, rc2t); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/cal2jd.c b/src/cpp/3rdparty/sofa/src/cal2jd.c new file mode 100644 index 000000000..f209d2c5e --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/cal2jd.c @@ -0,0 +1,192 @@ +#include "sofa.h" +#include "sofam.h" + +int iauCal2jd(int iy, int im, int id, double *djm0, double *djm) +/* +** - - - - - - - - - - +** i a u C a l 2 j d +** - - - - - - - - - - +** +** Gregorian Calendar to Julian Date. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** iy,im,id int year, month, day in Gregorian calendar (Note 1) +** +** Returned: +** djm0 double MJD zero-point: always 2400000.5 +** djm double Modified Julian Date for 0 hrs +** +** Returned (function value): +** int status: +** 0 = OK +** -1 = bad year (Note 3: JD not computed) +** -2 = bad month (JD not computed) +** -3 = bad day (JD computed) +** +** Notes: +** +** 1) The algorithm used is valid from -4800 March 1, but this +** implementation rejects dates before -4799 January 1. +** +** 2) The Julian Date is returned in two pieces, in the usual SOFA +** manner, which is designed to preserve time resolution. The +** Julian Date is available as a single number by adding djm0 and +** djm. +** +** 3) In early eras the conversion is from the "Proleptic Gregorian +** Calendar"; no account is taken of the date(s) of adoption of +** the Gregorian Calendar, nor is the AD/BC numbering convention +** observed. +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 12.92 (p604). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j, ly, my; + long iypmy; + +/* Earliest year allowed (4800BC) */ + const int IYMIN = -4799; + +/* Month lengths in days */ + static const int mtab[] + = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + +/* Preset status. */ + j = 0; + +/* Validate year and month. */ + if (iy < IYMIN) return -1; + if (im < 1 || im > 12) return -2; + +/* If February in a leap year, 1, otherwise 0. */ + ly = ((im == 2) && !(iy%4) && (iy%100 || !(iy%400))); + +/* Validate day, taking into account leap years. */ + if ( (id < 1) || (id > (mtab[im-1] + ly))) j = -3; + +/* Return result. */ + my = (im - 14) / 12; + iypmy = (long) (iy + my); + *djm0 = DJM0; + *djm = (double)((1461L * (iypmy + 4800L)) / 4L + + (367L * (long) (im - 2 - 12 * my)) / 12L + - (3L * ((iypmy + 4900L) / 100L)) / 4L + + (long) id - 2432076L); + +/* Return status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/cp.c b/src/cpp/3rdparty/sofa/src/cp.c new file mode 100644 index 000000000..4ac3d6c83 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/cp.c @@ -0,0 +1,130 @@ +#include "sofa.h" + +void iauCp(double p[3], double c[3]) +/* +** - - - - - - +** i a u C p +** - - - - - - +** +** Copy a p-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** p double[3] p-vector to be copied +** +** Returned: +** c double[3] copy +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + c[0] = p[0]; + c[1] = p[1]; + c[2] = p[2]; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/cpv.c b/src/cpp/3rdparty/sofa/src/cpv.c new file mode 100644 index 000000000..936bae6cf --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/cpv.c @@ -0,0 +1,132 @@ +#include "sofa.h" + +void iauCpv(double pv[2][3], double c[2][3]) +/* +** - - - - - - - +** i a u C p v +** - - - - - - - +** +** Copy a position/velocity vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** pv double[2][3] position/velocity vector to be copied +** +** Returned: +** c double[2][3] copy +** +** Called: +** iauCp copy p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauCp(pv[0], c[0]); + iauCp(pv[1], c[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/cr.c b/src/cpp/3rdparty/sofa/src/cr.c new file mode 100644 index 000000000..ea8ddbcd3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/cr.c @@ -0,0 +1,133 @@ +#include "sofa.h" + +void iauCr(double r[3][3], double c[3][3]) +/* +** - - - - - - +** i a u C r +** - - - - - - +** +** Copy an r-matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** r double[3][3] r-matrix to be copied +** +** Returned: +** c double[3][3] copy +** +** Called: +** iauCp copy p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauCp(r[0], c[0]); + iauCp(r[1], c[1]); + iauCp(r[2], c[2]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/d2dtf.c b/src/cpp/3rdparty/sofa/src/d2dtf.c new file mode 100644 index 000000000..550f6283e --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/d2dtf.c @@ -0,0 +1,289 @@ +#include "sofa.h" +#include "sofam.h" +#include + +int iauD2dtf(const char *scale, int ndp, double d1, double d2, + int *iy, int *im, int *id, int ihmsf[4]) +/* +** - - - - - - - - - +** i a u D 2 d t f +** - - - - - - - - - +** +** Format for output a 2-part Julian Date (or in the case of UTC a +** quasi-JD form that includes special provision for leap seconds). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** scale char[] time scale ID (Note 1) +** ndp int resolution (Note 2) +** d1,d2 double time as a 2-part Julian Date (Notes 3,4) +** +** Returned: +** iy,im,id int year, month, day in Gregorian calendar (Note 5) +** ihmsf int[4] hours, minutes, seconds, fraction (Note 1) +** +** Returned (function value): +** int status: +1 = dubious year (Note 5) +** 0 = OK +** -1 = unacceptable date (Note 6) +** +** Notes: +** +** 1) scale identifies the time scale. Only the value "UTC" (in upper +** case) is significant, and enables handling of leap seconds (see +** Note 4). +** +** 2) ndp is the number of decimal places in the seconds field, and can +** have negative as well as positive values, such as: +** +** ndp resolution +** -4 1 00 00 +** -3 0 10 00 +** -2 0 01 00 +** -1 0 00 10 +** 0 0 00 01 +** 1 0 00 00.1 +** 2 0 00 00.01 +** 3 0 00 00.001 +** +** The limits are platform dependent, but a safe range is -5 to +9. +** +** 3) d1+d2 is Julian Date, apportioned in any convenient way between +** the two arguments, for example where d1 is the Julian Day Number +** and d2 is the fraction of a day. In the case of UTC, where the +** use of JD is problematical, special conventions apply: see the +** next note. +** +** 4) JD cannot unambiguously represent UTC during a leap second unless +** special measures are taken. The SOFA internal convention is that +** the quasi-JD day represents UTC days whether the length is 86399, +** 86400 or 86401 SI seconds. In the 1960-1972 era there were +** smaller jumps (in either direction) each time the linear UTC(TAI) +** expression was changed, and these "mini-leaps" are also included +** in the SOFA convention. +** +** 5) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the future +** to be trusted. See iauDat for further details. +** +** 6) For calendar conventions and limitations, see iauCal2jd. +** +** Called: +** iauJd2cal JD to Gregorian calendar +** iauD2tf decompose days to hms +** iauDat delta(AT) = TAI-UTC +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int leap; + char s; + int iy1, im1, id1, js, iy2, im2, id2, ihmsf1[4], i; + double a1, b1, fd, dat0, dat12, w, dat24, dleap; + + +/* The two-part JD. */ + a1 = d1; + b1 = d2; + +/* Provisional calendar date. */ + js = iauJd2cal(a1, b1, &iy1, &im1, &id1, &fd); + if ( js ) return -1; + +/* Is this a leap second day? */ + leap = 0; + if ( ! strcmp(scale,"UTC") ) { + + /* TAI-UTC at 0h today. */ + js = iauDat(iy1, im1, id1, 0.0, &dat0); + if ( js < 0 ) return -1; + + /* TAI-UTC at 12h today (to detect drift). */ + js = iauDat(iy1, im1, id1, 0.5, &dat12); + if ( js < 0 ) return -1; + + /* TAI-UTC at 0h tomorrow (to detect jumps). */ + js = iauJd2cal(a1+1.5, b1-fd, &iy2, &im2, &id2, &w); + if ( js ) return -1; + js = iauDat(iy2, im2, id2, 0.0, &dat24); + if ( js < 0 ) return -1; + + /* Any sudden change in TAI-UTC (seconds). */ + dleap = dat24 - (2.0*dat12 - dat0); + + /* If leap second day, scale the fraction of a day into SI. */ + leap = (fabs(dleap) > 0.5); + if (leap) fd += fd * dleap/DAYSEC; + } + +/* Provisional time of day. */ + iauD2tf ( ndp, fd, &s, ihmsf1 ); + +/* Has the (rounded) time gone past 24h? */ + if ( ihmsf1[0] > 23 ) { + + /* Yes. We probably need tomorrow's calendar date. */ + js = iauJd2cal(a1+1.5, b1-fd, &iy2, &im2, &id2, &w); + if ( js ) return -1; + + /* Is today a leap second day? */ + if ( ! leap ) { + + /* No. Use 0h tomorrow. */ + iy1 = iy2; + im1 = im2; + id1 = id2; + ihmsf1[0] = 0; + ihmsf1[1] = 0; + ihmsf1[2] = 0; + + } else { + + /* Yes. Are we past the leap second itself? */ + if ( ihmsf1[2] > 0 ) { + + /* Yes. Use tomorrow but allow for the leap second. */ + iy1 = iy2; + im1 = im2; + id1 = id2; + ihmsf1[0] = 0; + ihmsf1[1] = 0; + ihmsf1[2] = 0; + + } else { + + /* No. Use 23 59 60... today. */ + ihmsf1[0] = 23; + ihmsf1[1] = 59; + ihmsf1[2] = 60; + } + + /* If rounding to 10s or coarser always go up to new day. */ + if ( ndp < 0 && ihmsf1[2] == 60 ) { + iy1 = iy2; + im1 = im2; + id1 = id2; + ihmsf1[0] = 0; + ihmsf1[1] = 0; + ihmsf1[2] = 0; + } + } + } + +/* Results. */ + *iy = iy1; + *im = im1; + *id = id1; + for ( i = 0; i < 4; i++ ) { + ihmsf[i] = ihmsf1[i]; + } + +/* Status. */ + return js; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/d2tf.c b/src/cpp/3rdparty/sofa/src/d2tf.c new file mode 100644 index 000000000..e8dc0c0b4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/d2tf.c @@ -0,0 +1,211 @@ +#include "sofa.h" +#include "sofam.h" + +void iauD2tf(int ndp, double days, char *sign, int ihmsf[4]) +/* +** - - - - - - - - +** i a u D 2 t f +** - - - - - - - - +** +** Decompose days to hours, minutes, seconds, fraction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** ndp int resolution (Note 1) +** days double interval in days +** +** Returned: +** sign char* '+' or '-' +** ihmsf int[4] hours, minutes, seconds, fraction +** +** Notes: +** +** 1) The argument ndp is interpreted as follows: +** +** ndp resolution +** : ...0000 00 00 +** -7 1000 00 00 +** -6 100 00 00 +** -5 10 00 00 +** -4 1 00 00 +** -3 0 10 00 +** -2 0 01 00 +** -1 0 00 10 +** 0 0 00 01 +** 1 0 00 00.1 +** 2 0 00 00.01 +** 3 0 00 00.001 +** : 0 00 00.000... +** +** 2) The largest positive useful value for ndp is determined by the +** size of days, the format of double on the target platform, and +** the risk of overflowing ihmsf[3]. On a typical platform, for +** days up to 1.0, the available floating-point precision might +** correspond to ndp=12. However, the practical limit is typically +** ndp=9, set by the capacity of a 32-bit int, or ndp=4 if int is +** only 16 bits. +** +** 3) The absolute value of days may exceed 1.0. In cases where it +** does not, it is up to the caller to test for and handle the +** case where days is very nearly 1.0 and rounds up to 24 hours, +** by testing for ihmsf[0]=24 and setting ihmsf[0-3] to zero. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int nrs, n; + double rs, rm, rh, a, w, ah, am, as, af; + + +/* Handle sign. */ + *sign = (char) ( ( days >= 0.0 ) ? '+' : '-' ); + +/* Interval in seconds. */ + a = DAYSEC * fabs(days); + +/* Pre-round if resolution coarser than 1s (then pretend ndp=1). */ + if (ndp < 0) { + nrs = 1; + for (n = 1; n <= -ndp; n++) { + nrs *= (n == 2 || n == 4) ? 6 : 10; + } + rs = (double) nrs; + w = a / rs; + a = rs * dnint(w); + } + +/* Express the unit of each field in resolution units. */ + nrs = 1; + for (n = 1; n <= ndp; n++) { + nrs *= 10; + } + rs = (double) nrs; + rm = rs * 60.0; + rh = rm * 60.0; + +/* Round the interval and express in resolution units. */ + a = dnint(rs * a); + +/* Break into fields. */ + ah = a / rh; + ah = dint(ah); + a -= ah * rh; + am = a / rm; + am = dint(am); + a -= am * rm; + as = a / rs; + as = dint(as); + af = a - as * rs; + +/* Return results. */ + ihmsf[0] = (int) ah; + ihmsf[1] = (int) am; + ihmsf[2] = (int) as; + ihmsf[3] = (int) af; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/dat.c b/src/cpp/3rdparty/sofa/src/dat.c new file mode 100644 index 000000000..bd78dc8a8 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/dat.c @@ -0,0 +1,354 @@ +#include "sofa.h" + +int iauDat(int iy, int im, int id, double fd, double *deltat) +/* +** - - - - - - - +** i a u D a t +** - - - - - - - +** +** For a given UTC date, calculate Delta(AT) = TAI-UTC. +** +** :------------------------------------------: +** : : +** : IMPORTANT : +** : : +** : A new version of this function must be : +** : produced whenever a new leap second is : +** : announced. There are four items to : +** : change on each such occasion: : +** : : +** : 1) A new line must be added to the set : +** : of statements that initialize the : +** : array "changes". : +** : : +** : 2) The constant IYV must be set to the : +** : current year. : +** : : +** : 3) The "Latest leap second" comment : +** : below must be set to the new leap : +** : second date. : +** : : +** : 4) The "This revision" comment, later, : +** : must be set to the current date. : +** : : +** : Change (2) must also be carried out : +** : whenever the function is re-issued, : +** : even if no leap seconds have been : +** : added. : +** : : +** : Latest leap second: 2016 December 31 : +** : : +** :__________________________________________: +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: user-replaceable support function. +** +** Given: +** iy int UTC: year (Notes 1 and 2) +** im int month (Note 2) +** id int day (Notes 2 and 3) +** fd double fraction of day (Note 4) +** +** Returned: +** deltat double TAI minus UTC, seconds +** +** Returned (function value): +** int status (Note 5): +** 1 = dubious year (Note 1) +** 0 = OK +** -1 = bad year +** -2 = bad month +** -3 = bad day (Note 3) +** -4 = bad fraction (Note 4) +** -5 = internal error (Note 5) +** +** Notes: +** +** 1) UTC began at 1960 January 1.0 (JD 2436934.5) and it is improper +** to call the function with an earlier date. If this is attempted, +** zero is returned together with a warning status. +** +** Because leap seconds cannot, in principle, be predicted in +** advance, a reliable check for dates beyond the valid range is +** impossible. To guard against gross errors, a year five or more +** after the release year of the present function (see the constant +** IYV) is considered dubious. In this case a warning status is +** returned but the result is computed in the normal way. +** +** For both too-early and too-late years, the warning status is +1. +** This is distinct from the error status -1, which signifies a year +** so early that JD could not be computed. +** +** 2) If the specified date is for a day which ends with a leap second, +** the TAI-UTC value returned is for the period leading up to the +** leap second. If the date is for a day which begins as a leap +** second ends, the TAI-UTC returned is for the period following the +** leap second. +** +** 3) The day number must be in the normal calendar range, for example +** 1 through 30 for April. The "almanac" convention of allowing +** such dates as January 0 and December 32 is not supported in this +** function, in order to avoid confusion near leap seconds. +** +** 4) The fraction of day is used only for dates before the +** introduction of leap seconds, the first of which occurred at the +** end of 1971. It is tested for validity (0 to 1 is the valid +** range) even if not used; if invalid, zero is used and status -4 +** is returned. For many applications, setting fd to zero is +** acceptable; the resulting error is always less than 3 ms (and +** occurs only pre-1972). +** +** 5) The status value returned in the case where there are multiple +** errors refers to the first error detected. For example, if the +** month and day are 13 and 32 respectively, status -2 (bad month) +** will be returned. The "internal error" status refers to a +** case that is impossible but causes some compilers to issue a +** warning. +** +** 6) In cases where a valid result is not available, zero is returned. +** +** References: +** +** 1) For dates from 1961 January 1 onwards, the expressions from the +** file ftp://maia.usno.navy.mil/ser7/tai-utc.dat are used. +** +** 2) The 5ms timestep at 1961 January 1 is taken from 2.58.1 (p87) of +** the 1992 Explanatory Supplement. +** +** Called: +** iauCal2jd Gregorian calendar to JD +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Release year for this version of iauDat */ + enum { IYV = 2021}; + +/* Reference dates (MJD) and drift rates (s/day), pre leap seconds */ + static const double drift[][2] = { + { 37300.0, 0.0012960 }, + { 37300.0, 0.0012960 }, + { 37300.0, 0.0012960 }, + { 37665.0, 0.0011232 }, + { 37665.0, 0.0011232 }, + { 38761.0, 0.0012960 }, + { 38761.0, 0.0012960 }, + { 38761.0, 0.0012960 }, + { 38761.0, 0.0012960 }, + { 38761.0, 0.0012960 }, + { 38761.0, 0.0012960 }, + { 38761.0, 0.0012960 }, + { 39126.0, 0.0025920 }, + { 39126.0, 0.0025920 } + }; + +/* Number of Delta(AT) expressions before leap seconds were introduced */ + enum { NERA1 = (int) (sizeof drift / sizeof (double) / 2) }; + +/* Dates and Delta(AT)s */ + static const struct { + int iyear, month; + double delat; + } changes[] = { + { 1960, 1, 1.4178180 }, + { 1961, 1, 1.4228180 }, + { 1961, 8, 1.3728180 }, + { 1962, 1, 1.8458580 }, + { 1963, 11, 1.9458580 }, + { 1964, 1, 3.2401300 }, + { 1964, 4, 3.3401300 }, + { 1964, 9, 3.4401300 }, + { 1965, 1, 3.5401300 }, + { 1965, 3, 3.6401300 }, + { 1965, 7, 3.7401300 }, + { 1965, 9, 3.8401300 }, + { 1966, 1, 4.3131700 }, + { 1968, 2, 4.2131700 }, + { 1972, 1, 10.0 }, + { 1972, 7, 11.0 }, + { 1973, 1, 12.0 }, + { 1974, 1, 13.0 }, + { 1975, 1, 14.0 }, + { 1976, 1, 15.0 }, + { 1977, 1, 16.0 }, + { 1978, 1, 17.0 }, + { 1979, 1, 18.0 }, + { 1980, 1, 19.0 }, + { 1981, 7, 20.0 }, + { 1982, 7, 21.0 }, + { 1983, 7, 22.0 }, + { 1985, 7, 23.0 }, + { 1988, 1, 24.0 }, + { 1990, 1, 25.0 }, + { 1991, 1, 26.0 }, + { 1992, 7, 27.0 }, + { 1993, 7, 28.0 }, + { 1994, 7, 29.0 }, + { 1996, 1, 30.0 }, + { 1997, 7, 31.0 }, + { 1999, 1, 32.0 }, + { 2006, 1, 33.0 }, + { 2009, 1, 34.0 }, + { 2012, 7, 35.0 }, + { 2015, 7, 36.0 }, + { 2017, 1, 37.0 } + }; + +/* Number of Delta(AT) changes */ + enum { NDAT = (int) (sizeof changes / sizeof changes[0]) }; + +/* Miscellaneous local variables */ + int j, i, m; + double da, djm0, djm; + + +/* Initialize the result to zero. */ + *deltat = da = 0.0; + +/* If invalid fraction of a day, set error status and give up. */ + if (fd < 0.0 || fd > 1.0) return -4; + +/* Convert the date into an MJD. */ + j = iauCal2jd(iy, im, id, &djm0, &djm); + +/* If invalid year, month, or day, give up. */ + if (j < 0) return j; + +/* If pre-UTC year, set warning status and give up. */ + if (iy < changes[0].iyear) return 1; + +/* If suspiciously late year, set warning status but proceed. */ + if (iy > IYV + 5) j = 1; + +/* Combine year and month to form a date-ordered integer... */ + m = 12*iy + im; + +/* ...and use it to find the preceding table entry. */ + for (i = NDAT-1; i >=0; i--) { + if (m >= (12 * changes[i].iyear + changes[i].month)) break; + } + +/* Prevent underflow warnings. */ + if (i < 0) return -5; + +/* Get the Delta(AT). */ + da = changes[i].delat; + +/* If pre-1972, adjust for drift. */ + if (i < NERA1) da += (djm + fd - drift[i][0]) * drift[i][1]; + +/* Return the Delta(AT) value. */ + *deltat = da; + +/* Return the status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2018 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) UNLIKE OTHER SOFA SOFTWARE, WHICH IS STRICTLY "READ ONLY", +** USERS ARE PERMITTED TO REPLACE THIS FUNCTION WITH ONE USING +** THE SAME NAME BUT DIFFERENT CODE. This is to allow use of +** locally supported mechanisms for keeping track of leap +** seconds, perhaps file or network based. It avoids the need +** for applications to be relinked periodically in order to pick +** up SOFA updates. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ + +} diff --git a/src/cpp/3rdparty/sofa/src/dtdb.c b/src/cpp/3rdparty/sofa/src/dtdb.c new file mode 100644 index 000000000..d5fdea9a6 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/dtdb.c @@ -0,0 +1,1266 @@ +#include "sofa.h" +#include "sofam.h" + +double iauDtdb(double date1, double date2, + double ut, double elong, double u, double v) +/* +** - - - - - - - - +** i a u D t d b +** - - - - - - - - +** +** An approximation to TDB-TT, the difference between barycentric +** dynamical time and terrestrial time, for an observer on the Earth. +** +** The different time scales - proper, coordinate and realized - are +** related to each other: +** +** TAI <- physically realized +** : +** offset <- observed (nominally +32.184s) +** : +** TT <- terrestrial time +** : +** rate adjustment (L_G) <- definition of TT +** : +** TCG <- time scale for GCRS +** : +** "periodic" terms <- iauDtdb is an implementation +** : +** rate adjustment (L_C) <- function of solar-system ephemeris +** : +** TCB <- time scale for BCRS +** : +** rate adjustment (-L_B) <- definition of TDB +** : +** TDB <- TCB scaled to track TT +** : +** "periodic" terms <- -iauDtdb is an approximation +** : +** TT <- terrestrial time +** +** Adopted values for the various constants can be found in the IERS +** Conventions (McCarthy & Petit 2003). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double date, TDB (Notes 1-3) +** ut double universal time (UT1, fraction of one day) +** elong double longitude (east positive, radians) +** u double distance from Earth spin axis (km) +** v double distance north of equatorial plane (km) +** +** Returned (function value): +** double TDB-TT (seconds) +** +** Notes: +** +** 1) The date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** Although the date is, formally, barycentric dynamical time (TDB), +** the terrestrial dynamical time (TT) can be used with no practical +** effect on the accuracy of the prediction. +** +** 2) TT can be regarded as a coordinate time that is realized as an +** offset of 32.184s from International Atomic Time, TAI. TT is a +** specific linear transformation of geocentric coordinate time TCG, +** which is the time scale for the Geocentric Celestial Reference +** System, GCRS. +** +** 3) TDB is a coordinate time, and is a specific linear transformation +** of barycentric coordinate time TCB, which is the time scale for +** the Barycentric Celestial Reference System, BCRS. +** +** 4) The difference TCG-TCB depends on the masses and positions of the +** bodies of the solar system and the velocity of the Earth. It is +** dominated by a rate difference, the residual being of a periodic +** character. The latter, which is modeled by the present function, +** comprises a main (annual) sinusoidal term of amplitude +** approximately 0.00166 seconds, plus planetary terms up to about +** 20 microseconds, and lunar and diurnal terms up to 2 microseconds. +** These effects come from the changing transverse Doppler effect +** and gravitational red-shift as the observer (on the Earth's +** surface) experiences variations in speed (with respect to the +** BCRS) and gravitational potential. +** +** 5) TDB can be regarded as the same as TCB but with a rate adjustment +** to keep it close to TT, which is convenient for many applications. +** The history of successive attempts to define TDB is set out in +** Resolution 3 adopted by the IAU General Assembly in 2006, which +** defines a fixed TDB(TCB) transformation that is consistent with +** contemporary solar-system ephemerides. Future ephemerides will +** imply slightly changed transformations between TCG and TCB, which +** could introduce a linear drift between TDB and TT; however, any +** such drift is unlikely to exceed 1 nanosecond per century. +** +** 6) The geocentric TDB-TT model used in the present function is that of +** Fairhead & Bretagnon (1990), in its full form. It was originally +** supplied by Fairhead (private communications with P.T.Wallace, +** 1990) as a Fortran subroutine. The present C function contains an +** adaptation of the Fairhead code. The numerical results are +** essentially unaffected by the changes, the differences with +** respect to the Fairhead & Bretagnon original being at the 1e-20 s +** level. +** +** The topocentric part of the model is from Moyer (1981) and +** Murray (1983), with fundamental arguments adapted from +** Simon et al. 1994. It is an approximation to the expression +** ( v / c ) . ( r / c ), where v is the barycentric velocity of +** the Earth, r is the geocentric position of the observer and +** c is the speed of light. +** +** By supplying zeroes for u and v, the topocentric part of the +** model can be nullified, and the function will return the Fairhead +** & Bretagnon result alone. +** +** 7) During the interval 1950-2050, the absolute accuracy is better +** than +/- 3 nanoseconds relative to time ephemerides obtained by +** direct numerical integrations based on the JPL DE405 solar system +** ephemeris. +** +** 8) It must be stressed that the present function is merely a model, +** and that numerical integration of solar-system ephemerides is the +** definitive method for predicting the relationship between TCG and +** TCB and hence between TT and TDB. +** +** References: +** +** Fairhead, L., & Bretagnon, P., Astron.Astrophys., 229, 240-247 +** (1990). +** +** IAU 2006 Resolution 3. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Moyer, T.D., Cel.Mech., 23, 33 (1981). +** +** Murray, C.A., Vectorial Astrometry, Adam Hilger (1983). +** +** Seidelmann, P.K. et al., Explanatory Supplement to the +** Astronomical Almanac, Chapter 2, University Science Books (1992). +** +** Simon, J.L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G. & Laskar, J., Astron.Astrophys., 282, 663-683 (1994). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, tsol, w, elsun, emsun, d, elj, els, wt, w0, w1, w2, w3, w4, + wf, wj; + int j; + +/* +** ===================== +** Fairhead et al. model +** ===================== +** +** 787 sets of three coefficients. +** +** Each set is +** amplitude (microseconds) +** frequency (radians per Julian millennium since J2000.0) +** phase (radians) +** +** Sets 1-474 are the T**0 terms +** " 475-679 " " T**1 +** " 680-764 " " T**2 +** " 765-784 " " T**3 +** " 785-787 " " T**4 +*/ + + static const double fairhd[787][3] = { + /* 1, 10 */ + { 1656.674564e-6, 6283.075849991, 6.240054195 }, + { 22.417471e-6, 5753.384884897, 4.296977442 }, + { 13.839792e-6, 12566.151699983, 6.196904410 }, + { 4.770086e-6, 529.690965095, 0.444401603 }, + { 4.676740e-6, 6069.776754553, 4.021195093 }, + { 2.256707e-6, 213.299095438, 5.543113262 }, + { 1.694205e-6, -3.523118349, 5.025132748 }, + { 1.554905e-6, 77713.771467920, 5.198467090 }, + { 1.276839e-6, 7860.419392439, 5.988822341 }, + { 1.193379e-6, 5223.693919802, 3.649823730 }, + /* 11, 20 */ + { 1.115322e-6, 3930.209696220, 1.422745069 }, + { 0.794185e-6, 11506.769769794, 2.322313077 }, + { 0.447061e-6, 26.298319800, 3.615796498 }, + { 0.435206e-6, -398.149003408, 4.349338347 }, + { 0.600309e-6, 1577.343542448, 2.678271909 }, + { 0.496817e-6, 6208.294251424, 5.696701824 }, + { 0.486306e-6, 5884.926846583, 0.520007179 }, + { 0.432392e-6, 74.781598567, 2.435898309 }, + { 0.468597e-6, 6244.942814354, 5.866398759 }, + { 0.375510e-6, 5507.553238667, 4.103476804 }, + /* 21, 30 */ + { 0.243085e-6, -775.522611324, 3.651837925 }, + { 0.173435e-6, 18849.227549974, 6.153743485 }, + { 0.230685e-6, 5856.477659115, 4.773852582 }, + { 0.203747e-6, 12036.460734888, 4.333987818 }, + { 0.143935e-6, -796.298006816, 5.957517795 }, + { 0.159080e-6, 10977.078804699, 1.890075226 }, + { 0.119979e-6, 38.133035638, 4.551585768 }, + { 0.118971e-6, 5486.777843175, 1.914547226 }, + { 0.116120e-6, 1059.381930189, 0.873504123 }, + { 0.137927e-6, 11790.629088659, 1.135934669 }, + /* 31, 40 */ + { 0.098358e-6, 2544.314419883, 0.092793886 }, + { 0.101868e-6, -5573.142801634, 5.984503847 }, + { 0.080164e-6, 206.185548437, 2.095377709 }, + { 0.079645e-6, 4694.002954708, 2.949233637 }, + { 0.062617e-6, 20.775395492, 2.654394814 }, + { 0.075019e-6, 2942.463423292, 4.980931759 }, + { 0.064397e-6, 5746.271337896, 1.280308748 }, + { 0.063814e-6, 5760.498431898, 4.167901731 }, + { 0.048042e-6, 2146.165416475, 1.495846011 }, + { 0.048373e-6, 155.420399434, 2.251573730 }, + /* 41, 50 */ + { 0.058844e-6, 426.598190876, 4.839650148 }, + { 0.046551e-6, -0.980321068, 0.921573539 }, + { 0.054139e-6, 17260.154654690, 3.411091093 }, + { 0.042411e-6, 6275.962302991, 2.869567043 }, + { 0.040184e-6, -7.113547001, 3.565975565 }, + { 0.036564e-6, 5088.628839767, 3.324679049 }, + { 0.040759e-6, 12352.852604545, 3.981496998 }, + { 0.036507e-6, 801.820931124, 6.248866009 }, + { 0.036955e-6, 3154.687084896, 5.071801441 }, + { 0.042732e-6, 632.783739313, 5.720622217 }, + /* 51, 60 */ + { 0.042560e-6, 161000.685737473, 1.270837679 }, + { 0.040480e-6, 15720.838784878, 2.546610123 }, + { 0.028244e-6, -6286.598968340, 5.069663519 }, + { 0.033477e-6, 6062.663207553, 4.144987272 }, + { 0.034867e-6, 522.577418094, 5.210064075 }, + { 0.032438e-6, 6076.890301554, 0.749317412 }, + { 0.030215e-6, 7084.896781115, 3.389610345 }, + { 0.029247e-6, -71430.695617928, 4.183178762 }, + { 0.033529e-6, 9437.762934887, 2.404714239 }, + { 0.032423e-6, 8827.390269875, 5.541473556 }, + /* 61, 70 */ + { 0.027567e-6, 6279.552731642, 5.040846034 }, + { 0.029862e-6, 12139.553509107, 1.770181024 }, + { 0.022509e-6, 10447.387839604, 1.460726241 }, + { 0.020937e-6, 8429.241266467, 0.652303414 }, + { 0.020322e-6, 419.484643875, 3.735430632 }, + { 0.024816e-6, -1194.447010225, 1.087136918 }, + { 0.025196e-6, 1748.016413067, 2.901883301 }, + { 0.021691e-6, 14143.495242431, 5.952658009 }, + { 0.017673e-6, 6812.766815086, 3.186129845 }, + { 0.022567e-6, 6133.512652857, 3.307984806 }, + /* 71, 80 */ + { 0.016155e-6, 10213.285546211, 1.331103168 }, + { 0.014751e-6, 1349.867409659, 4.308933301 }, + { 0.015949e-6, -220.412642439, 4.005298270 }, + { 0.015974e-6, -2352.866153772, 6.145309371 }, + { 0.014223e-6, 17789.845619785, 2.104551349 }, + { 0.017806e-6, 73.297125859, 3.475975097 }, + { 0.013671e-6, -536.804512095, 5.971672571 }, + { 0.011942e-6, 8031.092263058, 2.053414715 }, + { 0.014318e-6, 16730.463689596, 3.016058075 }, + { 0.012462e-6, 103.092774219, 1.737438797 }, + /* 81, 90 */ + { 0.010962e-6, 3.590428652, 2.196567739 }, + { 0.015078e-6, 19651.048481098, 3.969480770 }, + { 0.010396e-6, 951.718406251, 5.717799605 }, + { 0.011707e-6, -4705.732307544, 2.654125618 }, + { 0.010453e-6, 5863.591206116, 1.913704550 }, + { 0.012420e-6, 4690.479836359, 4.734090399 }, + { 0.011847e-6, 5643.178563677, 5.489005403 }, + { 0.008610e-6, 3340.612426700, 3.661698944 }, + { 0.011622e-6, 5120.601145584, 4.863931876 }, + { 0.010825e-6, 553.569402842, 0.842715011 }, + /* 91, 100 */ + { 0.008666e-6, -135.065080035, 3.293406547 }, + { 0.009963e-6, 149.563197135, 4.870690598 }, + { 0.009858e-6, 6309.374169791, 1.061816410 }, + { 0.007959e-6, 316.391869657, 2.465042647 }, + { 0.010099e-6, 283.859318865, 1.942176992 }, + { 0.007147e-6, -242.728603974, 3.661486981 }, + { 0.007505e-6, 5230.807466803, 4.920937029 }, + { 0.008323e-6, 11769.853693166, 1.229392026 }, + { 0.007490e-6, -6256.777530192, 3.658444681 }, + { 0.009370e-6, 149854.400134205, 0.673880395 }, + /* 101, 110 */ + { 0.007117e-6, 38.027672636, 5.294249518 }, + { 0.007857e-6, 12168.002696575, 0.525733528 }, + { 0.007019e-6, 6206.809778716, 0.837688810 }, + { 0.006056e-6, 955.599741609, 4.194535082 }, + { 0.008107e-6, 13367.972631107, 3.793235253 }, + { 0.006731e-6, 5650.292110678, 5.639906583 }, + { 0.007332e-6, 36.648562930, 0.114858677 }, + { 0.006366e-6, 4164.311989613, 2.262081818 }, + { 0.006858e-6, 5216.580372801, 0.642063318 }, + { 0.006919e-6, 6681.224853400, 6.018501522 }, + /* 111, 120 */ + { 0.006826e-6, 7632.943259650, 3.458654112 }, + { 0.005308e-6, -1592.596013633, 2.500382359 }, + { 0.005096e-6, 11371.704689758, 2.547107806 }, + { 0.004841e-6, 5333.900241022, 0.437078094 }, + { 0.005582e-6, 5966.683980335, 2.246174308 }, + { 0.006304e-6, 11926.254413669, 2.512929171 }, + { 0.006603e-6, 23581.258177318, 5.393136889 }, + { 0.005123e-6, -1.484472708, 2.999641028 }, + { 0.004648e-6, 1589.072895284, 1.275847090 }, + { 0.005119e-6, 6438.496249426, 1.486539246 }, + /* 121, 130 */ + { 0.004521e-6, 4292.330832950, 6.140635794 }, + { 0.005680e-6, 23013.539539587, 4.557814849 }, + { 0.005488e-6, -3.455808046, 0.090675389 }, + { 0.004193e-6, 7234.794256242, 4.869091389 }, + { 0.003742e-6, 7238.675591600, 4.691976180 }, + { 0.004148e-6, -110.206321219, 3.016173439 }, + { 0.004553e-6, 11499.656222793, 5.554998314 }, + { 0.004892e-6, 5436.993015240, 1.475415597 }, + { 0.004044e-6, 4732.030627343, 1.398784824 }, + { 0.004164e-6, 12491.370101415, 5.650931916 }, + /* 131, 140 */ + { 0.004349e-6, 11513.883316794, 2.181745369 }, + { 0.003919e-6, 12528.018664345, 5.823319737 }, + { 0.003129e-6, 6836.645252834, 0.003844094 }, + { 0.004080e-6, -7058.598461315, 3.690360123 }, + { 0.003270e-6, 76.266071276, 1.517189902 }, + { 0.002954e-6, 6283.143160294, 4.447203799 }, + { 0.002872e-6, 28.449187468, 1.158692983 }, + { 0.002881e-6, 735.876513532, 0.349250250 }, + { 0.003279e-6, 5849.364112115, 4.893384368 }, + { 0.003625e-6, 6209.778724132, 1.473760578 }, + /* 141, 150 */ + { 0.003074e-6, 949.175608970, 5.185878737 }, + { 0.002775e-6, 9917.696874510, 1.030026325 }, + { 0.002646e-6, 10973.555686350, 3.918259169 }, + { 0.002575e-6, 25132.303399966, 6.109659023 }, + { 0.003500e-6, 263.083923373, 1.892100742 }, + { 0.002740e-6, 18319.536584880, 4.320519510 }, + { 0.002464e-6, 202.253395174, 4.698203059 }, + { 0.002409e-6, 2.542797281, 5.325009315 }, + { 0.003354e-6, -90955.551694697, 1.942656623 }, + { 0.002296e-6, 6496.374945429, 5.061810696 }, + /* 151, 160 */ + { 0.003002e-6, 6172.869528772, 2.797822767 }, + { 0.003202e-6, 27511.467873537, 0.531673101 }, + { 0.002954e-6, -6283.008539689, 4.533471191 }, + { 0.002353e-6, 639.897286314, 3.734548088 }, + { 0.002401e-6, 16200.772724501, 2.605547070 }, + { 0.003053e-6, 233141.314403759, 3.029030662 }, + { 0.003024e-6, 83286.914269554, 2.355556099 }, + { 0.002863e-6, 17298.182327326, 5.240963796 }, + { 0.002103e-6, -7079.373856808, 5.756641637 }, + { 0.002303e-6, 83996.847317911, 2.013686814 }, + /* 161, 170 */ + { 0.002303e-6, 18073.704938650, 1.089100410 }, + { 0.002381e-6, 63.735898303, 0.759188178 }, + { 0.002493e-6, 6386.168624210, 0.645026535 }, + { 0.002366e-6, 3.932153263, 6.215885448 }, + { 0.002169e-6, 11015.106477335, 4.845297676 }, + { 0.002397e-6, 6243.458341645, 3.809290043 }, + { 0.002183e-6, 1162.474704408, 6.179611691 }, + { 0.002353e-6, 6246.427287062, 4.781719760 }, + { 0.002199e-6, -245.831646229, 5.956152284 }, + { 0.001729e-6, 3894.181829542, 1.264976635 }, + /* 171, 180 */ + { 0.001896e-6, -3128.388765096, 4.914231596 }, + { 0.002085e-6, 35.164090221, 1.405158503 }, + { 0.002024e-6, 14712.317116458, 2.752035928 }, + { 0.001737e-6, 6290.189396992, 5.280820144 }, + { 0.002229e-6, 491.557929457, 1.571007057 }, + { 0.001602e-6, 14314.168113050, 4.203664806 }, + { 0.002186e-6, 454.909366527, 1.402101526 }, + { 0.001897e-6, 22483.848574493, 4.167932508 }, + { 0.001825e-6, -3738.761430108, 0.545828785 }, + { 0.001894e-6, 1052.268383188, 5.817167450 }, + /* 181, 190 */ + { 0.001421e-6, 20.355319399, 2.419886601 }, + { 0.001408e-6, 10984.192351700, 2.732084787 }, + { 0.001847e-6, 10873.986030480, 2.903477885 }, + { 0.001391e-6, -8635.942003763, 0.593891500 }, + { 0.001388e-6, -7.046236698, 1.166145902 }, + { 0.001810e-6, -88860.057071188, 0.487355242 }, + { 0.001288e-6, -1990.745017041, 3.913022880 }, + { 0.001297e-6, 23543.230504682, 3.063805171 }, + { 0.001335e-6, -266.607041722, 3.995764039 }, + { 0.001376e-6, 10969.965257698, 5.152914309 }, + /* 191, 200 */ + { 0.001745e-6, 244287.600007027, 3.626395673 }, + { 0.001649e-6, 31441.677569757, 1.952049260 }, + { 0.001416e-6, 9225.539273283, 4.996408389 }, + { 0.001238e-6, 4804.209275927, 5.503379738 }, + { 0.001472e-6, 4590.910180489, 4.164913291 }, + { 0.001169e-6, 6040.347246017, 5.841719038 }, + { 0.001039e-6, 5540.085789459, 2.769753519 }, + { 0.001004e-6, -170.672870619, 0.755008103 }, + { 0.001284e-6, 10575.406682942, 5.306538209 }, + { 0.001278e-6, 71.812653151, 4.713486491 }, + /* 201, 210 */ + { 0.001321e-6, 18209.330263660, 2.624866359 }, + { 0.001297e-6, 21228.392023546, 0.382603541 }, + { 0.000954e-6, 6282.095528923, 0.882213514 }, + { 0.001145e-6, 6058.731054289, 1.169483931 }, + { 0.000979e-6, 5547.199336460, 5.448375984 }, + { 0.000987e-6, -6262.300454499, 2.656486959 }, + { 0.001070e-6, -154717.609887482, 1.827624012 }, + { 0.000991e-6, 4701.116501708, 4.387001801 }, + { 0.001155e-6, -14.227094002, 3.042700750 }, + { 0.001176e-6, 277.034993741, 3.335519004 }, + /* 211, 220 */ + { 0.000890e-6, 13916.019109642, 5.601498297 }, + { 0.000884e-6, -1551.045222648, 1.088831705 }, + { 0.000876e-6, 5017.508371365, 3.969902609 }, + { 0.000806e-6, 15110.466119866, 5.142876744 }, + { 0.000773e-6, -4136.910433516, 0.022067765 }, + { 0.001077e-6, 175.166059800, 1.844913056 }, + { 0.000954e-6, -6284.056171060, 0.968480906 }, + { 0.000737e-6, 5326.786694021, 4.923831588 }, + { 0.000845e-6, -433.711737877, 4.749245231 }, + { 0.000819e-6, 8662.240323563, 5.991247817 }, + /* 221, 230 */ + { 0.000852e-6, 199.072001436, 2.189604979 }, + { 0.000723e-6, 17256.631536341, 6.068719637 }, + { 0.000940e-6, 6037.244203762, 6.197428148 }, + { 0.000885e-6, 11712.955318231, 3.280414875 }, + { 0.000706e-6, 12559.038152982, 2.824848947 }, + { 0.000732e-6, 2379.164473572, 2.501813417 }, + { 0.000764e-6, -6127.655450557, 2.236346329 }, + { 0.000908e-6, 131.541961686, 2.521257490 }, + { 0.000907e-6, 35371.887265976, 3.370195967 }, + { 0.000673e-6, 1066.495477190, 3.876512374 }, + /* 231, 240 */ + { 0.000814e-6, 17654.780539750, 4.627122566 }, + { 0.000630e-6, 36.027866677, 0.156368499 }, + { 0.000798e-6, 515.463871093, 5.151962502 }, + { 0.000798e-6, 148.078724426, 5.909225055 }, + { 0.000806e-6, 309.278322656, 6.054064447 }, + { 0.000607e-6, -39.617508346, 2.839021623 }, + { 0.000601e-6, 412.371096874, 3.984225404 }, + { 0.000646e-6, 11403.676995575, 3.852959484 }, + { 0.000704e-6, 13521.751441591, 2.300991267 }, + { 0.000603e-6, -65147.619767937, 4.140083146 }, + /* 241, 250 */ + { 0.000609e-6, 10177.257679534, 0.437122327 }, + { 0.000631e-6, 5767.611978898, 4.026532329 }, + { 0.000576e-6, 11087.285125918, 4.760293101 }, + { 0.000674e-6, 14945.316173554, 6.270510511 }, + { 0.000726e-6, 5429.879468239, 6.039606892 }, + { 0.000710e-6, 28766.924424484, 5.672617711 }, + { 0.000647e-6, 11856.218651625, 3.397132627 }, + { 0.000678e-6, -5481.254918868, 6.249666675 }, + { 0.000618e-6, 22003.914634870, 2.466427018 }, + { 0.000738e-6, 6134.997125565, 2.242668890 }, + /* 251, 260 */ + { 0.000660e-6, 625.670192312, 5.864091907 }, + { 0.000694e-6, 3496.032826134, 2.668309141 }, + { 0.000531e-6, 6489.261398429, 1.681888780 }, + { 0.000611e-6, -143571.324284214, 2.424978312 }, + { 0.000575e-6, 12043.574281889, 4.216492400 }, + { 0.000553e-6, 12416.588502848, 4.772158039 }, + { 0.000689e-6, 4686.889407707, 6.224271088 }, + { 0.000495e-6, 7342.457780181, 3.817285811 }, + { 0.000567e-6, 3634.621024518, 1.649264690 }, + { 0.000515e-6, 18635.928454536, 3.945345892 }, + /* 261, 270 */ + { 0.000486e-6, -323.505416657, 4.061673868 }, + { 0.000662e-6, 25158.601719765, 1.794058369 }, + { 0.000509e-6, 846.082834751, 3.053874588 }, + { 0.000472e-6, -12569.674818332, 5.112133338 }, + { 0.000461e-6, 6179.983075773, 0.513669325 }, + { 0.000641e-6, 83467.156352816, 3.210727723 }, + { 0.000520e-6, 10344.295065386, 2.445597761 }, + { 0.000493e-6, 18422.629359098, 1.676939306 }, + { 0.000478e-6, 1265.567478626, 5.487314569 }, + { 0.000472e-6, -18.159247265, 1.999707589 }, + /* 271, 280 */ + { 0.000559e-6, 11190.377900137, 5.783236356 }, + { 0.000494e-6, 9623.688276691, 3.022645053 }, + { 0.000463e-6, 5739.157790895, 1.411223013 }, + { 0.000432e-6, 16858.482532933, 1.179256434 }, + { 0.000574e-6, 72140.628666286, 1.758191830 }, + { 0.000484e-6, 17267.268201691, 3.290589143 }, + { 0.000550e-6, 4907.302050146, 0.864024298 }, + { 0.000399e-6, 14.977853527, 2.094441910 }, + { 0.000491e-6, 224.344795702, 0.878372791 }, + { 0.000432e-6, 20426.571092422, 6.003829241 }, + /* 281, 290 */ + { 0.000481e-6, 5749.452731634, 4.309591964 }, + { 0.000480e-6, 5757.317038160, 1.142348571 }, + { 0.000485e-6, 6702.560493867, 0.210580917 }, + { 0.000426e-6, 6055.549660552, 4.274476529 }, + { 0.000480e-6, 5959.570433334, 5.031351030 }, + { 0.000466e-6, 12562.628581634, 4.959581597 }, + { 0.000520e-6, 39302.096962196, 4.788002889 }, + { 0.000458e-6, 12132.439962106, 1.880103788 }, + { 0.000470e-6, 12029.347187887, 1.405611197 }, + { 0.000416e-6, -7477.522860216, 1.082356330 }, + /* 291, 300 */ + { 0.000449e-6, 11609.862544012, 4.179989585 }, + { 0.000465e-6, 17253.041107690, 0.353496295 }, + { 0.000362e-6, -4535.059436924, 1.583849576 }, + { 0.000383e-6, 21954.157609398, 3.747376371 }, + { 0.000389e-6, 17.252277143, 1.395753179 }, + { 0.000331e-6, 18052.929543158, 0.566790582 }, + { 0.000430e-6, 13517.870106233, 0.685827538 }, + { 0.000368e-6, -5756.908003246, 0.731374317 }, + { 0.000330e-6, 10557.594160824, 3.710043680 }, + { 0.000332e-6, 20199.094959633, 1.652901407 }, + /* 301, 310 */ + { 0.000384e-6, 11933.367960670, 5.827781531 }, + { 0.000387e-6, 10454.501386605, 2.541182564 }, + { 0.000325e-6, 15671.081759407, 2.178850542 }, + { 0.000318e-6, 138.517496871, 2.253253037 }, + { 0.000305e-6, 9388.005909415, 0.578340206 }, + { 0.000352e-6, 5749.861766548, 3.000297967 }, + { 0.000311e-6, 6915.859589305, 1.693574249 }, + { 0.000297e-6, 24072.921469776, 1.997249392 }, + { 0.000363e-6, -640.877607382, 5.071820966 }, + { 0.000323e-6, 12592.450019783, 1.072262823 }, + /* 311, 320 */ + { 0.000341e-6, 12146.667056108, 4.700657997 }, + { 0.000290e-6, 9779.108676125, 1.812320441 }, + { 0.000342e-6, 6132.028180148, 4.322238614 }, + { 0.000329e-6, 6268.848755990, 3.033827743 }, + { 0.000374e-6, 17996.031168222, 3.388716544 }, + { 0.000285e-6, -533.214083444, 4.687313233 }, + { 0.000338e-6, 6065.844601290, 0.877776108 }, + { 0.000276e-6, 24.298513841, 0.770299429 }, + { 0.000336e-6, -2388.894020449, 5.353796034 }, + { 0.000290e-6, 3097.883822726, 4.075291557 }, + /* 321, 330 */ + { 0.000318e-6, 709.933048357, 5.941207518 }, + { 0.000271e-6, 13095.842665077, 3.208912203 }, + { 0.000331e-6, 6073.708907816, 4.007881169 }, + { 0.000292e-6, 742.990060533, 2.714333592 }, + { 0.000362e-6, 29088.811415985, 3.215977013 }, + { 0.000280e-6, 12359.966151546, 0.710872502 }, + { 0.000267e-6, 10440.274292604, 4.730108488 }, + { 0.000262e-6, 838.969287750, 1.327720272 }, + { 0.000250e-6, 16496.361396202, 0.898769761 }, + { 0.000325e-6, 20597.243963041, 0.180044365 }, + /* 331, 340 */ + { 0.000268e-6, 6148.010769956, 5.152666276 }, + { 0.000284e-6, 5636.065016677, 5.655385808 }, + { 0.000301e-6, 6080.822454817, 2.135396205 }, + { 0.000294e-6, -377.373607916, 3.708784168 }, + { 0.000236e-6, 2118.763860378, 1.733578756 }, + { 0.000234e-6, 5867.523359379, 5.575209112 }, + { 0.000268e-6, -226858.238553767, 0.069432392 }, + { 0.000265e-6, 167283.761587465, 4.369302826 }, + { 0.000280e-6, 28237.233459389, 5.304829118 }, + { 0.000292e-6, 12345.739057544, 4.096094132 }, + /* 341, 350 */ + { 0.000223e-6, 19800.945956225, 3.069327406 }, + { 0.000301e-6, 43232.306658416, 6.205311188 }, + { 0.000264e-6, 18875.525869774, 1.417263408 }, + { 0.000304e-6, -1823.175188677, 3.409035232 }, + { 0.000301e-6, 109.945688789, 0.510922054 }, + { 0.000260e-6, 813.550283960, 2.389438934 }, + { 0.000299e-6, 316428.228673312, 5.384595078 }, + { 0.000211e-6, 5756.566278634, 3.789392838 }, + { 0.000209e-6, 5750.203491159, 1.661943545 }, + { 0.000240e-6, 12489.885628707, 5.684549045 }, + /* 351, 360 */ + { 0.000216e-6, 6303.851245484, 3.862942261 }, + { 0.000203e-6, 1581.959348283, 5.549853589 }, + { 0.000200e-6, 5642.198242609, 1.016115785 }, + { 0.000197e-6, -70.849445304, 4.690702525 }, + { 0.000227e-6, 6287.008003254, 2.911891613 }, + { 0.000197e-6, 533.623118358, 1.048982898 }, + { 0.000205e-6, -6279.485421340, 1.829362730 }, + { 0.000209e-6, -10988.808157535, 2.636140084 }, + { 0.000208e-6, -227.526189440, 4.127883842 }, + { 0.000191e-6, 415.552490612, 4.401165650 }, + /* 361, 370 */ + { 0.000190e-6, 29296.615389579, 4.175658539 }, + { 0.000264e-6, 66567.485864652, 4.601102551 }, + { 0.000256e-6, -3646.350377354, 0.506364778 }, + { 0.000188e-6, 13119.721102825, 2.032195842 }, + { 0.000185e-6, -209.366942175, 4.694756586 }, + { 0.000198e-6, 25934.124331089, 3.832703118 }, + { 0.000195e-6, 4061.219215394, 3.308463427 }, + { 0.000234e-6, 5113.487598583, 1.716090661 }, + { 0.000188e-6, 1478.866574064, 5.686865780 }, + { 0.000222e-6, 11823.161639450, 1.942386641 }, + /* 371, 380 */ + { 0.000181e-6, 10770.893256262, 1.999482059 }, + { 0.000171e-6, 6546.159773364, 1.182807992 }, + { 0.000206e-6, 70.328180442, 5.934076062 }, + { 0.000169e-6, 20995.392966449, 2.169080622 }, + { 0.000191e-6, 10660.686935042, 5.405515999 }, + { 0.000228e-6, 33019.021112205, 4.656985514 }, + { 0.000184e-6, -4933.208440333, 3.327476868 }, + { 0.000220e-6, -135.625325010, 1.765430262 }, + { 0.000166e-6, 23141.558382925, 3.454132746 }, + { 0.000191e-6, 6144.558353121, 5.020393445 }, + /* 381, 390 */ + { 0.000180e-6, 6084.003848555, 0.602182191 }, + { 0.000163e-6, 17782.732072784, 4.960593133 }, + { 0.000225e-6, 16460.333529525, 2.596451817 }, + { 0.000222e-6, 5905.702242076, 3.731990323 }, + { 0.000204e-6, 227.476132789, 5.636192701 }, + { 0.000159e-6, 16737.577236597, 3.600691544 }, + { 0.000200e-6, 6805.653268085, 0.868220961 }, + { 0.000187e-6, 11919.140866668, 2.629456641 }, + { 0.000161e-6, 127.471796607, 2.862574720 }, + { 0.000205e-6, 6286.666278643, 1.742882331 }, + /* 391, 400 */ + { 0.000189e-6, 153.778810485, 4.812372643 }, + { 0.000168e-6, 16723.350142595, 0.027860588 }, + { 0.000149e-6, 11720.068865232, 0.659721876 }, + { 0.000189e-6, 5237.921013804, 5.245313000 }, + { 0.000143e-6, 6709.674040867, 4.317625647 }, + { 0.000146e-6, 4487.817406270, 4.815297007 }, + { 0.000144e-6, -664.756045130, 5.381366880 }, + { 0.000175e-6, 5127.714692584, 4.728443327 }, + { 0.000162e-6, 6254.626662524, 1.435132069 }, + { 0.000187e-6, 47162.516354635, 1.354371923 }, + /* 401, 410 */ + { 0.000146e-6, 11080.171578918, 3.369695406 }, + { 0.000180e-6, -348.924420448, 2.490902145 }, + { 0.000148e-6, 151.047669843, 3.799109588 }, + { 0.000157e-6, 6197.248551160, 1.284375887 }, + { 0.000167e-6, 146.594251718, 0.759969109 }, + { 0.000133e-6, -5331.357443741, 5.409701889 }, + { 0.000154e-6, 95.979227218, 3.366890614 }, + { 0.000148e-6, -6418.140930027, 3.384104996 }, + { 0.000128e-6, -6525.804453965, 3.803419985 }, + { 0.000130e-6, 11293.470674356, 0.939039445 }, + /* 411, 420 */ + { 0.000152e-6, -5729.506447149, 0.734117523 }, + { 0.000138e-6, 210.117701700, 2.564216078 }, + { 0.000123e-6, 6066.595360816, 4.517099537 }, + { 0.000140e-6, 18451.078546566, 0.642049130 }, + { 0.000126e-6, 11300.584221356, 3.485280663 }, + { 0.000119e-6, 10027.903195729, 3.217431161 }, + { 0.000151e-6, 4274.518310832, 4.404359108 }, + { 0.000117e-6, 6072.958148291, 0.366324650 }, + { 0.000165e-6, -7668.637425143, 4.298212528 }, + { 0.000117e-6, -6245.048177356, 5.379518958 }, + /* 421, 430 */ + { 0.000130e-6, -5888.449964932, 4.527681115 }, + { 0.000121e-6, -543.918059096, 6.109429504 }, + { 0.000162e-6, 9683.594581116, 5.720092446 }, + { 0.000141e-6, 6219.339951688, 0.679068671 }, + { 0.000118e-6, 22743.409379516, 4.881123092 }, + { 0.000129e-6, 1692.165669502, 0.351407289 }, + { 0.000126e-6, 5657.405657679, 5.146592349 }, + { 0.000114e-6, 728.762966531, 0.520791814 }, + { 0.000120e-6, 52.596639600, 0.948516300 }, + { 0.000115e-6, 65.220371012, 3.504914846 }, + /* 431, 440 */ + { 0.000126e-6, 5881.403728234, 5.577502482 }, + { 0.000158e-6, 163096.180360983, 2.957128968 }, + { 0.000134e-6, 12341.806904281, 2.598576764 }, + { 0.000151e-6, 16627.370915377, 3.985702050 }, + { 0.000109e-6, 1368.660252845, 0.014730471 }, + { 0.000131e-6, 6211.263196841, 0.085077024 }, + { 0.000146e-6, 5792.741760812, 0.708426604 }, + { 0.000146e-6, -77.750543984, 3.121576600 }, + { 0.000107e-6, 5341.013788022, 0.288231904 }, + { 0.000138e-6, 6281.591377283, 2.797450317 }, + /* 441, 450 */ + { 0.000113e-6, -6277.552925684, 2.788904128 }, + { 0.000115e-6, -525.758811831, 5.895222200 }, + { 0.000138e-6, 6016.468808270, 6.096188999 }, + { 0.000139e-6, 23539.707386333, 2.028195445 }, + { 0.000146e-6, -4176.041342449, 4.660008502 }, + { 0.000107e-6, 16062.184526117, 4.066520001 }, + { 0.000142e-6, 83783.548222473, 2.936315115 }, + { 0.000128e-6, 9380.959672717, 3.223844306 }, + { 0.000135e-6, 6205.325306007, 1.638054048 }, + { 0.000101e-6, 2699.734819318, 5.481603249 }, + /* 451, 460 */ + { 0.000104e-6, -568.821874027, 2.205734493 }, + { 0.000103e-6, 6321.103522627, 2.440421099 }, + { 0.000119e-6, 6321.208885629, 2.547496264 }, + { 0.000138e-6, 1975.492545856, 2.314608466 }, + { 0.000121e-6, 137.033024162, 4.539108237 }, + { 0.000123e-6, 19402.796952817, 4.538074405 }, + { 0.000119e-6, 22805.735565994, 2.869040566 }, + { 0.000133e-6, 64471.991241142, 6.056405489 }, + { 0.000129e-6, -85.827298831, 2.540635083 }, + { 0.000131e-6, 13613.804277336, 4.005732868 }, + /* 461, 470 */ + { 0.000104e-6, 9814.604100291, 1.959967212 }, + { 0.000112e-6, 16097.679950283, 3.589026260 }, + { 0.000123e-6, 2107.034507542, 1.728627253 }, + { 0.000121e-6, 36949.230808424, 6.072332087 }, + { 0.000108e-6, -12539.853380183, 3.716133846 }, + { 0.000113e-6, -7875.671863624, 2.725771122 }, + { 0.000109e-6, 4171.425536614, 4.033338079 }, + { 0.000101e-6, 6247.911759770, 3.441347021 }, + { 0.000113e-6, 7330.728427345, 0.656372122 }, + { 0.000113e-6, 51092.726050855, 2.791483066 }, + /* 471, 480 */ + { 0.000106e-6, 5621.842923210, 1.815323326 }, + { 0.000101e-6, 111.430161497, 5.711033677 }, + { 0.000103e-6, 909.818733055, 2.812745443 }, + { 0.000101e-6, 1790.642637886, 1.965746028 }, + + /* T */ + { 102.156724e-6, 6283.075849991, 4.249032005 }, + { 1.706807e-6, 12566.151699983, 4.205904248 }, + { 0.269668e-6, 213.299095438, 3.400290479 }, + { 0.265919e-6, 529.690965095, 5.836047367 }, + { 0.210568e-6, -3.523118349, 6.262738348 }, + { 0.077996e-6, 5223.693919802, 4.670344204 }, + /* 481, 490 */ + { 0.054764e-6, 1577.343542448, 4.534800170 }, + { 0.059146e-6, 26.298319800, 1.083044735 }, + { 0.034420e-6, -398.149003408, 5.980077351 }, + { 0.032088e-6, 18849.227549974, 4.162913471 }, + { 0.033595e-6, 5507.553238667, 5.980162321 }, + { 0.029198e-6, 5856.477659115, 0.623811863 }, + { 0.027764e-6, 155.420399434, 3.745318113 }, + { 0.025190e-6, 5746.271337896, 2.980330535 }, + { 0.022997e-6, -796.298006816, 1.174411803 }, + { 0.024976e-6, 5760.498431898, 2.467913690 }, + /* 491, 500 */ + { 0.021774e-6, 206.185548437, 3.854787540 }, + { 0.017925e-6, -775.522611324, 1.092065955 }, + { 0.013794e-6, 426.598190876, 2.699831988 }, + { 0.013276e-6, 6062.663207553, 5.845801920 }, + { 0.011774e-6, 12036.460734888, 2.292832062 }, + { 0.012869e-6, 6076.890301554, 5.333425680 }, + { 0.012152e-6, 1059.381930189, 6.222874454 }, + { 0.011081e-6, -7.113547001, 5.154724984 }, + { 0.010143e-6, 4694.002954708, 4.044013795 }, + { 0.009357e-6, 5486.777843175, 3.416081409 }, + /* 501, 510 */ + { 0.010084e-6, 522.577418094, 0.749320262 }, + { 0.008587e-6, 10977.078804699, 2.777152598 }, + { 0.008628e-6, 6275.962302991, 4.562060226 }, + { 0.008158e-6, -220.412642439, 5.806891533 }, + { 0.007746e-6, 2544.314419883, 1.603197066 }, + { 0.007670e-6, 2146.165416475, 3.000200440 }, + { 0.007098e-6, 74.781598567, 0.443725817 }, + { 0.006180e-6, -536.804512095, 1.302642751 }, + { 0.005818e-6, 5088.628839767, 4.827723531 }, + { 0.004945e-6, -6286.598968340, 0.268305170 }, + /* 511, 520 */ + { 0.004774e-6, 1349.867409659, 5.808636673 }, + { 0.004687e-6, -242.728603974, 5.154890570 }, + { 0.006089e-6, 1748.016413067, 4.403765209 }, + { 0.005975e-6, -1194.447010225, 2.583472591 }, + { 0.004229e-6, 951.718406251, 0.931172179 }, + { 0.005264e-6, 553.569402842, 2.336107252 }, + { 0.003049e-6, 5643.178563677, 1.362634430 }, + { 0.002974e-6, 6812.766815086, 1.583012668 }, + { 0.003403e-6, -2352.866153772, 2.552189886 }, + { 0.003030e-6, 419.484643875, 5.286473844 }, + /* 521, 530 */ + { 0.003210e-6, -7.046236698, 1.863796539 }, + { 0.003058e-6, 9437.762934887, 4.226420633 }, + { 0.002589e-6, 12352.852604545, 1.991935820 }, + { 0.002927e-6, 5216.580372801, 2.319951253 }, + { 0.002425e-6, 5230.807466803, 3.084752833 }, + { 0.002656e-6, 3154.687084896, 2.487447866 }, + { 0.002445e-6, 10447.387839604, 2.347139160 }, + { 0.002990e-6, 4690.479836359, 6.235872050 }, + { 0.002890e-6, 5863.591206116, 0.095197563 }, + { 0.002498e-6, 6438.496249426, 2.994779800 }, + /* 531, 540 */ + { 0.001889e-6, 8031.092263058, 3.569003717 }, + { 0.002567e-6, 801.820931124, 3.425611498 }, + { 0.001803e-6, -71430.695617928, 2.192295512 }, + { 0.001782e-6, 3.932153263, 5.180433689 }, + { 0.001694e-6, -4705.732307544, 4.641779174 }, + { 0.001704e-6, -1592.596013633, 3.997097652 }, + { 0.001735e-6, 5849.364112115, 0.417558428 }, + { 0.001643e-6, 8429.241266467, 2.180619584 }, + { 0.001680e-6, 38.133035638, 4.164529426 }, + { 0.002045e-6, 7084.896781115, 0.526323854 }, + /* 541, 550 */ + { 0.001458e-6, 4292.330832950, 1.356098141 }, + { 0.001437e-6, 20.355319399, 3.895439360 }, + { 0.001738e-6, 6279.552731642, 0.087484036 }, + { 0.001367e-6, 14143.495242431, 3.987576591 }, + { 0.001344e-6, 7234.794256242, 0.090454338 }, + { 0.001438e-6, 11499.656222793, 0.974387904 }, + { 0.001257e-6, 6836.645252834, 1.509069366 }, + { 0.001358e-6, 11513.883316794, 0.495572260 }, + { 0.001628e-6, 7632.943259650, 4.968445721 }, + { 0.001169e-6, 103.092774219, 2.838496795 }, + /* 551, 560 */ + { 0.001162e-6, 4164.311989613, 3.408387778 }, + { 0.001092e-6, 6069.776754553, 3.617942651 }, + { 0.001008e-6, 17789.845619785, 0.286350174 }, + { 0.001008e-6, 639.897286314, 1.610762073 }, + { 0.000918e-6, 10213.285546211, 5.532798067 }, + { 0.001011e-6, -6256.777530192, 0.661826484 }, + { 0.000753e-6, 16730.463689596, 3.905030235 }, + { 0.000737e-6, 11926.254413669, 4.641956361 }, + { 0.000694e-6, 3340.612426700, 2.111120332 }, + { 0.000701e-6, 3894.181829542, 2.760823491 }, + /* 561, 570 */ + { 0.000689e-6, -135.065080035, 4.768800780 }, + { 0.000700e-6, 13367.972631107, 5.760439898 }, + { 0.000664e-6, 6040.347246017, 1.051215840 }, + { 0.000654e-6, 5650.292110678, 4.911332503 }, + { 0.000788e-6, 6681.224853400, 4.699648011 }, + { 0.000628e-6, 5333.900241022, 5.024608847 }, + { 0.000755e-6, -110.206321219, 4.370971253 }, + { 0.000628e-6, 6290.189396992, 3.660478857 }, + { 0.000635e-6, 25132.303399966, 4.121051532 }, + { 0.000534e-6, 5966.683980335, 1.173284524 }, + /* 571, 580 */ + { 0.000543e-6, -433.711737877, 0.345585464 }, + { 0.000517e-6, -1990.745017041, 5.414571768 }, + { 0.000504e-6, 5767.611978898, 2.328281115 }, + { 0.000485e-6, 5753.384884897, 1.685874771 }, + { 0.000463e-6, 7860.419392439, 5.297703006 }, + { 0.000604e-6, 515.463871093, 0.591998446 }, + { 0.000443e-6, 12168.002696575, 4.830881244 }, + { 0.000570e-6, 199.072001436, 3.899190272 }, + { 0.000465e-6, 10969.965257698, 0.476681802 }, + { 0.000424e-6, -7079.373856808, 1.112242763 }, + /* 581, 590 */ + { 0.000427e-6, 735.876513532, 1.994214480 }, + { 0.000478e-6, -6127.655450557, 3.778025483 }, + { 0.000414e-6, 10973.555686350, 5.441088327 }, + { 0.000512e-6, 1589.072895284, 0.107123853 }, + { 0.000378e-6, 10984.192351700, 0.915087231 }, + { 0.000402e-6, 11371.704689758, 4.107281715 }, + { 0.000453e-6, 9917.696874510, 1.917490952 }, + { 0.000395e-6, 149.563197135, 2.763124165 }, + { 0.000371e-6, 5739.157790895, 3.112111866 }, + { 0.000350e-6, 11790.629088659, 0.440639857 }, + /* 591, 600 */ + { 0.000356e-6, 6133.512652857, 5.444568842 }, + { 0.000344e-6, 412.371096874, 5.676832684 }, + { 0.000383e-6, 955.599741609, 5.559734846 }, + { 0.000333e-6, 6496.374945429, 0.261537984 }, + { 0.000340e-6, 6055.549660552, 5.975534987 }, + { 0.000334e-6, 1066.495477190, 2.335063907 }, + { 0.000399e-6, 11506.769769794, 5.321230910 }, + { 0.000314e-6, 18319.536584880, 2.313312404 }, + { 0.000424e-6, 1052.268383188, 1.211961766 }, + { 0.000307e-6, 63.735898303, 3.169551388 }, + /* 601, 610 */ + { 0.000329e-6, 29.821438149, 6.106912080 }, + { 0.000357e-6, 6309.374169791, 4.223760346 }, + { 0.000312e-6, -3738.761430108, 2.180556645 }, + { 0.000301e-6, 309.278322656, 1.499984572 }, + { 0.000268e-6, 12043.574281889, 2.447520648 }, + { 0.000257e-6, 12491.370101415, 3.662331761 }, + { 0.000290e-6, 625.670192312, 1.272834584 }, + { 0.000256e-6, 5429.879468239, 1.913426912 }, + { 0.000339e-6, 3496.032826134, 4.165930011 }, + { 0.000283e-6, 3930.209696220, 4.325565754 }, + /* 611, 620 */ + { 0.000241e-6, 12528.018664345, 3.832324536 }, + { 0.000304e-6, 4686.889407707, 1.612348468 }, + { 0.000259e-6, 16200.772724501, 3.470173146 }, + { 0.000238e-6, 12139.553509107, 1.147977842 }, + { 0.000236e-6, 6172.869528772, 3.776271728 }, + { 0.000296e-6, -7058.598461315, 0.460368852 }, + { 0.000306e-6, 10575.406682942, 0.554749016 }, + { 0.000251e-6, 17298.182327326, 0.834332510 }, + { 0.000290e-6, 4732.030627343, 4.759564091 }, + { 0.000261e-6, 5884.926846583, 0.298259862 }, + /* 621, 630 */ + { 0.000249e-6, 5547.199336460, 3.749366406 }, + { 0.000213e-6, 11712.955318231, 5.415666119 }, + { 0.000223e-6, 4701.116501708, 2.703203558 }, + { 0.000268e-6, -640.877607382, 0.283670793 }, + { 0.000209e-6, 5636.065016677, 1.238477199 }, + { 0.000193e-6, 10177.257679534, 1.943251340 }, + { 0.000182e-6, 6283.143160294, 2.456157599 }, + { 0.000184e-6, -227.526189440, 5.888038582 }, + { 0.000182e-6, -6283.008539689, 0.241332086 }, + { 0.000228e-6, -6284.056171060, 2.657323816 }, + /* 631, 640 */ + { 0.000166e-6, 7238.675591600, 5.930629110 }, + { 0.000167e-6, 3097.883822726, 5.570955333 }, + { 0.000159e-6, -323.505416657, 5.786670700 }, + { 0.000154e-6, -4136.910433516, 1.517805532 }, + { 0.000176e-6, 12029.347187887, 3.139266834 }, + { 0.000167e-6, 12132.439962106, 3.556352289 }, + { 0.000153e-6, 202.253395174, 1.463313961 }, + { 0.000157e-6, 17267.268201691, 1.586837396 }, + { 0.000142e-6, 83996.847317911, 0.022670115 }, + { 0.000152e-6, 17260.154654690, 0.708528947 }, + /* 641, 650 */ + { 0.000144e-6, 6084.003848555, 5.187075177 }, + { 0.000135e-6, 5756.566278634, 1.993229262 }, + { 0.000134e-6, 5750.203491159, 3.457197134 }, + { 0.000144e-6, 5326.786694021, 6.066193291 }, + { 0.000160e-6, 11015.106477335, 1.710431974 }, + { 0.000133e-6, 3634.621024518, 2.836451652 }, + { 0.000134e-6, 18073.704938650, 5.453106665 }, + { 0.000134e-6, 1162.474704408, 5.326898811 }, + { 0.000128e-6, 5642.198242609, 2.511652591 }, + { 0.000160e-6, 632.783739313, 5.628785365 }, + /* 651, 660 */ + { 0.000132e-6, 13916.019109642, 0.819294053 }, + { 0.000122e-6, 14314.168113050, 5.677408071 }, + { 0.000125e-6, 12359.966151546, 5.251984735 }, + { 0.000121e-6, 5749.452731634, 2.210924603 }, + { 0.000136e-6, -245.831646229, 1.646502367 }, + { 0.000120e-6, 5757.317038160, 3.240883049 }, + { 0.000134e-6, 12146.667056108, 3.059480037 }, + { 0.000137e-6, 6206.809778716, 1.867105418 }, + { 0.000141e-6, 17253.041107690, 2.069217456 }, + { 0.000129e-6, -7477.522860216, 2.781469314 }, + /* 661, 670 */ + { 0.000116e-6, 5540.085789459, 4.281176991 }, + { 0.000116e-6, 9779.108676125, 3.320925381 }, + { 0.000129e-6, 5237.921013804, 3.497704076 }, + { 0.000113e-6, 5959.570433334, 0.983210840 }, + { 0.000122e-6, 6282.095528923, 2.674938860 }, + { 0.000140e-6, -11.045700264, 4.957936982 }, + { 0.000108e-6, 23543.230504682, 1.390113589 }, + { 0.000106e-6, -12569.674818332, 0.429631317 }, + { 0.000110e-6, -266.607041722, 5.501340197 }, + { 0.000115e-6, 12559.038152982, 4.691456618 }, + /* 671, 680 */ + { 0.000134e-6, -2388.894020449, 0.577313584 }, + { 0.000109e-6, 10440.274292604, 6.218148717 }, + { 0.000102e-6, -543.918059096, 1.477842615 }, + { 0.000108e-6, 21228.392023546, 2.237753948 }, + { 0.000101e-6, -4535.059436924, 3.100492232 }, + { 0.000103e-6, 76.266071276, 5.594294322 }, + { 0.000104e-6, 949.175608970, 5.674287810 }, + { 0.000101e-6, 13517.870106233, 2.196632348 }, + { 0.000100e-6, 11933.367960670, 4.056084160 }, + + /* T^2 */ + { 4.322990e-6, 6283.075849991, 2.642893748 }, + /* 681, 690 */ + { 0.406495e-6, 0.000000000, 4.712388980 }, + { 0.122605e-6, 12566.151699983, 2.438140634 }, + { 0.019476e-6, 213.299095438, 1.642186981 }, + { 0.016916e-6, 529.690965095, 4.510959344 }, + { 0.013374e-6, -3.523118349, 1.502210314 }, + { 0.008042e-6, 26.298319800, 0.478549024 }, + { 0.007824e-6, 155.420399434, 5.254710405 }, + { 0.004894e-6, 5746.271337896, 4.683210850 }, + { 0.004875e-6, 5760.498431898, 0.759507698 }, + { 0.004416e-6, 5223.693919802, 6.028853166 }, + /* 691, 700 */ + { 0.004088e-6, -7.113547001, 0.060926389 }, + { 0.004433e-6, 77713.771467920, 3.627734103 }, + { 0.003277e-6, 18849.227549974, 2.327912542 }, + { 0.002703e-6, 6062.663207553, 1.271941729 }, + { 0.003435e-6, -775.522611324, 0.747446224 }, + { 0.002618e-6, 6076.890301554, 3.633715689 }, + { 0.003146e-6, 206.185548437, 5.647874613 }, + { 0.002544e-6, 1577.343542448, 6.232904270 }, + { 0.002218e-6, -220.412642439, 1.309509946 }, + { 0.002197e-6, 5856.477659115, 2.407212349 }, + /* 701, 710 */ + { 0.002897e-6, 5753.384884897, 5.863842246 }, + { 0.001766e-6, 426.598190876, 0.754113147 }, + { 0.001738e-6, -796.298006816, 2.714942671 }, + { 0.001695e-6, 522.577418094, 2.629369842 }, + { 0.001584e-6, 5507.553238667, 1.341138229 }, + { 0.001503e-6, -242.728603974, 0.377699736 }, + { 0.001552e-6, -536.804512095, 2.904684667 }, + { 0.001370e-6, -398.149003408, 1.265599125 }, + { 0.001889e-6, -5573.142801634, 4.413514859 }, + { 0.001722e-6, 6069.776754553, 2.445966339 }, + /* 711, 720 */ + { 0.001124e-6, 1059.381930189, 5.041799657 }, + { 0.001258e-6, 553.569402842, 3.849557278 }, + { 0.000831e-6, 951.718406251, 2.471094709 }, + { 0.000767e-6, 4694.002954708, 5.363125422 }, + { 0.000756e-6, 1349.867409659, 1.046195744 }, + { 0.000775e-6, -11.045700264, 0.245548001 }, + { 0.000597e-6, 2146.165416475, 4.543268798 }, + { 0.000568e-6, 5216.580372801, 4.178853144 }, + { 0.000711e-6, 1748.016413067, 5.934271972 }, + { 0.000499e-6, 12036.460734888, 0.624434410 }, + /* 721, 730 */ + { 0.000671e-6, -1194.447010225, 4.136047594 }, + { 0.000488e-6, 5849.364112115, 2.209679987 }, + { 0.000621e-6, 6438.496249426, 4.518860804 }, + { 0.000495e-6, -6286.598968340, 1.868201275 }, + { 0.000456e-6, 5230.807466803, 1.271231591 }, + { 0.000451e-6, 5088.628839767, 0.084060889 }, + { 0.000435e-6, 5643.178563677, 3.324456609 }, + { 0.000387e-6, 10977.078804699, 4.052488477 }, + { 0.000547e-6, 161000.685737473, 2.841633844 }, + { 0.000522e-6, 3154.687084896, 2.171979966 }, + /* 731, 740 */ + { 0.000375e-6, 5486.777843175, 4.983027306 }, + { 0.000421e-6, 5863.591206116, 4.546432249 }, + { 0.000439e-6, 7084.896781115, 0.522967921 }, + { 0.000309e-6, 2544.314419883, 3.172606705 }, + { 0.000347e-6, 4690.479836359, 1.479586566 }, + { 0.000317e-6, 801.820931124, 3.553088096 }, + { 0.000262e-6, 419.484643875, 0.606635550 }, + { 0.000248e-6, 6836.645252834, 3.014082064 }, + { 0.000245e-6, -1592.596013633, 5.519526220 }, + { 0.000225e-6, 4292.330832950, 2.877956536 }, + /* 741, 750 */ + { 0.000214e-6, 7234.794256242, 1.605227587 }, + { 0.000205e-6, 5767.611978898, 0.625804796 }, + { 0.000180e-6, 10447.387839604, 3.499954526 }, + { 0.000229e-6, 199.072001436, 5.632304604 }, + { 0.000214e-6, 639.897286314, 5.960227667 }, + { 0.000175e-6, -433.711737877, 2.162417992 }, + { 0.000209e-6, 515.463871093, 2.322150893 }, + { 0.000173e-6, 6040.347246017, 2.556183691 }, + { 0.000184e-6, 6309.374169791, 4.732296790 }, + { 0.000227e-6, 149854.400134205, 5.385812217 }, + /* 751, 760 */ + { 0.000154e-6, 8031.092263058, 5.120720920 }, + { 0.000151e-6, 5739.157790895, 4.815000443 }, + { 0.000197e-6, 7632.943259650, 0.222827271 }, + { 0.000197e-6, 74.781598567, 3.910456770 }, + { 0.000138e-6, 6055.549660552, 1.397484253 }, + { 0.000149e-6, -6127.655450557, 5.333727496 }, + { 0.000137e-6, 3894.181829542, 4.281749907 }, + { 0.000135e-6, 9437.762934887, 5.979971885 }, + { 0.000139e-6, -2352.866153772, 4.715630782 }, + { 0.000142e-6, 6812.766815086, 0.513330157 }, + /* 761, 770 */ + { 0.000120e-6, -4705.732307544, 0.194160689 }, + { 0.000131e-6, -71430.695617928, 0.000379226 }, + { 0.000124e-6, 6279.552731642, 2.122264908 }, + { 0.000108e-6, -6256.777530192, 0.883445696 }, + + /* T^3 */ + { 0.143388e-6, 6283.075849991, 1.131453581 }, + { 0.006671e-6, 12566.151699983, 0.775148887 }, + { 0.001480e-6, 155.420399434, 0.480016880 }, + { 0.000934e-6, 213.299095438, 6.144453084 }, + { 0.000795e-6, 529.690965095, 2.941595619 }, + { 0.000673e-6, 5746.271337896, 0.120415406 }, + /* 771, 780 */ + { 0.000672e-6, 5760.498431898, 5.317009738 }, + { 0.000389e-6, -220.412642439, 3.090323467 }, + { 0.000373e-6, 6062.663207553, 3.003551964 }, + { 0.000360e-6, 6076.890301554, 1.918913041 }, + { 0.000316e-6, -21.340641002, 5.545798121 }, + { 0.000315e-6, -242.728603974, 1.884932563 }, + { 0.000278e-6, 206.185548437, 1.266254859 }, + { 0.000238e-6, -536.804512095, 4.532664830 }, + { 0.000185e-6, 522.577418094, 4.578313856 }, + { 0.000245e-6, 18849.227549974, 0.587467082 }, + /* 781, 787 */ + { 0.000180e-6, 426.598190876, 5.151178553 }, + { 0.000200e-6, 553.569402842, 5.355983739 }, + { 0.000141e-6, 5223.693919802, 1.336556009 }, + { 0.000104e-6, 5856.477659115, 4.239842759 }, + + /* T^4 */ + { 0.003826e-6, 6283.075849991, 5.705257275 }, + { 0.000303e-6, 12566.151699983, 5.407132842 }, + { 0.000209e-6, 155.420399434, 1.989815753 } + }; + + +/* Time since J2000.0 in Julian millennia. */ + t = ((date1 - DJ00) + date2) / DJM; + +/* ================= */ +/* Topocentric terms */ +/* ================= */ + +/* Convert UT to local solar time in radians. */ + tsol = fmod(ut, 1.0) * D2PI + elong; + +/* FUNDAMENTAL ARGUMENTS: Simon et al. 1994. */ + +/* Combine time argument (millennia) with deg/arcsec factor. */ + w = t / 3600.0; + +/* Sun Mean Longitude. */ + elsun = fmod(280.46645683 + 1296027711.03429 * w, 360.0) * DD2R; + +/* Sun Mean Anomaly. */ + emsun = fmod(357.52910918 + 1295965810.481 * w, 360.0) * DD2R; + +/* Mean Elongation of Moon from Sun. */ + d = fmod(297.85019547 + 16029616012.090 * w, 360.0) * DD2R; + +/* Mean Longitude of Jupiter. */ + elj = fmod(34.35151874 + 109306899.89453 * w, 360.0) * DD2R; + +/* Mean Longitude of Saturn. */ + els = fmod(50.07744430 + 44046398.47038 * w, 360.0) * DD2R; + +/* TOPOCENTRIC TERMS: Moyer 1981 and Murray 1983. */ + wt = + 0.00029e-10 * u * sin(tsol + elsun - els) + + 0.00100e-10 * u * sin(tsol - 2.0 * emsun) + + 0.00133e-10 * u * sin(tsol - d) + + 0.00133e-10 * u * sin(tsol + elsun - elj) + - 0.00229e-10 * u * sin(tsol + 2.0 * elsun + emsun) + - 0.02200e-10 * v * cos(elsun + emsun) + + 0.05312e-10 * u * sin(tsol - emsun) + - 0.13677e-10 * u * sin(tsol + 2.0 * elsun) + - 1.31840e-10 * v * cos(elsun) + + 3.17679e-10 * u * sin(tsol); + +/* ===================== */ +/* Fairhead et al. model */ +/* ===================== */ + +/* T**0 */ + w0 = 0; + for (j = 473; j >= 0; j--) { + w0 += fairhd[j][0] * sin(fairhd[j][1] * t + fairhd[j][2]); + } + +/* T**1 */ + w1 = 0; + for (j = 678; j >= 474; j--) { + w1 += fairhd[j][0] * sin(fairhd[j][1] * t + fairhd[j][2]); + } + +/* T**2 */ + w2 = 0; + for (j = 763; j >= 679; j--) { + w2 += fairhd[j][0] * sin(fairhd[j][1] * t + fairhd[j][2]); + } + +/* T**3 */ + w3 = 0; + for (j = 783; j >= 764; j--) { + w3 += fairhd[j][0] * sin(fairhd[j][1] * t + fairhd[j][2]); + } + +/* T**4 */ + w4 = 0; + for (j = 786; j >= 784; j--) { + w4 += fairhd[j][0] * sin(fairhd[j][1] * t + fairhd[j][2]); + } + +/* Multiply by powers of T and combine. */ + wf = t * (t * (t * (t * w4 + w3) + w2) + w1) + w0; + +/* Adjustments to use JPL planetary masses instead of IAU. */ + wj = 0.00065e-6 * sin(6069.776754 * t + 4.021194) + + 0.00033e-6 * sin( 213.299095 * t + 5.543132) + + (-0.00196e-6 * sin(6208.294251 * t + 5.696701)) + + (-0.00173e-6 * sin( 74.781599 * t + 2.435900)) + + 0.03638e-6 * t * t; + +/* ============ */ +/* Final result */ +/* ============ */ + +/* TDB-TT in seconds. */ + w = wt + wf + wj; + + return w; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/dtf2d.c b/src/cpp/3rdparty/sofa/src/dtf2d.c new file mode 100644 index 000000000..54ba7954b --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/dtf2d.c @@ -0,0 +1,256 @@ +#include "sofa.h" +#include "sofam.h" +#include + +int iauDtf2d(const char *scale, int iy, int im, int id, + int ihr, int imn, double sec, double *d1, double *d2) +/* +** - - - - - - - - - +** i a u D t f 2 d +** - - - - - - - - - +** +** Encode date and time fields into 2-part Julian Date (or in the case +** of UTC a quasi-JD form that includes special provision for leap +** seconds). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** scale char[] time scale ID (Note 1) +** iy,im,id int year, month, day in Gregorian calendar (Note 2) +** ihr,imn int hour, minute +** sec double seconds +** +** Returned: +** d1,d2 double 2-part Julian Date (Notes 3,4) +** +** Returned (function value): +** int status: +3 = both of next two +** +2 = time is after end of day (Note 5) +** +1 = dubious year (Note 6) +** 0 = OK +** -1 = bad year +** -2 = bad month +** -3 = bad day +** -4 = bad hour +** -5 = bad minute +** -6 = bad second (<0) +** +** Notes: +** +** 1) scale identifies the time scale. Only the value "UTC" (in upper +** case) is significant, and enables handling of leap seconds (see +** Note 4). +** +** 2) For calendar conventions and limitations, see iauCal2jd. +** +** 3) The sum of the results, d1+d2, is Julian Date, where normally d1 +** is the Julian Day Number and d2 is the fraction of a day. In the +** case of UTC, where the use of JD is problematical, special +** conventions apply: see the next note. +** +** 4) JD cannot unambiguously represent UTC during a leap second unless +** special measures are taken. The SOFA internal convention is that +** the quasi-JD day represents UTC days whether the length is 86399, +** 86400 or 86401 SI seconds. In the 1960-1972 era there were +** smaller jumps (in either direction) each time the linear UTC(TAI) +** expression was changed, and these "mini-leaps" are also included +** in the SOFA convention. +** +** 5) The warning status "time is after end of day" usually means that +** the sec argument is greater than 60.0. However, in a day ending +** in a leap second the limit changes to 61.0 (or 59.0 in the case +** of a negative leap second). +** +** 6) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the future +** to be trusted. See iauDat for further details. +** +** 7) Only in the case of continuous and regular time scales (TAI, TT, +** TCG, TCB and TDB) is the result d1+d2 a Julian Date, strictly +** speaking. In the other cases (UT1 and UTC) the result must be +** used with circumspection; in particular the difference between +** two such results cannot be interpreted as a precise time +** interval. +** +** Called: +** iauCal2jd Gregorian calendar to JD +** iauDat delta(AT) = TAI-UTC +** iauJd2cal JD to Gregorian calendar +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int js, iy2, im2, id2; + double dj, w, day, seclim, dat0, dat12, dat24, dleap, time; + + +/* Today's Julian Day Number. */ + js = iauCal2jd(iy, im, id, &dj, &w); + if ( js ) return js; + dj += w; + +/* Day length and final minute length in seconds (provisional). */ + day = DAYSEC; + seclim = 60.0; + +/* Deal with the UTC leap second case. */ + if ( ! strcmp(scale,"UTC") ) { + + /* TAI-UTC at 0h today. */ + js = iauDat(iy, im, id, 0.0, &dat0); + if ( js < 0 ) return js; + + /* TAI-UTC at 12h today (to detect drift). */ + js = iauDat(iy, im, id, 0.5, &dat12); + if ( js < 0 ) return js; + + /* TAI-UTC at 0h tomorrow (to detect jumps). */ + js = iauJd2cal ( dj, 1.5, &iy2, &im2, &id2, &w); + if ( js ) return js; + js = iauDat(iy2, im2, id2, 0.0, &dat24); + if ( js < 0 ) return js; + + /* Any sudden change in TAI-UTC between today and tomorrow. */ + dleap = dat24 - (2.0*dat12 - dat0); + + /* If leap second day, correct the day and final minute lengths. */ + day += dleap; + if ( ihr == 23 && imn == 59 ) seclim += dleap; + + /* End of UTC-specific actions. */ + } + +/* Validate the time. */ + if ( ihr >= 0 && ihr <= 23 ) { + if ( imn >= 0 && imn <= 59 ) { + if ( sec >= 0 ) { + if ( sec >= seclim ) { + js += 2; + } + } else { + js = -6; + } + } else { + js = -5; + } + } else { + js = -4; + } + if ( js < 0 ) return js; + +/* The time in days. */ + time = ( 60.0 * ( (double) ( 60 * ihr + imn ) ) + sec ) / day; + +/* Return the date and time. */ + *d1 = dj; + *d2 = time; + +/* Status. */ + return js; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/eceq06.c b/src/cpp/3rdparty/sofa/src/eceq06.c new file mode 100644 index 000000000..e8d2ecd77 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/eceq06.c @@ -0,0 +1,184 @@ +#include "sofa.h" + +void iauEceq06(double date1, double date2, double dl, double db, + double *dr, double *dd) +/* +** - - - - - - - - - - +** i a u E c e q 0 6 +** - - - - - - - - - - +** +** Transformation from ecliptic coordinates (mean equinox and ecliptic +** of date) to ICRS RA,Dec, using the IAU 2006 precession model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian date (Note 1) +** dl,db double ecliptic longitude and latitude (radians) +** +** Returned: +** dr,dd double ICRS right ascension and declination (radians) +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) No assumptions are made about whether the coordinates represent +** starlight and embody astrometric effects such as parallax or +** aberration. +** +** 3) The transformation is approximately that from ecliptic longitude +** and latitude (mean equinox and ecliptic of date) to mean J2000.0 +** right ascension and declination, with only frame bias (always +** less than 25 mas) to disturb this classical picture. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauEcm06 J2000.0 to ecliptic rotation matrix, IAU 2006 +** iauTrxp product of transpose of r-matrix and p-vector +** iauC2s unit vector to spherical coordinates +** iauAnp normalize angle into range 0 to 2pi +** iauAnpm normalize angle into range +/- pi +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rm[3][3], v1[3], v2[3], a, b; + + +/* Spherical to Cartesian. */ + iauS2c(dl, db, v1); + +/* Rotation matrix, ICRS equatorial to ecliptic. */ + iauEcm06(date1, date2, rm); + +/* The transformation from ecliptic to ICRS. */ + iauTrxp(rm, v1, v2); + +/* Cartesian to spherical. */ + iauC2s(v2, &a, &b); + +/* Express in conventional ranges. */ + *dr = iauAnp(a); + *dd = iauAnpm(b); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ecm06.c b/src/cpp/3rdparty/sofa/src/ecm06.c new file mode 100644 index 000000000..18dc7e35b --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ecm06.c @@ -0,0 +1,187 @@ +#include "sofa.h" + +void iauEcm06(double date1, double date2, double rm[3][3]) +/* +** - - - - - - - - - +** i a u E c m 0 6 +** - - - - - - - - - +** +** ICRS equatorial to ecliptic rotation matrix, IAU 2006. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian date (Note 1) +** +** Returned: +** rm double[3][3] ICRS to ecliptic rotation matrix +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 1) The matrix is in the sense +** +** E_ep = rm x P_ICRS, +** +** where P_ICRS is a vector with respect to ICRS right ascension +** and declination axes and E_ep is the same vector with respect to +** the (inertial) ecliptic and equinox of date. +** +** 2) P_ICRS is a free vector, merely a direction, typically of unit +** magnitude, and not bound to any particular spatial origin, such +** as the Earth, Sun or SSB. No assumptions are made about whether +** it represents starlight and embodies astrometric effects such as +** parallax or aberration. The transformation is approximately that +** between mean J2000.0 right ascension and declination and ecliptic +** longitude and latitude, with only frame bias (always less than +** 25 mas) to disturb this classical picture. +** +** Called: +** iauObl06 mean obliquity, IAU 2006 +** iauPmat06 PB matrix, IAU 2006 +** iauIr initialize r-matrix to identity +** iauRx rotate around X-axis +** iauRxr product of two r-matrices +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double ob, bp[3][3], e[3][3]; + + +/* Obliquity, IAU 2006. */ + ob = iauObl06(date1, date2); + +/* Precession-bias matrix, IAU 2006. */ + iauPmat06(date1, date2, bp); + +/* Equatorial of date to ecliptic matrix. */ + iauIr(e); + iauRx(ob, e); + +/* ICRS to ecliptic coordinates rotation matrix, IAU 2006. */ + iauRxr(e, bp, rm); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ee00.c b/src/cpp/3rdparty/sofa/src/ee00.c new file mode 100644 index 000000000..2d2bcdcd9 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ee00.c @@ -0,0 +1,180 @@ +#include "sofa.h" + +double iauEe00(double date1, double date2, double epsa, double dpsi) +/* +** - - - - - - - - +** i a u E e 0 0 +** - - - - - - - - +** +** The equation of the equinoxes, compatible with IAU 2000 resolutions, +** given the nutation in longitude and the mean obliquity. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** epsa double mean obliquity (Note 2) +** dpsi double nutation in longitude (Note 3) +** +** Returned (function value): +** double equation of the equinoxes (Note 4) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The obliquity, in radians, is mean of date. +** +** 3) The result, which is in radians, operates in the following sense: +** +** Greenwich apparent ST = GMST + equation of the equinoxes +** +** 4) The result is compatible with the IAU 2000 resolutions. For +** further details, see IERS Conventions 2003 and Capitaine et al. +** (2002). +** +** Called: +** iauEect00 equation of the equinoxes complementary terms +** +** References: +** +** Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to +** implement the IAU 2000 definition of UT1", Astronomy & +** Astrophysics, 406, 1135-1149 (2003) +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double ee; + + +/* Equation of the equinoxes. */ + ee = dpsi * cos(epsa) + iauEect00(date1, date2); + + return ee; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ee00a.c b/src/cpp/3rdparty/sofa/src/ee00a.c new file mode 100644 index 000000000..a810c9792 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ee00a.c @@ -0,0 +1,187 @@ +#include "sofa.h" + +double iauEe00a(double date1, double date2) +/* +** - - - - - - - - - +** i a u E e 0 0 a +** - - - - - - - - - +** +** Equation of the equinoxes, compatible with IAU 2000 resolutions. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double equation of the equinoxes (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The result, which is in radians, operates in the following sense: +** +** Greenwich apparent ST = GMST + equation of the equinoxes +** +** 3) The result is compatible with the IAU 2000 resolutions. For +** further details, see IERS Conventions 2003 and Capitaine et al. +** (2002). +** +** Called: +** iauPr00 IAU 2000 precession adjustments +** iauObl80 mean obliquity, IAU 1980 +** iauNut00a nutation, IAU 2000A +** iauEe00 equation of the equinoxes, IAU 2000 +** +** References: +** +** Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to +** implement the IAU 2000 definition of UT1", Astronomy & +** Astrophysics, 406, 1135-1149 (2003). +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsipr, depspr, epsa, dpsi, deps, ee; + + +/* IAU 2000 precession-rate adjustments. */ + iauPr00(date1, date2, &dpsipr, &depspr); + +/* Mean obliquity, consistent with IAU 2000 precession-nutation. */ + epsa = iauObl80(date1, date2) + depspr; + +/* Nutation in longitude. */ + iauNut00a(date1, date2, &dpsi, &deps); + +/* Equation of the equinoxes. */ + ee = iauEe00(date1, date2, epsa, dpsi); + + return ee; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ee00b.c b/src/cpp/3rdparty/sofa/src/ee00b.c new file mode 100644 index 000000000..5d9c59292 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ee00b.c @@ -0,0 +1,193 @@ +#include "sofa.h" + +double iauEe00b(double date1, double date2) +/* +** - - - - - - - - - +** i a u E e 0 0 b +** - - - - - - - - - +** +** Equation of the equinoxes, compatible with IAU 2000 resolutions but +** using the truncated nutation model IAU 2000B. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double equation of the equinoxes (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The result, which is in radians, operates in the following sense: +** +** Greenwich apparent ST = GMST + equation of the equinoxes +** +** 3) The result is compatible with the IAU 2000 resolutions except +** that accuracy has been compromised (1 mas) for the sake of speed. +** For further details, see McCarthy & Luzum (2003), IERS +** Conventions 2003 and Capitaine et al. (2003). +** +** Called: +** iauPr00 IAU 2000 precession adjustments +** iauObl80 mean obliquity, IAU 1980 +** iauNut00b nutation, IAU 2000B +** iauEe00 equation of the equinoxes, IAU 2000 +** +** References: +** +** Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to +** implement the IAU 2000 definition of UT1", Astronomy & +** Astrophysics, 406, 1135-1149 (2003) +** +** McCarthy, D.D. & Luzum, B.J., "An abridged model of the +** precession-nutation of the celestial pole", Celestial Mechanics & +** Dynamical Astronomy, 85, 37-49 (2003) +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsipr, depspr, epsa, dpsi, deps, ee; + + +/* IAU 2000 precession-rate adjustments. */ + iauPr00(date1, date2, &dpsipr, &depspr); + +/* Mean obliquity, consistent with IAU 2000 precession-nutation. */ + epsa = iauObl80(date1, date2) + depspr; + +/* Nutation in longitude. */ + iauNut00b(date1, date2, &dpsi, &deps); + +/* Equation of the equinoxes. */ + ee = iauEe00(date1, date2, epsa, dpsi); + + return ee; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ee06a.c b/src/cpp/3rdparty/sofa/src/ee06a.c new file mode 100644 index 000000000..986010fc3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ee06a.c @@ -0,0 +1,174 @@ +#include "sofa.h" + +double iauEe06a(double date1, double date2) +/* +** - - - - - - - - - +** i a u E e 0 6 a +** - - - - - - - - - +** +** Equation of the equinoxes, compatible with IAU 2000 resolutions and +** IAU 2006/2000A precession-nutation. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double equation of the equinoxes (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The result, which is in radians, operates in the following sense: +** +** Greenwich apparent ST = GMST + equation of the equinoxes +** +** Called: +** iauAnpm normalize angle into range +/- pi +** iauGst06a Greenwich apparent sidereal time, IAU 2006/2000A +** iauGmst06 Greenwich mean sidereal time, IAU 2006 +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), 2004, IERS Conventions (2003), +** IERS Technical Note No. 32, BKG +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gst06a, gmst06, ee; + + +/* Apparent and mean sidereal times. */ + gst06a = iauGst06a(0.0, 0.0, date1, date2); + gmst06 = iauGmst06(0.0, 0.0, date1, date2); + +/* Equation of the equinoxes. */ + ee = iauAnpm(gst06a - gmst06); + + return ee; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/eect00.c b/src/cpp/3rdparty/sofa/src/eect00.c new file mode 100644 index 000000000..572c332ef --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/eect00.c @@ -0,0 +1,335 @@ +#include "sofa.h" +#include "sofam.h" + +double iauEect00(double date1, double date2) +/* +** - - - - - - - - - - +** i a u E e c t 0 0 +** - - - - - - - - - - +** +** Equation of the equinoxes complementary terms, consistent with +** IAU 2000 resolutions. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double complementary terms (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The "complementary terms" are part of the equation of the +** equinoxes (EE), classically the difference between apparent and +** mean Sidereal Time: +** +** GAST = GMST + EE +** +** with: +** +** EE = dpsi * cos(eps) +** +** where dpsi is the nutation in longitude and eps is the obliquity +** of date. However, if the rotation of the Earth were constant in +** an inertial frame the classical formulation would lead to +** apparent irregularities in the UT1 timescale traceable to side- +** effects of precession-nutation. In order to eliminate these +** effects from UT1, "complementary terms" were introduced in 1994 +** (IAU, 1994) and took effect from 1997 (Capitaine and Gontier, +** 1993): +** +** GAST = GMST + CT + EE +** +** By convention, the complementary terms are included as part of +** the equation of the equinoxes rather than as part of the mean +** Sidereal Time. This slightly compromises the "geometrical" +** interpretation of mean sidereal time but is otherwise +** inconsequential. +** +** The present function computes CT in the above expression, +** compatible with IAU 2000 resolutions (Capitaine et al., 2002, and +** IERS Conventions 2003). +** +** Called: +** iauFal03 mean anomaly of the Moon +** iauFalp03 mean anomaly of the Sun +** iauFaf03 mean argument of the latitude of the Moon +** iauFad03 mean elongation of the Moon from the Sun +** iauFaom03 mean longitude of the Moon's ascending node +** iauFave03 mean longitude of Venus +** iauFae03 mean longitude of Earth +** iauFapa03 general accumulated precession in longitude +** +** References: +** +** Capitaine, N. & Gontier, A.-M., Astron.Astrophys., 275, +** 645-650 (1993) +** +** Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to +** implement the IAU 2000 definition of UT1", Astron.Astrophys., 406, +** 1135-1149 (2003) +** +** IAU Resolution C7, Recommendation 3 (1994) +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Time since J2000.0, in Julian centuries */ + double t; + +/* Miscellaneous */ + int i, j; + double a, s0, s1; + +/* Fundamental arguments */ + double fa[14]; + +/* Returned value. */ + double eect; + +/* ----------------------------------------- */ +/* The series for the EE complementary terms */ +/* ----------------------------------------- */ + + typedef struct { + int nfa[8]; /* coefficients of l,l',F,D,Om,LVe,LE,pA */ + double s, c; /* sine and cosine coefficients */ + } TERM; + +/* Terms of order t^0 */ + static const TERM e0[] = { + + /* 1-10 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, 2640.96e-6, -0.39e-6 }, + {{ 0, 0, 0, 0, 2, 0, 0, 0}, 63.52e-6, -0.02e-6 }, + {{ 0, 0, 2, -2, 3, 0, 0, 0}, 11.75e-6, 0.01e-6 }, + {{ 0, 0, 2, -2, 1, 0, 0, 0}, 11.21e-6, 0.01e-6 }, + {{ 0, 0, 2, -2, 2, 0, 0, 0}, -4.55e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 3, 0, 0, 0}, 2.02e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 1, 0, 0, 0}, 1.98e-6, 0.00e-6 }, + {{ 0, 0, 0, 0, 3, 0, 0, 0}, -1.72e-6, 0.00e-6 }, + {{ 0, 1, 0, 0, 1, 0, 0, 0}, -1.41e-6, -0.01e-6 }, + {{ 0, 1, 0, 0, -1, 0, 0, 0}, -1.26e-6, -0.01e-6 }, + + /* 11-20 */ + {{ 1, 0, 0, 0, -1, 0, 0, 0}, -0.63e-6, 0.00e-6 }, + {{ 1, 0, 0, 0, 1, 0, 0, 0}, -0.63e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 3, 0, 0, 0}, 0.46e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 1, 0, 0, 0}, 0.45e-6, 0.00e-6 }, + {{ 0, 0, 4, -4, 4, 0, 0, 0}, 0.36e-6, 0.00e-6 }, + {{ 0, 0, 1, -1, 1, -8, 12, 0}, -0.24e-6, -0.12e-6 }, + {{ 0, 0, 2, 0, 0, 0, 0, 0}, 0.32e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 2, 0, 0, 0}, 0.28e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 3, 0, 0, 0}, 0.27e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 1, 0, 0, 0}, 0.26e-6, 0.00e-6 }, + + /* 21-30 */ + {{ 0, 0, 2, -2, 0, 0, 0, 0}, -0.21e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -3, 0, 0, 0}, 0.19e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -1, 0, 0, 0}, 0.18e-6, 0.00e-6 }, + {{ 0, 0, 0, 0, 0, 8,-13, -1}, -0.10e-6, 0.05e-6 }, + {{ 0, 0, 0, 2, 0, 0, 0, 0}, 0.15e-6, 0.00e-6 }, + {{ 2, 0, -2, 0, -1, 0, 0, 0}, -0.14e-6, 0.00e-6 }, + {{ 1, 0, 0, -2, 1, 0, 0, 0}, 0.14e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 2, 0, 0, 0}, -0.14e-6, 0.00e-6 }, + {{ 1, 0, 0, -2, -1, 0, 0, 0}, 0.14e-6, 0.00e-6 }, + {{ 0, 0, 4, -2, 4, 0, 0, 0}, 0.13e-6, 0.00e-6 }, + + /* 31-33 */ + {{ 0, 0, 2, -2, 4, 0, 0, 0}, -0.11e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -3, 0, 0, 0}, 0.11e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -1, 0, 0, 0}, 0.11e-6, 0.00e-6 } + }; + +/* Terms of order t^1 */ + static const TERM e1[] = { + {{ 0, 0, 0, 0, 1, 0, 0, 0}, -0.87e-6, 0.00e-6 } + }; + +/* Number of terms in the series */ + const int NE0 = (int) (sizeof e0 / sizeof (TERM)); + const int NE1 = (int) (sizeof e1 / sizeof (TERM)); + +/* ------------------------------------------------------------------ */ + +/* Interval between fundamental epoch J2000.0 and current date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Fundamental Arguments (from IERS Conventions 2003) */ + +/* Mean anomaly of the Moon. */ + fa[0] = iauFal03(t); + +/* Mean anomaly of the Sun. */ + fa[1] = iauFalp03(t); + +/* Mean longitude of the Moon minus that of the ascending node. */ + fa[2] = iauFaf03(t); + +/* Mean elongation of the Moon from the Sun. */ + fa[3] = iauFad03(t); + +/* Mean longitude of the ascending node of the Moon. */ + fa[4] = iauFaom03(t); + +/* Mean longitude of Venus. */ + fa[5] = iauFave03(t); + +/* Mean longitude of Earth. */ + fa[6] = iauFae03(t); + +/* General precession in longitude. */ + fa[7] = iauFapa03(t); + +/* Evaluate the EE complementary terms. */ + s0 = 0.0; + s1 = 0.0; + + for (i = NE0-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)(e0[i].nfa[j]) * fa[j]; + } + s0 += e0[i].s * sin(a) + e0[i].c * cos(a); + } + + for (i = NE1-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)(e1[i].nfa[j]) * fa[j]; + } + s1 += e1[i].s * sin(a) + e1[i].c * cos(a); + } + + eect = (s0 + s1 * t ) * DAS2R; + + return eect; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/eform.c b/src/cpp/3rdparty/sofa/src/eform.c new file mode 100644 index 000000000..11c9e2e71 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/eform.c @@ -0,0 +1,199 @@ +#include "sofa.h" +#include "sofam.h" + +int iauEform ( int n, double *a, double *f ) +/* +** - - - - - - - - - +** i a u E f o r m +** - - - - - - - - - +** +** Earth reference ellipsoids. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** n int ellipsoid identifier (Note 1) +** +** Returned: +** a double equatorial radius (meters, Note 2) +** f double flattening (Note 2) +** +** Returned (function value): +** int status: 0 = OK +** -1 = illegal identifier (Note 3) +** +** Notes: +** +** 1) The identifier n is a number that specifies the choice of +** reference ellipsoid. The following are supported: +** +** n ellipsoid +** +** 1 WGS84 +** 2 GRS80 +** 3 WGS72 +** +** The n value has no significance outside the SOFA software. For +** convenience, symbols WGS84 etc. are defined in sofam.h. +** +** 2) The ellipsoid parameters are returned in the form of equatorial +** radius in meters (a) and flattening (f). The latter is a number +** around 0.00335, i.e. around 1/298. +** +** 3) For the case where an unsupported n value is supplied, zero a and +** f are returned, as well as error status. +** +** References: +** +** Department of Defense World Geodetic System 1984, National +** Imagery and Mapping Agency Technical Report 8350.2, Third +** Edition, p3-2. +** +** Moritz, H., Bull. Geodesique 66-2, 187 (1992). +** +** The Department of Defense World Geodetic System 1972, World +** Geodetic System Committee, May 1974. +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** p220. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Look up a and f for the specified reference ellipsoid. */ + switch ( n ) { + + case WGS84: + *a = 6378137.0; + *f = 1.0 / 298.257223563; + break; + + case GRS80: + *a = 6378137.0; + *f = 1.0 / 298.257222101; + break; + + case WGS72: + *a = 6378135.0; + *f = 1.0 / 298.26; + break; + + default: + + /* Invalid identifier. */ + *a = 0.0; + *f = 0.0; + return -1; + + } + +/* OK status. */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/eo06a.c b/src/cpp/3rdparty/sofa/src/eo06a.c new file mode 100644 index 000000000..6bd5bcaac --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/eo06a.c @@ -0,0 +1,183 @@ +#include "sofa.h" + +double iauEo06a(double date1, double date2) +/* +** - - - - - - - - - +** i a u E o 0 6 a +** - - - - - - - - - +** +** Equation of the origins, IAU 2006 precession and IAU 2000A nutation. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double the equation of the origins in radians +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The equation of the origins is the distance between the true +** equinox and the celestial intermediate origin and, equivalently, +** the difference between Earth rotation angle and Greenwich +** apparent sidereal time (ERA-GST). It comprises the precession +** (since J2000.0) in right ascension plus the equation of the +** equinoxes (including the small correction terms). +** +** Called: +** iauPnm06a classical NPB matrix, IAU 2006/2000A +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS06 the CIO locator s, given X,Y, IAU 2006 +** iauEors equation of the origins, given NPB matrix and s +** +** References: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r[3][3], x, y, s, eo; + + +/* Classical nutation x precession x bias matrix. */ + iauPnm06a(date1, date2, r); + +/* Extract CIP coordinates. */ + iauBpn2xy(r, &x, &y); + +/* The CIO locator, s. */ + s = iauS06(date1, date2, x, y); + +/* Solve for the EO. */ + eo = iauEors(r, s); + + return eo; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/eors.c b/src/cpp/3rdparty/sofa/src/eors.c new file mode 100644 index 000000000..500f0476d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/eors.c @@ -0,0 +1,160 @@ +#include "sofa.h" + +double iauEors(double rnpb[3][3], double s) +/* +** - - - - - - - - +** i a u E o r s +** - - - - - - - - +** +** Equation of the origins, given the classical NPB matrix and the +** quantity s. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rnpb double[3][3] classical nutation x precession x bias matrix +** s double the quantity s (the CIO locator) in radians +** +** Returned (function value): +** double the equation of the origins in radians +** +** Notes: +** +** 1) The equation of the origins is the distance between the true +** equinox and the celestial intermediate origin and, equivalently, +** the difference between Earth rotation angle and Greenwich +** apparent sidereal time (ERA-GST). It comprises the precession +** (since J2000.0) in right ascension plus the equation of the +** equinoxes (including the small correction terms). +** +** 2) The algorithm is from Wallace & Capitaine (2006). +** +** References: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** Wallace, P. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, ax, xs, ys, zs, p, q, eo; + + +/* Evaluate Wallace & Capitaine (2006) expression (16). */ + x = rnpb[2][0]; + ax = x / (1.0 + rnpb[2][2]); + xs = 1.0 - ax * x; + ys = -ax * rnpb[2][1]; + zs = -x; + p = rnpb[0][0] * xs + rnpb[0][1] * ys + rnpb[0][2] * zs; + q = rnpb[1][0] * xs + rnpb[1][1] * ys + rnpb[1][2] * zs; + eo = ((p != 0) || (q != 0)) ? s - atan2(q, p) : s; + + return eo; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/epb.c b/src/cpp/3rdparty/sofa/src/epb.c new file mode 100644 index 000000000..f893dd4c2 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/epb.c @@ -0,0 +1,144 @@ +#include "sofa.h" +#include "sofam.h" + +double iauEpb(double dj1, double dj2) +/* +** - - - - - - - +** i a u E p b +** - - - - - - - +** +** Julian Date to Besselian Epoch. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** dj1,dj2 double Julian Date (see note) +** +** Returned (function value): +** double Besselian Epoch. +** +** Note: +** +** The Julian Date is supplied in two pieces, in the usual SOFA +** manner, which is designed to preserve time resolution. The +** Julian Date is available as a single number by adding dj1 and +** dj2. The maximum resolution is achieved if dj1 is 2451545.0 +** (J2000.0). +** +** Reference: +** +** Lieske, J.H., 1979. Astron.Astrophys., 73, 282. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* J2000.0-B1900.0 (2415019.81352) in days */ + const double D1900 = 36524.68648; + + return 1900.0 + ((dj1 - DJ00) + (dj2 + D1900)) / DTY; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/epb2jd.c b/src/cpp/3rdparty/sofa/src/epb2jd.c new file mode 100644 index 000000000..9d6c0fd77 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/epb2jd.c @@ -0,0 +1,142 @@ +#include "sofa.h" +#include "sofam.h" + +void iauEpb2jd(double epb, double *djm0, double *djm) +/* +** - - - - - - - - - - +** i a u E p b 2 j d +** - - - - - - - - - - +** +** Besselian Epoch to Julian Date. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epb double Besselian Epoch (e.g. 1957.3) +** +** Returned: +** djm0 double MJD zero-point: always 2400000.5 +** djm double Modified Julian Date +** +** Note: +** +** The Julian Date is returned in two pieces, in the usual SOFA +** manner, which is designed to preserve time resolution. The +** Julian Date is available as a single number by adding djm0 and +** djm. +** +** Reference: +** +** Lieske, J.H., 1979, Astron.Astrophys. 73, 282. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + *djm0 = DJM0; + *djm = 15019.81352 + (epb - 1900.0) * DTY; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/epj.c b/src/cpp/3rdparty/sofa/src/epj.c new file mode 100644 index 000000000..5dcaf1389 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/epj.c @@ -0,0 +1,146 @@ +#include "sofa.h" +#include "sofam.h" + +double iauEpj(double dj1, double dj2) +/* +** - - - - - - - +** i a u E p j +** - - - - - - - +** +** Julian Date to Julian Epoch. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** dj1,dj2 double Julian Date (see note) +** +** Returned (function value): +** double Julian Epoch +** +** Note: +** +** The Julian Date is supplied in two pieces, in the usual SOFA +** manner, which is designed to preserve time resolution. The +** Julian Date is available as a single number by adding dj1 and +** dj2. The maximum resolution is achieved if dj1 is 2451545.0 +** (J2000.0). +** +** Reference: +** +** Lieske, J.H., 1979, Astron.Astrophys. 73, 282. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double epj; + + + epj = 2000.0 + ((dj1 - DJ00) + dj2) / DJY; + + return epj; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/epj2jd.c b/src/cpp/3rdparty/sofa/src/epj2jd.c new file mode 100644 index 000000000..e915a68b0 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/epj2jd.c @@ -0,0 +1,142 @@ +#include "sofa.h" +#include "sofam.h" + +void iauEpj2jd(double epj, double *djm0, double *djm) +/* +** - - - - - - - - - - +** i a u E p j 2 j d +** - - - - - - - - - - +** +** Julian Epoch to Julian Date. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian Epoch (e.g. 1996.8) +** +** Returned: +** djm0 double MJD zero-point: always 2400000.5 +** djm double Modified Julian Date +** +** Note: +** +** The Julian Date is returned in two pieces, in the usual SOFA +** manner, which is designed to preserve time resolution. The +** Julian Date is available as a single number by adding djm0 and +** djm. +** +** Reference: +** +** Lieske, J.H., 1979, Astron.Astrophys. 73, 282. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + *djm0 = DJM0; + *djm = DJM00 + (epj - 2000.0) * 365.25; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/epv00.c b/src/cpp/3rdparty/sofa/src/epv00.c new file mode 100644 index 000000000..fddb363dd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/epv00.c @@ -0,0 +1,2642 @@ +#include "sofa.h" +#include "sofam.h" + +int iauEpv00(double date1, double date2, + double pvh[2][3], double pvb[2][3]) +/* +** - - - - - - - - - +** i a u E p v 0 0 +** - - - - - - - - - +** +** Earth position and velocity, heliocentric and barycentric, with +** respect to the Barycentric Celestial Reference System. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TDB date (Note 1) +** +** Returned: +** pvh double[2][3] heliocentric Earth position/velocity +** pvb double[2][3] barycentric Earth position/velocity +** +** Returned (function value): +** int status: 0 = OK +** +1 = warning: date outside +** the range 1900-2100 AD +** +** Notes: +** +** 1) The TDB date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TDB)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. However, +** the accuracy of the result is more likely to be limited by the +** algorithm itself than the way the date has been expressed. +** +** n.b. TT can be used instead of TDB in most applications. +** +** 2) On return, the arrays pvh and pvb contain the following: +** +** pvh[0][0] x } +** pvh[0][1] y } heliocentric position, au +** pvh[0][2] z } +** +** pvh[1][0] xdot } +** pvh[1][1] ydot } heliocentric velocity, au/d +** pvh[1][2] zdot } +** +** pvb[0][0] x } +** pvb[0][1] y } barycentric position, au +** pvb[0][2] z } +** +** pvb[1][0] xdot } +** pvb[1][1] ydot } barycentric velocity, au/d +** pvb[1][2] zdot } +** +** The vectors are with respect to the Barycentric Celestial +** Reference System. The time unit is one day in TDB. +** +** 3) The function is a SIMPLIFIED SOLUTION from the planetary theory +** VSOP2000 (X. Moisson, P. Bretagnon, 2001, Celes. Mechanics & +** Dyn. Astron., 80, 3/4, 205-213) and is an adaptation of original +** Fortran code supplied by P. Bretagnon (private comm., 2000). +** +** 4) Comparisons over the time span 1900-2100 with this simplified +** solution and the JPL DE405 ephemeris give the following results: +** +** RMS max +** Heliocentric: +** position error 3.7 11.2 km +** velocity error 1.4 5.0 mm/s +** +** Barycentric: +** position error 4.6 13.4 km +** velocity error 1.4 4.9 mm/s +** +** Comparisons with the JPL DE406 ephemeris show that by 1800 and +** 2200 the position errors are approximately double their 1900-2100 +** size. By 1500 and 2500 the deterioration is a factor of 10 and +** by 1000 and 3000 a factor of 60. The velocity accuracy falls off +** at about half that rate. +** +** 5) It is permissible to use the same array for pvh and pvb, which +** will receive the barycentric values. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* +** Matrix elements for orienting the analytical model to DE405. +** +** The corresponding Euler angles are: +** +** d ' " +** 1st rotation - 23 26 21.4091 about the x-axis (obliquity) +** 2nd rotation + 0.0475 about the z-axis (RA offset) +** +** These were obtained empirically, by comparisons with DE405 over +** 1900-2100. +*/ + static const double am12 = 0.000000211284, + am13 = -0.000000091603, + am21 = -0.000000230286, + am22 = 0.917482137087, + am23 = -0.397776982902, + am32 = 0.397776982902, + am33 = 0.917482137087; + +/* +** ---------------------- +** Ephemeris Coefficients +** ---------------------- +** +** The ephemeris consists of harmonic terms for predicting (i) the Sun +** to Earth vector and (ii) the Solar-System-barycenter to Sun vector +** respectively. The coefficients are stored in arrays which, although +** 1-demensional, contain groups of three. Each triplet of +** coefficients is the amplitude, phase and frequency for one term in +** the model, and each array contains the number of terms called for by +** the model. +** +** There are eighteen such arrays, named as follows: +** +** array model power of T component +** +** e0x Sun-to-Earth 0 x +** e0y Sun-to-Earth 0 y +** e0z Sun-to-Earth 0 z +** +** e1x Sun-to-Earth 1 x +** e1y Sun-to-Earth 1 y +** e1z Sun-to-Earth 1 z +** +** e2x Sun-to-Earth 2 x +** e2y Sun-to-Earth 2 y +** e2z Sun-to-Earth 2 z +** +** s0x SSB-to-Sun 0 x +** s0y SSB-to-Sun 0 y +** s0z SSB-to-Sun 0 z +** +** s1x SSB-to-Sun 1 x +** s1y SSB-to-Sun 1 y +** s1z SSB-to-Sun 1 z +** +** s2x SSB-to-Sun 2 x +** s2y SSB-to-Sun 2 y +** s2z SSB-to-Sun 2 z +*/ + +/* Sun-to-Earth, T^0, X */ + static const double e0x[] = { + 0.9998292878132e+00, 0.1753485171504e+01, 0.6283075850446e+01, + 0.8352579567414e-02, 0.1710344404582e+01, 0.1256615170089e+02, + 0.5611445335148e-02, 0.0000000000000e+00, 0.0000000000000e+00, + 0.1046664295572e-03, 0.1667225416770e+01, 0.1884922755134e+02, + 0.3110842534677e-04, 0.6687513390251e+00, 0.8399684731857e+02, + 0.2552413503550e-04, 0.5830637358413e+00, 0.5296909721118e+00, + 0.2137207845781e-04, 0.1092330954011e+01, 0.1577343543434e+01, + 0.1680240182951e-04, 0.4955366134987e+00, 0.6279552690824e+01, + 0.1679012370795e-04, 0.6153014091901e+01, 0.6286599010068e+01, + 0.1445526946777e-04, 0.3472744100492e+01, 0.2352866153506e+01, + + 0.1091038246184e-04, 0.3689845786119e+01, 0.5223693906222e+01, + 0.9344399733932e-05, 0.6073934645672e+01, 0.1203646072878e+02, + 0.8993182910652e-05, 0.3175705249069e+01, 0.1021328554739e+02, + 0.5665546034116e-05, 0.2152484672246e+01, 0.1059381944224e+01, + 0.6844146703035e-05, 0.1306964099750e+01, 0.5753384878334e+01, + 0.7346610905565e-05, 0.4354980070466e+01, 0.3981490189893e+00, + 0.6815396474414e-05, 0.2218229211267e+01, 0.4705732307012e+01, + 0.6112787253053e-05, 0.5384788425458e+01, 0.6812766822558e+01, + 0.4518120711239e-05, 0.6087604012291e+01, 0.5884926831456e+01, + 0.4521963430706e-05, 0.1279424524906e+01, 0.6256777527156e+01, + + 0.4497426764085e-05, 0.5369129144266e+01, 0.6309374173736e+01, + 0.4062190566959e-05, 0.5436473303367e+00, 0.6681224869435e+01, + 0.5412193480192e-05, 0.7867838528395e+00, 0.7755226100720e+00, + 0.5469839049386e-05, 0.1461440311134e+01, 0.1414349524433e+02, + 0.5205264083477e-05, 0.4432944696116e+01, 0.7860419393880e+01, + 0.2149759935455e-05, 0.4502237496846e+01, 0.1150676975667e+02, + 0.2279109618501e-05, 0.1239441308815e+01, 0.7058598460518e+01, + 0.2259282939683e-05, 0.3272430985331e+01, 0.4694002934110e+01, + 0.2558950271319e-05, 0.2265471086404e+01, 0.1216800268190e+02, + 0.2561581447555e-05, 0.1454740653245e+01, 0.7099330490126e+00, + + 0.1781441115440e-05, 0.2962068630206e+01, 0.7962980379786e+00, + 0.1612005874644e-05, 0.1473255041006e+01, 0.5486777812467e+01, + 0.1818630667105e-05, 0.3743903293447e+00, 0.6283008715021e+01, + 0.1818601377529e-05, 0.6274174354554e+01, 0.6283142985870e+01, + 0.1554475925257e-05, 0.1624110906816e+01, 0.2513230340178e+02, + 0.2090948029241e-05, 0.5852052276256e+01, 0.1179062909082e+02, + 0.2000176345460e-05, 0.4072093298513e+01, 0.1778984560711e+02, + 0.1289535917759e-05, 0.5217019331069e+01, 0.7079373888424e+01, + 0.1281135307881e-05, 0.4802054538934e+01, 0.3738761453707e+01, + 0.1518229005692e-05, 0.8691914742502e+00, 0.2132990797783e+00, + + 0.9450128579027e-06, 0.4601859529950e+01, 0.1097707878456e+02, + 0.7781119494996e-06, 0.1844352816694e+01, 0.8827390247185e+01, + 0.7733407759912e-06, 0.3582790154750e+01, 0.5507553240374e+01, + 0.7350644318120e-06, 0.2695277788230e+01, 0.1589072916335e+01, + 0.6535928827023e-06, 0.3651327986142e+01, 0.1176985366291e+02, + 0.6324624183656e-06, 0.2241302375862e+01, 0.6262300422539e+01, + 0.6298565300557e-06, 0.4407122406081e+01, 0.6303851278352e+01, + 0.8587037089179e-06, 0.3024307223119e+01, 0.1672837615881e+03, + 0.8299954491035e-06, 0.6192539428237e+01, 0.3340612434717e+01, + 0.6311263503401e-06, 0.2014758795416e+01, 0.7113454667900e-02, + + 0.6005646745452e-06, 0.3399500503397e+01, 0.4136910472696e+01, + 0.7917715109929e-06, 0.2493386877837e+01, 0.6069776770667e+01, + 0.7556958099685e-06, 0.4159491740143e+01, 0.6496374930224e+01, + 0.6773228244949e-06, 0.4034162934230e+01, 0.9437762937313e+01, + 0.5370708577847e-06, 0.1562219163734e+01, 0.1194447056968e+01, + 0.5710804266203e-06, 0.2662730803386e+01, 0.6282095334605e+01, + 0.5709824583726e-06, 0.3985828430833e+01, 0.6284056366286e+01, + 0.5143950896447e-06, 0.1308144688689e+01, 0.6290189305114e+01, + 0.5088010604546e-06, 0.5352817214804e+01, 0.6275962395778e+01, + 0.4960369085172e-06, 0.2644267922349e+01, 0.6127655567643e+01, + + 0.4803137891183e-06, 0.4008844192080e+01, 0.6438496133249e+01, + 0.5731747768225e-06, 0.3794550174597e+01, 0.3154687086868e+01, + 0.4735947960579e-06, 0.6107118308982e+01, 0.3128388763578e+01, + 0.4808348796625e-06, 0.4771458618163e+01, 0.8018209333619e+00, + 0.4115073743137e-06, 0.3327111335159e+01, 0.8429241228195e+01, + 0.5230575889287e-06, 0.5305708551694e+01, 0.1336797263425e+02, + 0.5133977889215e-06, 0.5784230738814e+01, 0.1235285262111e+02, + 0.5065815825327e-06, 0.2052064793679e+01, 0.1185621865188e+02, + 0.4339831593868e-06, 0.3644994195830e+01, 0.1726015463500e+02, + 0.3952928638953e-06, 0.4930376436758e+01, 0.5481254917084e+01, + + 0.4898498111942e-06, 0.4542084219731e+00, 0.9225539266174e+01, + 0.4757490209328e-06, 0.3161126388878e+01, 0.5856477690889e+01, + 0.4727701669749e-06, 0.6214993845446e+00, 0.2544314396739e+01, + 0.3800966681863e-06, 0.3040132339297e+01, 0.4265981595566e+00, + 0.3257301077939e-06, 0.8064977360087e+00, 0.3930209696940e+01, + 0.3255810528674e-06, 0.1974147981034e+01, 0.2146165377750e+01, + 0.3252029748187e-06, 0.2845924913135e+01, 0.4164311961999e+01, + 0.3255505635308e-06, 0.3017900824120e+01, 0.5088628793478e+01, + 0.2801345211990e-06, 0.6109717793179e+01, 0.1256967486051e+02, + 0.3688987740970e-06, 0.2911550235289e+01, 0.1807370494127e+02, + + 0.2475153429458e-06, 0.2179146025856e+01, 0.2629832328990e-01, + 0.3033457749150e-06, 0.1994161050744e+01, 0.4535059491685e+01, + 0.2186743763110e-06, 0.5125687237936e+01, 0.1137170464392e+02, + 0.2764777032774e-06, 0.4822646860252e+00, 0.1256262854127e+02, + 0.2199028768592e-06, 0.4637633293831e+01, 0.1255903824622e+02, + 0.2046482824760e-06, 0.1467038733093e+01, 0.7084896783808e+01, + 0.2611209147507e-06, 0.3044718783485e+00, 0.7143069561767e+02, + 0.2286079656818e-06, 0.4764220356805e+01, 0.8031092209206e+01, + 0.1855071202587e-06, 0.3383637774428e+01, 0.1748016358760e+01, + 0.2324669506784e-06, 0.6189088449251e+01, 0.1831953657923e+02, + + 0.1709528015688e-06, 0.5874966729774e+00, 0.4933208510675e+01, + 0.2168156875828e-06, 0.4302994009132e+01, 0.1044738781244e+02, + 0.2106675556535e-06, 0.3800475419891e+01, 0.7477522907414e+01, + 0.1430213830465e-06, 0.1294660846502e+01, 0.2942463415728e+01, + 0.1388396901944e-06, 0.4594797202114e+01, 0.8635942003952e+01, + 0.1922258844190e-06, 0.4943044543591e+00, 0.1729818233119e+02, + 0.1888460058292e-06, 0.2426943912028e+01, 0.1561374759853e+03, + 0.1789449386107e-06, 0.1582973303499e+00, 0.1592596075957e+01, + 0.1360803685374e-06, 0.5197240440504e+01, 0.1309584267300e+02, + 0.1504038014709e-06, 0.3120360916217e+01, 0.1649636139783e+02, + + 0.1382769533389e-06, 0.6164702888205e+01, 0.7632943190217e+01, + 0.1438059769079e-06, 0.1437423770979e+01, 0.2042657109477e+02, + 0.1326303260037e-06, 0.3609688799679e+01, 0.1213955354133e+02, + 0.1159244950540e-06, 0.5463018167225e+01, 0.5331357529664e+01, + 0.1433118149136e-06, 0.6028909912097e+01, 0.7342457794669e+01, + 0.1234623148594e-06, 0.3109645574997e+01, 0.6279485555400e+01, + 0.1233949875344e-06, 0.3539359332866e+01, 0.6286666145492e+01, + 0.9927196061299e-07, 0.1259321569772e+01, 0.7234794171227e+01, + 0.1242302191316e-06, 0.1065949392609e+01, 0.1511046609763e+02, + 0.1098402195201e-06, 0.2192508743837e+01, 0.1098880815746e+02, + + 0.1158191395315e-06, 0.4054411278650e+01, 0.5729506548653e+01, + 0.9048475596241e-07, 0.5429764748518e+01, 0.9623688285163e+01, + 0.8889853269023e-07, 0.5046586206575e+01, 0.6148010737701e+01, + 0.1048694242164e-06, 0.2628858030806e+01, 0.6836645152238e+01, + 0.1112308378646e-06, 0.4177292719907e+01, 0.1572083878776e+02, + 0.8631729709901e-07, 0.1601345232557e+01, 0.6418140963190e+01, + 0.8527816951664e-07, 0.2463888997513e+01, 0.1471231707864e+02, + 0.7892139456991e-07, 0.3154022088718e+01, 0.2118763888447e+01, + 0.1051782905236e-06, 0.4795035816088e+01, 0.1349867339771e+01, + 0.1048219943164e-06, 0.2952983395230e+01, 0.5999216516294e+01, + + 0.7435760775143e-07, 0.5420547991464e+01, 0.6040347114260e+01, + 0.9869574106949e-07, 0.3695646753667e+01, 0.6566935184597e+01, + 0.9156886364226e-07, 0.3922675306609e+01, 0.5643178611111e+01, + 0.7006834356188e-07, 0.1233968624861e+01, 0.6525804586632e+01, + 0.9806170182601e-07, 0.1919542280684e+01, 0.2122839202813e+02, + 0.9052289673607e-07, 0.4615902724369e+01, 0.4690479774488e+01, + 0.7554200867893e-07, 0.1236863719072e+01, 0.1253985337760e+02, + 0.8215741286498e-07, 0.3286800101559e+00, 0.1097355562493e+02, + 0.7185178575397e-07, 0.5880942158367e+01, 0.6245048154254e+01, + 0.7130726476180e-07, 0.7674871987661e+00, 0.6321103546637e+01, + + 0.6650894461162e-07, 0.6987129150116e+00, 0.5327476111629e+01, + 0.7396888823688e-07, 0.3576824794443e+01, 0.5368044267797e+00, + 0.7420588884775e-07, 0.5033615245369e+01, 0.2354323048545e+02, + 0.6141181642908e-07, 0.9449927045673e+00, 0.1296430071988e+02, + 0.6373557924058e-07, 0.6206342280341e+01, 0.9517183207817e+00, + 0.6359474329261e-07, 0.5036079095757e+01, 0.1990745094947e+01, + 0.5740173582646e-07, 0.6105106371350e+01, 0.9555997388169e+00, + 0.7019864084602e-07, 0.7237747359018e+00, 0.5225775174439e+00, + 0.6398054487042e-07, 0.3976367969666e+01, 0.2407292145756e+02, + 0.7797092650498e-07, 0.4305423910623e+01, 0.2200391463820e+02, + + 0.6466760000900e-07, 0.3500136825200e+01, 0.5230807360890e+01, + 0.7529417043890e-07, 0.3514779246100e+01, 0.1842262939178e+02, + 0.6924571140892e-07, 0.2743457928679e+01, 0.1554202828031e+00, + 0.6220798650222e-07, 0.2242598118209e+01, 0.1845107853235e+02, + 0.5870209391853e-07, 0.2332832707527e+01, 0.6398972393349e+00, + 0.6263953473888e-07, 0.2191105358956e+01, 0.6277552955062e+01, + 0.6257781390012e-07, 0.4457559396698e+01, 0.6288598745829e+01, + 0.5697304945123e-07, 0.3499234761404e+01, 0.1551045220144e+01, + 0.6335438746791e-07, 0.6441691079251e+00, 0.5216580451554e+01, + 0.6377258441152e-07, 0.2252599151092e+01, 0.5650292065779e+01, + + 0.6484841818165e-07, 0.1992812417646e+01, 0.1030928125552e+00, + 0.4735551485250e-07, 0.3744672082942e+01, 0.1431416805965e+02, + 0.4628595996170e-07, 0.1334226211745e+01, 0.5535693017924e+00, + 0.6258152336933e-07, 0.4395836159154e+01, 0.2608790314060e+02, + 0.6196171366594e-07, 0.2587043007997e+01, 0.8467247584405e+02, + 0.6159556952126e-07, 0.4782499769128e+01, 0.2394243902548e+03, + 0.4987741172394e-07, 0.7312257619924e+00, 0.7771377146812e+02, + 0.5459280703142e-07, 0.3001376372532e+01, 0.6179983037890e+01, + 0.4863461189999e-07, 0.3767222128541e+01, 0.9027992316901e+02, + 0.5349912093158e-07, 0.3663594450273e+01, 0.6386168663001e+01, + + 0.5673725607806e-07, 0.4331187919049e+01, 0.6915859635113e+01, + 0.4745485060512e-07, 0.5816195745518e+01, 0.6282970628506e+01, + 0.4745379005326e-07, 0.8323672435672e+00, 0.6283181072386e+01, + 0.4049002796321e-07, 0.3785023976293e+01, 0.6254626709878e+01, + 0.4247084014515e-07, 0.2378220728783e+01, 0.7875671926403e+01, + 0.4026912363055e-07, 0.2864103423269e+01, 0.6311524991013e+01, + 0.4062935011774e-07, 0.2415408595975e+01, 0.3634620989887e+01, + 0.5347771048509e-07, 0.3343479309801e+01, 0.2515860172507e+02, + 0.4829494136505e-07, 0.2821742398262e+01, 0.5760498333002e+01, + 0.4342554404599e-07, 0.5624662458712e+01, 0.7238675589263e+01, + + 0.4021599184361e-07, 0.5557250275009e+00, 0.1101510648075e+02, + 0.4104900474558e-07, 0.3296691780005e+01, 0.6709674010002e+01, + 0.4376532905131e-07, 0.3814443999443e+01, 0.6805653367890e+01, + 0.3314590480650e-07, 0.3560229189250e+01, 0.1259245002418e+02, + 0.3232421839643e-07, 0.5185389180568e+01, 0.1066495398892e+01, + 0.3541176318876e-07, 0.3921381909679e+01, 0.9917696840332e+01, + 0.3689831242681e-07, 0.4190658955386e+01, 0.1192625446156e+02, + 0.3890605376774e-07, 0.5546023371097e+01, 0.7478166569050e-01, + 0.3038559339780e-07, 0.6231032794494e+01, 0.1256621883632e+02, + 0.3137083969782e-07, 0.6207063419190e+01, 0.4292330755499e+01, + + 0.4024004081854e-07, 0.1195257375713e+01, 0.1334167431096e+02, + 0.3300234879283e-07, 0.1804694240998e+01, 0.1057540660594e+02, + 0.3635399155575e-07, 0.5597811343500e+01, 0.6208294184755e+01, + 0.3032668691356e-07, 0.3191059366530e+01, 0.1805292951336e+02, + 0.2809652069058e-07, 0.4094348032570e+01, 0.3523159621801e-02, + 0.3696955383823e-07, 0.5219282738794e+01, 0.5966683958112e+01, + 0.3562894142503e-07, 0.1037247544554e+01, 0.6357857516136e+01, + 0.3510598524148e-07, 0.1430020816116e+01, 0.6599467742779e+01, + 0.3617736142953e-07, 0.3002911403677e+01, 0.6019991944201e+01, + 0.2624524910730e-07, 0.2437046757292e+01, 0.6702560555334e+01, + + 0.2535824204490e-07, 0.1581594689647e+01, 0.3141537925223e+02, + 0.3519787226257e-07, 0.5379863121521e+01, 0.2505706758577e+03, + 0.2578406709982e-07, 0.4904222639329e+01, 0.1673046366289e+02, + 0.3423887981473e-07, 0.3646448997315e+01, 0.6546159756691e+01, + 0.2776083886467e-07, 0.3307829300144e+01, 0.1272157198369e+02, + 0.3379592818379e-07, 0.1747541251125e+01, 0.1494531617769e+02, + 0.3050255426284e-07, 0.1784689432607e-01, 0.4732030630302e+01, + 0.2652378350236e-07, 0.4420055276260e+01, 0.5863591145557e+01, + 0.2374498173768e-07, 0.3629773929208e+01, 0.2388894113936e+01, + 0.2716451255140e-07, 0.3079623706780e+01, 0.1202934727411e+02, + + 0.3038583699229e-07, 0.3312487903507e+00, 0.1256608456547e+02, + 0.2220681228760e-07, 0.5265520401774e+01, 0.1336244973887e+02, + 0.3044156540912e-07, 0.4766664081250e+01, 0.2908881142201e+02, + 0.2731859923561e-07, 0.5069146530691e+01, 0.1391601904066e+02, + 0.2285603018171e-07, 0.5954935112271e+01, 0.6076890225335e+01, + 0.2025006454555e-07, 0.4061789589267e+01, 0.4701116388778e+01, + 0.2012597519804e-07, 0.2485047705241e+01, 0.6262720680387e+01, + 0.2003406962258e-07, 0.4163779209320e+01, 0.6303431020504e+01, + 0.2207863441371e-07, 0.6923839133828e+00, 0.6489261475556e+01, + 0.2481374305624e-07, 0.5944173595676e+01, 0.1204357418345e+02, + + 0.2130923288870e-07, 0.4641013671967e+01, 0.5746271423666e+01, + 0.2446370543391e-07, 0.6125796518757e+01, 0.1495633313810e+00, + 0.1932492759052e-07, 0.2234572324504e+00, 0.1352175143971e+02, + 0.2600122568049e-07, 0.4281012405440e+01, 0.4590910121555e+01, + 0.2431754047488e-07, 0.1429943874870e+00, 0.1162474756779e+01, + 0.1875902869209e-07, 0.9781803816948e+00, 0.6279194432410e+01, + 0.1874381139426e-07, 0.5670368130173e+01, 0.6286957268481e+01, + 0.2156696047173e-07, 0.2008985006833e+01, 0.1813929450232e+02, + 0.1965076182484e-07, 0.2566186202453e+00, 0.4686889479442e+01, + 0.2334816372359e-07, 0.4408121891493e+01, 0.1002183730415e+02, + + 0.1869937408802e-07, 0.5272745038656e+01, 0.2427287361862e+00, + 0.2436236460883e-07, 0.4407720479029e+01, 0.9514313292143e+02, + 0.1761365216611e-07, 0.1943892315074e+00, 0.1351787002167e+02, + 0.2156289480503e-07, 0.1418570924545e+01, 0.6037244212485e+01, + 0.2164748979255e-07, 0.4724603439430e+01, 0.2301353951334e+02, + 0.2222286670853e-07, 0.2400266874598e+01, 0.1266924451345e+02, + 0.2070901414929e-07, 0.5230348028732e+01, 0.6528907488406e+01, + 0.1792745177020e-07, 0.2099190328945e+01, 0.6819880277225e+01, + 0.1841802068445e-07, 0.3467527844848e+00, 0.6514761976723e+02, + 0.1578401631718e-07, 0.7098642356340e+00, 0.2077542790660e-01, + + 0.1561690152531e-07, 0.5943349620372e+01, 0.6272439236156e+01, + 0.1558591045463e-07, 0.7040653478980e+00, 0.6293712464735e+01, + 0.1737356469576e-07, 0.4487064760345e+01, 0.1765478049437e+02, + 0.1434755619991e-07, 0.2993391570995e+01, 0.1102062672231e+00, + 0.1482187806654e-07, 0.2278049198251e+01, 0.1052268489556e+01, + 0.1424812827089e-07, 0.1682114725827e+01, 0.1311972100268e+02, + 0.1380282448623e-07, 0.3262668602579e+01, 0.1017725758696e+02, + 0.1811481244566e-07, 0.3187771221777e+01, 0.1887552587463e+02, + 0.1504446185696e-07, 0.5650162308647e+01, 0.7626583626240e-01, + 0.1740776154137e-07, 0.5487068607507e+01, 0.1965104848470e+02, + + 0.1374339536251e-07, 0.5745688172201e+01, 0.6016468784579e+01, + 0.1761377477704e-07, 0.5748060203659e+01, 0.2593412433514e+02, + 0.1535138225795e-07, 0.6226848505790e+01, 0.9411464614024e+01, + 0.1788140543676e-07, 0.6189318878563e+01, 0.3301902111895e+02, + 0.1375002807996e-07, 0.5371812884394e+01, 0.6327837846670e+00, + 0.1242115758632e-07, 0.1471687569712e+01, 0.3894181736510e+01, + 0.1450977333938e-07, 0.4143836662127e+01, 0.1277945078067e+02, + 0.1297579575023e-07, 0.9003477661957e+00, 0.6549682916313e+01, + 0.1462667934821e-07, 0.5760505536428e+01, 0.1863592847156e+02, + 0.1381774374799e-07, 0.1085471729463e+01, 0.2379164476796e+01, + + 0.1682333169307e-07, 0.5409870870133e+01, 0.1620077269078e+02, + 0.1190812918837e-07, 0.1397205174601e+01, 0.1149965630200e+02, + 0.1221434762106e-07, 0.9001804809095e+00, 0.1257326515556e+02, + 0.1549934644860e-07, 0.4262528275544e+01, 0.1820933031200e+02, + 0.1252138953050e-07, 0.1411642012027e+01, 0.6993008899458e+01, + 0.1237078905387e-07, 0.2844472403615e+01, 0.2435678079171e+02, + 0.1446953389615e-07, 0.5295835522223e+01, 0.3813291813120e-01, + 0.1388446457170e-07, 0.4969428135497e+01, 0.2458316379602e+00, + 0.1019339179228e-07, 0.2491369561806e+01, 0.6112403035119e+01, + 0.1258880815343e-07, 0.4679426248976e+01, 0.5429879531333e+01, + + 0.1297768238261e-07, 0.1074509953328e+01, 0.1249137003520e+02, + 0.9913505718094e-08, 0.4735097918224e+01, 0.6247047890016e+01, + 0.9830453155969e-08, 0.4158649187338e+01, 0.6453748665772e+01, + 0.1192615865309e-07, 0.3438208613699e+01, 0.6290122169689e+01, + 0.9835874798277e-08, 0.1913300781229e+01, 0.6319103810876e+01, + 0.9639087569277e-08, 0.9487683644125e+00, 0.8273820945392e+01, + 0.1175716107001e-07, 0.3228141664287e+01, 0.6276029531202e+01, + 0.1018926508678e-07, 0.2216607854300e+01, 0.1254537627298e+02, + 0.9500087869225e-08, 0.2625116459733e+01, 0.1256517118505e+02, + 0.9664192916575e-08, 0.5860562449214e+01, 0.6259197520765e+01, + + 0.9612858712203e-08, 0.7885682917381e+00, 0.6306954180126e+01, + 0.1117645675413e-07, 0.3932148831189e+01, 0.1779695906178e+02, + 0.1158864052160e-07, 0.9995605521691e+00, 0.1778273215245e+02, + 0.9021043467028e-08, 0.5263769742673e+01, 0.6172869583223e+01, + 0.8836134773563e-08, 0.1496843220365e+01, 0.1692165728891e+01, + 0.1045872200691e-07, 0.7009039517214e+00, 0.2204125344462e+00, + 0.1211463487798e-07, 0.4041544938511e+01, 0.8257698122054e+02, + 0.8541990804094e-08, 0.1447586692316e+01, 0.6393282117669e+01, + 0.1038720703636e-07, 0.4594249718112e+00, 0.1550861511662e+02, + 0.1126722351445e-07, 0.3925550579036e+01, 0.2061856251104e+00, + + 0.8697373859631e-08, 0.4411341856037e+01, 0.9491756770005e+00, + 0.8869380028441e-08, 0.2402659724813e+01, 0.3903911373650e+01, + 0.9247014693258e-08, 0.1401579743423e+01, 0.6267823317922e+01, + 0.9205062930950e-08, 0.5245978000814e+01, 0.6298328382969e+01, + 0.8000745038049e-08, 0.3590803356945e+01, 0.2648454860559e+01, + 0.9168973650819e-08, 0.2470150501679e+01, 0.1498544001348e+03, + 0.1075444949238e-07, 0.1328606161230e+01, 0.3694923081589e+02, + 0.7817298525817e-08, 0.6162256225998e+01, 0.4804209201333e+01, + 0.9541469226356e-08, 0.3942568967039e+01, 0.1256713221673e+02, + 0.9821910122027e-08, 0.2360246287233e+00, 0.1140367694411e+02, + + 0.9897822023777e-08, 0.4619805634280e+01, 0.2280573557157e+02, + 0.7737289283765e-08, 0.3784727847451e+01, 0.7834121070590e+01, + 0.9260204034710e-08, 0.2223352487601e+01, 0.2787043132925e+01, + 0.7320252888486e-08, 0.1288694636874e+01, 0.6282655592598e+01, + 0.7319785780946e-08, 0.5359869567774e+01, 0.6283496108294e+01, + 0.7147219933778e-08, 0.5516616675856e+01, 0.1725663147538e+02, + 0.7946502829878e-08, 0.2630459984567e+01, 0.1241073141809e+02, + 0.9001711808932e-08, 0.2849815827227e+01, 0.6281591679874e+01, + 0.8994041507257e-08, 0.3795244450750e+01, 0.6284560021018e+01, + 0.8298582787358e-08, 0.5236413127363e+00, 0.1241658836951e+02, + + 0.8526596520710e-08, 0.4794605424426e+01, 0.1098419223922e+02, + 0.8209822103197e-08, 0.1578752370328e+01, 0.1096996532989e+02, + 0.6357049861094e-08, 0.5708926113761e+01, 0.1596186371003e+01, + 0.7370473179049e-08, 0.3842402530241e+01, 0.4061219149443e+01, + 0.7232154664726e-08, 0.3067548981535e+01, 0.1610006857377e+03, + 0.6328765494903e-08, 0.1313930030069e+01, 0.1193336791622e+02, + 0.8030064908595e-08, 0.3488500408886e+01, 0.8460828644453e+00, + 0.6275464259232e-08, 0.1532061626198e+01, 0.8531963191132e+00, + 0.7051897446325e-08, 0.3285859929993e+01, 0.5849364236221e+01, + 0.6161593705428e-08, 0.1477341999464e+01, 0.5573142801433e+01, + + 0.7754683957278e-08, 0.1586118663096e+01, 0.8662240327241e+01, + 0.5889928990701e-08, 0.1304887868803e+01, 0.1232342296471e+02, + 0.5705756047075e-08, 0.4555333589350e+01, 0.1258692712880e+02, + 0.5964178808332e-08, 0.3001762842062e+01, 0.5333900173445e+01, + 0.6712446027467e-08, 0.4886780007595e+01, 0.1171295538178e+02, + 0.5941809275464e-08, 0.4701509603824e+01, 0.9779108567966e+01, + 0.5466993627395e-08, 0.4588357817278e+01, 0.1884211409667e+02, + 0.6340512090980e-08, 0.1164543038893e+01, 0.5217580628120e+02, + 0.6325505710045e-08, 0.3919171259645e+01, 0.1041998632314e+02, + 0.6164789509685e-08, 0.2143828253542e+01, 0.6151533897323e+01, + + 0.5263330812430e-08, 0.6066564434241e+01, 0.1885275071096e+02, + 0.5597087780221e-08, 0.2926316429472e+01, 0.4337116142245e+00, + 0.5396556236817e-08, 0.3244303591505e+01, 0.6286362197481e+01, + 0.5396615148223e-08, 0.3404304703662e+01, 0.6279789503410e+01, + 0.7091832443341e-08, 0.8532377803192e+00, 0.4907302013889e+01, + 0.6572352589782e-08, 0.4901966774419e+01, 0.1176433076753e+02, + 0.5960236060795e-08, 0.1874672315797e+01, 0.1422690933580e-01, + 0.5125480043511e-08, 0.3735726064334e+01, 0.1245594543367e+02, + 0.5928241866410e-08, 0.4502033899935e+01, 0.6414617803568e+01, + 0.5249600357424e-08, 0.4372334799878e+01, 0.1151388321134e+02, + + 0.6059171276087e-08, 0.2581617302908e+01, 0.6062663316000e+01, + 0.5295235081662e-08, 0.2974811513158e+01, 0.3496032717521e+01, + 0.5820561875933e-08, 0.1796073748244e+00, 0.2838593341516e+00, + 0.4754696606440e-08, 0.1981998136973e+01, 0.3104930017775e+01, + 0.6385053548955e-08, 0.2559174171605e+00, 0.6133512519065e+01, + 0.6589828273941e-08, 0.2750967106776e+01, 0.4087944051283e+02, + 0.5383376567189e-08, 0.6325947523578e+00, 0.2248384854122e+02, + 0.5928941683538e-08, 0.1672304519067e+01, 0.1581959461667e+01, + 0.4816060709794e-08, 0.3512566172575e+01, 0.9388005868221e+01, + 0.6003381586512e-08, 0.5610932219189e+01, 0.5326786718777e+01, + + 0.5504225393105e-08, 0.4037501131256e+01, 0.6503488384892e+01, + 0.5353772620129e-08, 0.6122774968240e+01, 0.1735668374386e+03, + 0.5786253768544e-08, 0.5527984999515e+01, 0.1350651127443e+00, + 0.5065706702002e-08, 0.9980765573624e+00, 0.1248988586463e+02, + 0.5972838885276e-08, 0.6044489493203e+01, 0.2673594526851e+02, + 0.5323585877961e-08, 0.3924265998147e+01, 0.4171425416666e+01, + 0.5210772682858e-08, 0.6220111376901e+01, 0.2460261242967e+02, + 0.4726549040535e-08, 0.3716043206862e+01, 0.7232251527446e+01, + 0.6029425105059e-08, 0.8548704071116e+00, 0.3227113045244e+03, + 0.4481542826513e-08, 0.1426925072829e+01, 0.5547199253223e+01, + + 0.5836024505068e-08, 0.7135651752625e-01, 0.7285056171570e+02, + 0.4137046613272e-08, 0.5330767643283e+01, 0.1087398597200e+02, + 0.5171977473924e-08, 0.4494262335353e+00, 0.1884570439172e+02, + 0.5694429833732e-08, 0.2952369582215e+01, 0.9723862754494e+02, + 0.4009158925298e-08, 0.3500003416535e+01, 0.6244942932314e+01, + 0.4784939596873e-08, 0.6196709413181e+01, 0.2929661536378e+02, + 0.3983725022610e-08, 0.5103690031897e+01, 0.4274518229222e+01, + 0.3870535232462e-08, 0.3187569587401e+01, 0.6321208768577e+01, + 0.5140501213951e-08, 0.1668924357457e+01, 0.1232032006293e+02, + 0.3849034819355e-08, 0.4445722510309e+01, 0.1726726808967e+02, + + 0.4002383075060e-08, 0.5226224152423e+01, 0.7018952447668e+01, + 0.3890719543549e-08, 0.4371166550274e+01, 0.1491901785440e+02, + 0.4887084607881e-08, 0.5973556689693e+01, 0.1478866649112e+01, + 0.3739939287592e-08, 0.2089084714600e+01, 0.6922973089781e+01, + 0.5031925918209e-08, 0.4658371936827e+01, 0.1715706182245e+02, + 0.4387748764954e-08, 0.4825580552819e+01, 0.2331413144044e+03, + 0.4147398098865e-08, 0.3739003524998e+01, 0.1376059875786e+02, + 0.3719089993586e-08, 0.1148941386536e+01, 0.6297302759782e+01, + 0.3934238461056e-08, 0.1559893008343e+01, 0.7872148766781e+01, + 0.3672471375622e-08, 0.5516145383612e+01, 0.6268848941110e+01, + + 0.3768911277583e-08, 0.6116053700563e+01, 0.4157198507331e+01, + 0.4033388417295e-08, 0.5076821746017e+01, 0.1567108171867e+02, + 0.3764194617832e-08, 0.8164676232075e+00, 0.3185192151914e+01, + 0.4840628226284e-08, 0.1360479453671e+01, 0.1252801878276e+02, + 0.4949443923785e-08, 0.2725622229926e+01, 0.1617106187867e+03, + 0.4117393089971e-08, 0.6054459628492e+00, 0.5642198095270e+01, + 0.3925754020428e-08, 0.8570462135210e+00, 0.2139354194808e+02, + 0.3630551757923e-08, 0.3552067338279e+01, 0.6294805223347e+01, + 0.3627274802357e-08, 0.3096565085313e+01, 0.6271346477544e+01, + 0.3806143885093e-08, 0.6367751709777e+00, 0.1725304118033e+02, + + 0.4433254641565e-08, 0.4848461503937e+01, 0.7445550607224e+01, + 0.3712319846576e-08, 0.1331950643655e+01, 0.4194847048887e+00, + 0.3849847534783e-08, 0.4958368297746e+00, 0.9562891316684e+00, + 0.3483955430165e-08, 0.2237215515707e+01, 0.1161697602389e+02, + 0.3961912730982e-08, 0.3332402188575e+01, 0.2277943724828e+02, + 0.3419978244481e-08, 0.5785600576016e+01, 0.1362553364512e+02, + 0.3329417758177e-08, 0.9812676559709e-01, 0.1685848245639e+02, + 0.4207206893193e-08, 0.9494780468236e+00, 0.2986433403208e+02, + 0.3268548976410e-08, 0.1739332095686e+00, 0.5749861718712e+01, + 0.3321880082685e-08, 0.1423354800666e+01, 0.6279143387820e+01, + + 0.4503173010852e-08, 0.2314972675293e+00, 0.1385561574497e+01, + 0.4316599090954e-08, 0.1012646782616e+00, 0.4176041334900e+01, + 0.3283493323850e-08, 0.5233306881265e+01, 0.6287008313071e+01, + 0.3164033542343e-08, 0.4005597257511e+01, 0.2099539292909e+02, + 0.4159720956725e-08, 0.5365676242020e+01, 0.5905702259363e+01, + 0.3565176892217e-08, 0.4284440620612e+01, 0.3932462625300e-02, + 0.3514440950221e-08, 0.4270562636575e+01, 0.7335344340001e+01, + 0.3540596871909e-08, 0.5953553201060e+01, 0.1234573916645e+02, + 0.2960769905118e-08, 0.1115180417718e+01, 0.2670964694522e+02, + 0.2962213739684e-08, 0.3863811918186e+01, 0.6408777551755e+00, + + 0.3883556700251e-08, 0.1268617928302e+01, 0.6660449441528e+01, + 0.2919225516346e-08, 0.4908605223265e+01, 0.1375773836557e+01, + 0.3115158863370e-08, 0.3744519976885e+01, 0.3802769619140e-01, + 0.4099438144212e-08, 0.4173244670532e+01, 0.4480965020977e+02, + 0.2899531858964e-08, 0.5910601428850e+01, 0.2059724391010e+02, + 0.3289733429855e-08, 0.2488050078239e+01, 0.1081813534213e+02, + 0.3933075612875e-08, 0.1122363652883e+01, 0.3773735910827e+00, + 0.3021403764467e-08, 0.4951973724904e+01, 0.2982630633589e+02, + 0.2798598949757e-08, 0.5117057845513e+01, 0.1937891852345e+02, + 0.3397421302707e-08, 0.6104159180476e+01, 0.6923953605621e+01, + + 0.3720398002179e-08, 0.1184933429829e+01, 0.3066615496545e+02, + 0.3598484186267e-08, 0.3505282086105e+01, 0.6147450479709e+01, + 0.3694594027310e-08, 0.2286651088141e+01, 0.2636725487657e+01, + 0.2680444152969e-08, 0.1871816775482e+00, 0.6816289982179e+01, + 0.3497574865641e-08, 0.3143251755431e+01, 0.6418701221183e+01, + 0.3130274129494e-08, 0.2462167316018e+01, 0.1235996607578e+02, + 0.3241119069551e-08, 0.4256374004686e+01, 0.1652265972112e+02, + 0.2601960842061e-08, 0.4970362941425e+01, 0.1045450126711e+02, + 0.2690601527504e-08, 0.2372657824898e+01, 0.3163918923335e+00, + 0.2908688152664e-08, 0.4232652627721e+01, 0.2828699048865e+02, + + 0.3120456131875e-08, 0.3925747001137e+00, 0.2195415756911e+02, + 0.3148855423384e-08, 0.3093478330445e+01, 0.1172006883645e+02, + 0.3051044261017e-08, 0.5560948248212e+01, 0.6055599646783e+01, + 0.2826006876660e-08, 0.5072790310072e+01, 0.5120601093667e+01, + 0.3100034191711e-08, 0.4998530231096e+01, 0.1799603123222e+02, + 0.2398771640101e-08, 0.2561739802176e+01, 0.6255674361143e+01, + 0.2384002842728e-08, 0.4087420284111e+01, 0.6310477339748e+01, + 0.2842146517568e-08, 0.2515048217955e+01, 0.5469525544182e+01, + 0.2847674371340e-08, 0.5235326497443e+01, 0.1034429499989e+02, + 0.2903722140764e-08, 0.1088200795797e+01, 0.6510552054109e+01, + + 0.3187610710605e-08, 0.4710624424816e+01, 0.1693792562116e+03, + 0.3048869992813e-08, 0.2857975896445e+00, 0.8390110365991e+01, + 0.2860216950984e-08, 0.2241619020815e+01, 0.2243449970715e+00, + 0.2701117683113e-08, 0.6651573305272e-01, 0.6129297044991e+01, + 0.2509891590152e-08, 0.1285135324585e+01, 0.1044027435778e+02, + 0.2623200252223e-08, 0.2981229834530e+00, 0.6436854655901e+01, + 0.2622541669202e-08, 0.6122470726189e+01, 0.9380959548977e+01, + 0.2818435667099e-08, 0.4251087148947e+01, 0.5934151399930e+01, + 0.2365196797465e-08, 0.3465070460790e+01, 0.2470570524223e+02, + 0.2358704646143e-08, 0.5791603815350e+01, 0.8671969964381e+01, + + 0.2388299481390e-08, 0.4142483772941e+01, 0.7096626156709e+01, + 0.1996041217224e-08, 0.2101901889496e+01, 0.1727188400790e+02, + 0.2687593060336e-08, 0.1526689456959e+01, 0.7075506709219e+02, + 0.2618913670810e-08, 0.2397684236095e+01, 0.6632000300961e+01, + 0.2571523050364e-08, 0.5751929456787e+00, 0.6206810014183e+01, + 0.2582135006946e-08, 0.5595464352926e+01, 0.4873985990671e+02, + 0.2372530190361e-08, 0.5092689490655e+01, 0.1590676413561e+02, + 0.2357178484712e-08, 0.4444363527851e+01, 0.3097883698531e+01, + 0.2451590394723e-08, 0.3108251687661e+01, 0.6612329252343e+00, + 0.2370045949608e-08, 0.2608133861079e+01, 0.3459636466239e+02, + + 0.2268997267358e-08, 0.3639717753384e+01, 0.2844914056730e-01, + 0.1731432137906e-08, 0.1741898445707e+00, 0.2019909489111e+02, + 0.1629869741622e-08, 0.3902225646724e+01, 0.3035599730800e+02, + 0.2206215801974e-08, 0.4971131250731e+01, 0.6281667977667e+01, + 0.2205469554680e-08, 0.1677462357110e+01, 0.6284483723224e+01, + 0.2148792362509e-08, 0.4236259604006e+01, 0.1980482729015e+02, + 0.1873733657847e-08, 0.5926814998687e+01, 0.2876692439167e+02, + 0.2026573758959e-08, 0.4349643351962e+01, 0.2449240616245e+02, + 0.1807770325110e-08, 0.5700940482701e+01, 0.2045286941806e+02, + 0.1881174408581e-08, 0.6601286363430e+00, 0.2358125818164e+02, + + 0.1368023671690e-08, 0.2211098592752e+01, 0.2473415438279e+02, + 0.1720017916280e-08, 0.4942488551129e+01, 0.1679593901136e+03, + 0.1702427665131e-08, 0.1452233856386e+01, 0.3338575901272e+03, + 0.1414032510054e-08, 0.5525357721439e+01, 0.1624205518357e+03, + 0.1652626045364e-08, 0.4108794283624e+01, 0.8956999012000e+02, + 0.1642957769686e-08, 0.7344335209984e+00, 0.5267006960365e+02, + 0.1614952403624e-08, 0.3541213951363e+01, 0.3332657872986e+02, + 0.1535988291188e-08, 0.4031094072151e+01, 0.3852657435933e+02, + 0.1593193738177e-08, 0.4185136203609e+01, 0.2282781046519e+03, + 0.1074569126382e-08, 0.1720485636868e+01, 0.8397383534231e+02, + + 0.1074408214509e-08, 0.2758613420318e+01, 0.8401985929482e+02, + 0.9700199670465e-09, 0.4216686842097e+01, 0.7826370942180e+02, + 0.1258433517061e-08, 0.2575068876639e+00, 0.3115650189215e+03, + 0.1240303229539e-08, 0.4800844956756e+00, 0.1784300471910e+03, + 0.9018345948127e-09, 0.3896756361552e+00, 0.5886454391678e+02, + 0.1135301432805e-08, 0.3700805023550e+00, 0.7842370451713e+02, + 0.9215887951370e-09, 0.4364579276638e+01, 0.1014262087719e+03, + 0.1055401054147e-08, 0.2156564222111e+01, 0.5660027930059e+02, + 0.1008725979831e-08, 0.5454015785234e+01, 0.4245678405627e+02, + 0.7217398104321e-09, 0.1597772562175e+01, 0.2457074661053e+03, + + 0.6912033134447e-09, 0.5824090621461e+01, 0.1679936946371e+03, + 0.6833881523549e-09, 0.3578778482835e+01, 0.6053048899753e+02, + 0.4887304205142e-09, 0.3724362812423e+01, 0.9656299901946e+02, + 0.5173709754788e-09, 0.5422427507933e+01, 0.2442876000072e+03, + 0.4671353097145e-09, 0.2396106924439e+01, 0.1435713242844e+03, + 0.5652608439480e-09, 0.2804028838685e+01, 0.8365903305582e+02, + 0.5604061331253e-09, 0.1638816006247e+01, 0.8433466158131e+02, + 0.4712723365400e-09, 0.8979003224474e+00, 0.3164282286739e+03, + 0.4909967465112e-09, 0.3210426725516e+01, 0.4059982187939e+03, + 0.4771358267658e-09, 0.5308027211629e+01, 0.1805255418145e+03, + + 0.3943451445989e-09, 0.2195145341074e+01, 0.2568537517081e+03, + 0.3952109120244e-09, 0.5081189491586e+01, 0.2449975330562e+03, + 0.3788134594789e-09, 0.4345171264441e+01, 0.1568131045107e+03, + 0.3738330190479e-09, 0.2613062847997e+01, 0.3948519331910e+03, + 0.3099866678136e-09, 0.2846760817689e+01, 0.1547176098872e+03, + 0.2002962716768e-09, 0.4921360989412e+01, 0.2268582385539e+03, + 0.2198291338754e-09, 0.1130360117454e+00, 0.1658638954901e+03, + 0.1491958330784e-09, 0.4228195232278e+01, 0.2219950288015e+03, + 0.1475384076173e-09, 0.3005721811604e+00, 0.3052819430710e+03, + 0.1661626624624e-09, 0.7830125621203e+00, 0.2526661704812e+03, + + 0.9015823460025e-10, 0.3807792942715e+01, 0.4171445043968e+03 }; + +/* Sun-to-Earth, T^0, Y */ + static const double e0y[] = { + 0.9998921098898e+00, 0.1826583913846e+00, 0.6283075850446e+01, + -0.2442700893735e-01, 0.0000000000000e+00, 0.0000000000000e+00, + 0.8352929742915e-02, 0.1395277998680e+00, 0.1256615170089e+02, + 0.1046697300177e-03, 0.9641423109763e-01, 0.1884922755134e+02, + 0.3110841876663e-04, 0.5381140401712e+01, 0.8399684731857e+02, + 0.2570269094593e-04, 0.5301016407128e+01, 0.5296909721118e+00, + 0.2147389623610e-04, 0.2662510869850e+01, 0.1577343543434e+01, + 0.1680344384050e-04, 0.5207904119704e+01, 0.6279552690824e+01, + 0.1679117312193e-04, 0.4582187486968e+01, 0.6286599010068e+01, + 0.1440512068440e-04, 0.1900688517726e+01, 0.2352866153506e+01, + + 0.1135139664999e-04, 0.5273108538556e+01, 0.5223693906222e+01, + 0.9345482571018e-05, 0.4503047687738e+01, 0.1203646072878e+02, + 0.9007418719568e-05, 0.1605621059637e+01, 0.1021328554739e+02, + 0.5671536712314e-05, 0.5812849070861e+00, 0.1059381944224e+01, + 0.7451401861666e-05, 0.2807346794836e+01, 0.3981490189893e+00, + 0.6393470057114e-05, 0.6029224133855e+01, 0.5753384878334e+01, + 0.6814275881697e-05, 0.6472990145974e+00, 0.4705732307012e+01, + 0.6113705628887e-05, 0.3813843419700e+01, 0.6812766822558e+01, + 0.4503851367273e-05, 0.4527804370996e+01, 0.5884926831456e+01, + 0.4522249141926e-05, 0.5991783029224e+01, 0.6256777527156e+01, + + 0.4501794307018e-05, 0.3798703844397e+01, 0.6309374173736e+01, + 0.5514927480180e-05, 0.3961257833388e+01, 0.5507553240374e+01, + 0.4062862799995e-05, 0.5256247296369e+01, 0.6681224869435e+01, + 0.5414900429712e-05, 0.5499032014097e+01, 0.7755226100720e+00, + 0.5463153987424e-05, 0.6173092454097e+01, 0.1414349524433e+02, + 0.5071611859329e-05, 0.2870244247651e+01, 0.7860419393880e+01, + 0.2195112094455e-05, 0.2952338617201e+01, 0.1150676975667e+02, + 0.2279139233919e-05, 0.5951775132933e+01, 0.7058598460518e+01, + 0.2278386100876e-05, 0.4845456398785e+01, 0.4694002934110e+01, + 0.2559088003308e-05, 0.6945321117311e+00, 0.1216800268190e+02, + + 0.2561079286856e-05, 0.6167224608301e+01, 0.7099330490126e+00, + 0.1792755796387e-05, 0.1400122509632e+01, 0.7962980379786e+00, + 0.1818715656502e-05, 0.4703347611830e+01, 0.6283142985870e+01, + 0.1818744924791e-05, 0.5086748900237e+01, 0.6283008715021e+01, + 0.1554518791390e-05, 0.5331008042713e-01, 0.2513230340178e+02, + 0.2063265737239e-05, 0.4283680484178e+01, 0.1179062909082e+02, + 0.1497613520041e-05, 0.6074207826073e+01, 0.5486777812467e+01, + 0.2000617940427e-05, 0.2501426281450e+01, 0.1778984560711e+02, + 0.1289731195580e-05, 0.3646340599536e+01, 0.7079373888424e+01, + 0.1282657998934e-05, 0.3232864804902e+01, 0.3738761453707e+01, + + 0.1528915968658e-05, 0.5581433416669e+01, 0.2132990797783e+00, + 0.1187304098432e-05, 0.5453576453694e+01, 0.9437762937313e+01, + 0.7842782928118e-06, 0.2823953922273e+00, 0.8827390247185e+01, + 0.7352892280868e-06, 0.1124369580175e+01, 0.1589072916335e+01, + 0.6570189360797e-06, 0.2089154042840e+01, 0.1176985366291e+02, + 0.6324967590410e-06, 0.6704855581230e+00, 0.6262300422539e+01, + 0.6298289872283e-06, 0.2836414855840e+01, 0.6303851278352e+01, + 0.6476686465855e-06, 0.4852433866467e+00, 0.7113454667900e-02, + 0.8587034651234e-06, 0.1453511005668e+01, 0.1672837615881e+03, + 0.8068948788113e-06, 0.9224087798609e+00, 0.6069776770667e+01, + + 0.8353786011661e-06, 0.4631707184895e+01, 0.3340612434717e+01, + 0.6009324532132e-06, 0.1829498827726e+01, 0.4136910472696e+01, + 0.7558158559566e-06, 0.2588596800317e+01, 0.6496374930224e+01, + 0.5809279504503e-06, 0.5516818853476e+00, 0.1097707878456e+02, + 0.5374131950254e-06, 0.6275674734960e+01, 0.1194447056968e+01, + 0.5711160507326e-06, 0.1091905956872e+01, 0.6282095334605e+01, + 0.5710183170746e-06, 0.2415001635090e+01, 0.6284056366286e+01, + 0.5144373590610e-06, 0.6020336443438e+01, 0.6290189305114e+01, + 0.5103108927267e-06, 0.3775634564605e+01, 0.6275962395778e+01, + 0.4960654697891e-06, 0.1073450946756e+01, 0.6127655567643e+01, + + 0.4786385689280e-06, 0.2431178012310e+01, 0.6438496133249e+01, + 0.6109911263665e-06, 0.5343356157914e+01, 0.3154687086868e+01, + 0.4839898944024e-06, 0.5830833594047e-01, 0.8018209333619e+00, + 0.4734822623919e-06, 0.4536080134821e+01, 0.3128388763578e+01, + 0.4834741473290e-06, 0.2585090489754e+00, 0.7084896783808e+01, + 0.5134858581156e-06, 0.4213317172603e+01, 0.1235285262111e+02, + 0.5064004264978e-06, 0.4814418806478e+00, 0.1185621865188e+02, + 0.3753476772761e-06, 0.1599953399788e+01, 0.8429241228195e+01, + 0.4935264014283e-06, 0.2157417556873e+01, 0.2544314396739e+01, + 0.3950929600897e-06, 0.3359394184254e+01, 0.5481254917084e+01, + + 0.4895849789777e-06, 0.5165704376558e+01, 0.9225539266174e+01, + 0.4215241688886e-06, 0.2065368800993e+01, 0.1726015463500e+02, + 0.3796773731132e-06, 0.1468606346612e+01, 0.4265981595566e+00, + 0.3114178142515e-06, 0.3615638079474e+01, 0.2146165377750e+01, + 0.3260664220838e-06, 0.4417134922435e+01, 0.4164311961999e+01, + 0.3976996123008e-06, 0.4700866883004e+01, 0.5856477690889e+01, + 0.2801459672924e-06, 0.4538902060922e+01, 0.1256967486051e+02, + 0.3638931868861e-06, 0.1334197991475e+01, 0.1807370494127e+02, + 0.2487013269476e-06, 0.3749275558275e+01, 0.2629832328990e-01, + 0.3034165481994e-06, 0.4236622030873e+00, 0.4535059491685e+01, + + 0.2676278825586e-06, 0.5970848007811e+01, 0.3930209696940e+01, + 0.2764903818918e-06, 0.5194636754501e+01, 0.1256262854127e+02, + 0.2485149930507e-06, 0.1002434207846e+01, 0.5088628793478e+01, + 0.2199305540941e-06, 0.3066773098403e+01, 0.1255903824622e+02, + 0.2571106500435e-06, 0.7588312459063e+00, 0.1336797263425e+02, + 0.2049751817158e-06, 0.3444977434856e+01, 0.1137170464392e+02, + 0.2599707296297e-06, 0.1873128542205e+01, 0.7143069561767e+02, + 0.1785018072217e-06, 0.5015891306615e+01, 0.1748016358760e+01, + 0.2324833891115e-06, 0.4618271239730e+01, 0.1831953657923e+02, + 0.1709711119545e-06, 0.5300003455669e+01, 0.4933208510675e+01, + + 0.2107159351716e-06, 0.2229819815115e+01, 0.7477522907414e+01, + 0.1750333080295e-06, 0.6161485880008e+01, 0.1044738781244e+02, + 0.2000598210339e-06, 0.2967357299999e+01, 0.8031092209206e+01, + 0.1380920248681e-06, 0.3027007923917e+01, 0.8635942003952e+01, + 0.1412460470299e-06, 0.6037597163798e+01, 0.2942463415728e+01, + 0.1888459803001e-06, 0.8561476243374e+00, 0.1561374759853e+03, + 0.1788370542585e-06, 0.4869736290209e+01, 0.1592596075957e+01, + 0.1360893296167e-06, 0.3626411886436e+01, 0.1309584267300e+02, + 0.1506846530160e-06, 0.1550975377427e+01, 0.1649636139783e+02, + 0.1800913376176e-06, 0.2075826033190e+01, 0.1729818233119e+02, + + 0.1436261390649e-06, 0.6148876420255e+01, 0.2042657109477e+02, + 0.1220227114151e-06, 0.4382583879906e+01, 0.7632943190217e+01, + 0.1337883603592e-06, 0.2036644327361e+01, 0.1213955354133e+02, + 0.1159326650738e-06, 0.3892276994687e+01, 0.5331357529664e+01, + 0.1352853128569e-06, 0.1447950649744e+01, 0.1673046366289e+02, + 0.1433408296083e-06, 0.4457854692961e+01, 0.7342457794669e+01, + 0.1234701666518e-06, 0.1538818147151e+01, 0.6279485555400e+01, + 0.1234027192007e-06, 0.1968523220760e+01, 0.6286666145492e+01, + 0.1244024091797e-06, 0.5779803499985e+01, 0.1511046609763e+02, + 0.1097934945516e-06, 0.6210975221388e+00, 0.1098880815746e+02, + + 0.1254611329856e-06, 0.2591963807998e+01, 0.1572083878776e+02, + 0.1158247286784e-06, 0.2483612812670e+01, 0.5729506548653e+01, + 0.9039078252960e-07, 0.3857554579796e+01, 0.9623688285163e+01, + 0.9108024978836e-07, 0.5826368512984e+01, 0.7234794171227e+01, + 0.8887068108436e-07, 0.3475694573987e+01, 0.6148010737701e+01, + 0.8632374035438e-07, 0.3059070488983e-01, 0.6418140963190e+01, + 0.7893186992967e-07, 0.1583194837728e+01, 0.2118763888447e+01, + 0.8297650201172e-07, 0.8519770534637e+00, 0.1471231707864e+02, + 0.1019759578988e-06, 0.1319598738732e+00, 0.1349867339771e+01, + 0.1010037696236e-06, 0.9937860115618e+00, 0.6836645152238e+01, + + 0.1047727548266e-06, 0.1382138405399e+01, 0.5999216516294e+01, + 0.7351993881086e-07, 0.3833397851735e+01, 0.6040347114260e+01, + 0.9868771092341e-07, 0.2124913814390e+01, 0.6566935184597e+01, + 0.7007321959390e-07, 0.5946305343763e+01, 0.6525804586632e+01, + 0.6861411679709e-07, 0.4574654977089e+01, 0.7238675589263e+01, + 0.7554519809614e-07, 0.5949232686844e+01, 0.1253985337760e+02, + 0.9541880448335e-07, 0.3495242990564e+01, 0.2122839202813e+02, + 0.7185606722155e-07, 0.4310113471661e+01, 0.6245048154254e+01, + 0.7131360871710e-07, 0.5480309323650e+01, 0.6321103546637e+01, + 0.6651142021039e-07, 0.5411097713654e+01, 0.5327476111629e+01, + + 0.8538618213667e-07, 0.1827849973951e+01, 0.1101510648075e+02, + 0.8634954288044e-07, 0.5443584943349e+01, 0.5643178611111e+01, + 0.7449415051484e-07, 0.2011535459060e+01, 0.5368044267797e+00, + 0.7421047599169e-07, 0.3464562529249e+01, 0.2354323048545e+02, + 0.6140694354424e-07, 0.5657556228815e+01, 0.1296430071988e+02, + 0.6353525143033e-07, 0.3463816593821e+01, 0.1990745094947e+01, + 0.6221964013447e-07, 0.1532259498697e+01, 0.9517183207817e+00, + 0.5852480257244e-07, 0.1375396598875e+01, 0.9555997388169e+00, + 0.6398637498911e-07, 0.2405645801972e+01, 0.2407292145756e+02, + 0.7039744069878e-07, 0.5397541799027e+01, 0.5225775174439e+00, + + 0.6977997694382e-07, 0.4762347105419e+01, 0.1097355562493e+02, + 0.7460629558396e-07, 0.2711944692164e+01, 0.2200391463820e+02, + 0.5376577536101e-07, 0.2352980430239e+01, 0.1431416805965e+02, + 0.7530607893556e-07, 0.1943940180699e+01, 0.1842262939178e+02, + 0.6822928971605e-07, 0.4337651846959e+01, 0.1554202828031e+00, + 0.6220772380094e-07, 0.6716871369278e+00, 0.1845107853235e+02, + 0.6586950799043e-07, 0.2229714460505e+01, 0.5216580451554e+01, + 0.5873800565771e-07, 0.7627013920580e+00, 0.6398972393349e+00, + 0.6264346929745e-07, 0.6202785478961e+00, 0.6277552955062e+01, + 0.6257929115669e-07, 0.2886775596668e+01, 0.6288598745829e+01, + + 0.5343536033409e-07, 0.1977241012051e+01, 0.4690479774488e+01, + 0.5587849781714e-07, 0.1922923484825e+01, 0.1551045220144e+01, + 0.6905100845603e-07, 0.3570757164631e+01, 0.1030928125552e+00, + 0.6178957066649e-07, 0.5197558947765e+01, 0.5230807360890e+01, + 0.6187270224331e-07, 0.8193497368922e+00, 0.5650292065779e+01, + 0.5385664291426e-07, 0.5406336665586e+01, 0.7771377146812e+02, + 0.6329363917926e-07, 0.2837760654536e+01, 0.2608790314060e+02, + 0.4546018761604e-07, 0.2933580297050e+01, 0.5535693017924e+00, + 0.6196091049375e-07, 0.4157871494377e+01, 0.8467247584405e+02, + 0.6159555108218e-07, 0.3211703561703e+01, 0.2394243902548e+03, + + 0.4995340539317e-07, 0.1459098102922e+01, 0.4732030630302e+01, + 0.5457031243572e-07, 0.1430457676136e+01, 0.6179983037890e+01, + 0.4863461418397e-07, 0.2196425916730e+01, 0.9027992316901e+02, + 0.5342947626870e-07, 0.2086612890268e+01, 0.6386168663001e+01, + 0.5674296648439e-07, 0.2760204966535e+01, 0.6915859635113e+01, + 0.4745783120161e-07, 0.4245368971862e+01, 0.6282970628506e+01, + 0.4745676961198e-07, 0.5544725787016e+01, 0.6283181072386e+01, + 0.4049796869973e-07, 0.2213984363586e+01, 0.6254626709878e+01, + 0.4248333596940e-07, 0.8075781952896e+00, 0.7875671926403e+01, + 0.4027178070205e-07, 0.1293268540378e+01, 0.6311524991013e+01, + + 0.4066543943476e-07, 0.3986141175804e+01, 0.3634620989887e+01, + 0.4858863787880e-07, 0.1276112738231e+01, 0.5760498333002e+01, + 0.5277398263530e-07, 0.4916111741527e+01, 0.2515860172507e+02, + 0.4105635656559e-07, 0.1725805864426e+01, 0.6709674010002e+01, + 0.4376781925772e-07, 0.2243642442106e+01, 0.6805653367890e+01, + 0.3235827894693e-07, 0.3614135118271e+01, 0.1066495398892e+01, + 0.3073244740308e-07, 0.2460873393460e+01, 0.5863591145557e+01, + 0.3088609271373e-07, 0.5678431771790e+01, 0.9917696840332e+01, + 0.3393022279836e-07, 0.3814017477291e+01, 0.1391601904066e+02, + 0.3038686508802e-07, 0.4660216229171e+01, 0.1256621883632e+02, + + 0.4019677752497e-07, 0.5906906243735e+01, 0.1334167431096e+02, + 0.3288834998232e-07, 0.9536146445882e+00, 0.1620077269078e+02, + 0.3889973794631e-07, 0.3942205097644e+01, 0.7478166569050e-01, + 0.3050438987141e-07, 0.1624810271286e+01, 0.1805292951336e+02, + 0.3601142564638e-07, 0.4030467142575e+01, 0.6208294184755e+01, + 0.3689015557141e-07, 0.3648878818694e+01, 0.5966683958112e+01, + 0.3563471893565e-07, 0.5749584017096e+01, 0.6357857516136e+01, + 0.2776183170667e-07, 0.2630124187070e+01, 0.3523159621801e-02, + 0.2922350530341e-07, 0.1790346403629e+01, 0.1272157198369e+02, + 0.3511076917302e-07, 0.6142198301611e+01, 0.6599467742779e+01, + + 0.3619351007632e-07, 0.1432421386492e+01, 0.6019991944201e+01, + 0.2561254711098e-07, 0.2302822475792e+01, 0.1259245002418e+02, + 0.2626903942920e-07, 0.8660470994571e+00, 0.6702560555334e+01, + 0.2550187397083e-07, 0.6069721995383e+01, 0.1057540660594e+02, + 0.2535873526138e-07, 0.1079020331795e-01, 0.3141537925223e+02, + 0.3519786153847e-07, 0.3809066902283e+01, 0.2505706758577e+03, + 0.3424651492873e-07, 0.2075435114417e+01, 0.6546159756691e+01, + 0.2372676630861e-07, 0.2057803120154e+01, 0.2388894113936e+01, + 0.2710980779541e-07, 0.1510068488010e+01, 0.1202934727411e+02, + 0.3038710889704e-07, 0.5043617528901e+01, 0.1256608456547e+02, + + 0.2220364130585e-07, 0.3694793218205e+01, 0.1336244973887e+02, + 0.3025880825460e-07, 0.5450618999049e-01, 0.2908881142201e+02, + 0.2784493486864e-07, 0.3381164084502e+01, 0.1494531617769e+02, + 0.2294414142438e-07, 0.4382309025210e+01, 0.6076890225335e+01, + 0.2012723294724e-07, 0.9142212256518e+00, 0.6262720680387e+01, + 0.2036357831958e-07, 0.5676172293154e+01, 0.4701116388778e+01, + 0.2003474823288e-07, 0.2592767977625e+01, 0.6303431020504e+01, + 0.2207144900109e-07, 0.5404976271180e+01, 0.6489261475556e+01, + 0.2481664905135e-07, 0.4373284587027e+01, 0.1204357418345e+02, + 0.2674949182295e-07, 0.5859182188482e+01, 0.4590910121555e+01, + + 0.2450554720322e-07, 0.4555381557451e+01, 0.1495633313810e+00, + 0.2601975986457e-07, 0.3933165584959e+01, 0.1965104848470e+02, + 0.2199860022848e-07, 0.5227977189087e+01, 0.1351787002167e+02, + 0.2448121172316e-07, 0.4858060353949e+01, 0.1162474756779e+01, + 0.1876014864049e-07, 0.5690546553605e+01, 0.6279194432410e+01, + 0.1874513219396e-07, 0.4099539297446e+01, 0.6286957268481e+01, + 0.2156380842559e-07, 0.4382594769913e+00, 0.1813929450232e+02, + 0.1981691240061e-07, 0.1829784152444e+01, 0.4686889479442e+01, + 0.2329992648539e-07, 0.2836254278973e+01, 0.1002183730415e+02, + 0.1765184135302e-07, 0.2803494925833e+01, 0.4292330755499e+01, + + 0.2436368366085e-07, 0.2836897959677e+01, 0.9514313292143e+02, + 0.2164089203889e-07, 0.6127522446024e+01, 0.6037244212485e+01, + 0.1847755034221e-07, 0.3683163635008e+01, 0.2427287361862e+00, + 0.1674798769966e-07, 0.3316993867246e+00, 0.1311972100268e+02, + 0.2222542124356e-07, 0.8294097805480e+00, 0.1266924451345e+02, + 0.2071074505925e-07, 0.3659492220261e+01, 0.6528907488406e+01, + 0.1608224471835e-07, 0.4774492067182e+01, 0.1352175143971e+02, + 0.1857583439071e-07, 0.2873120597682e+01, 0.8662240327241e+01, + 0.1793018836159e-07, 0.5282441177929e+00, 0.6819880277225e+01, + 0.1575391221692e-07, 0.1320789654258e+01, 0.1102062672231e+00, + + 0.1840132009557e-07, 0.1917110916256e+01, 0.6514761976723e+02, + 0.1760917288281e-07, 0.2972635937132e+01, 0.5746271423666e+01, + 0.1561779518516e-07, 0.4372569261981e+01, 0.6272439236156e+01, + 0.1558687885205e-07, 0.5416424926425e+01, 0.6293712464735e+01, + 0.1951359382579e-07, 0.3094448898752e+01, 0.2301353951334e+02, + 0.1569144275614e-07, 0.2802103689808e+01, 0.1765478049437e+02, + 0.1479130389462e-07, 0.2136435020467e+01, 0.2077542790660e-01, + 0.1467828510764e-07, 0.7072627435674e+00, 0.1052268489556e+01, + 0.1627627337440e-07, 0.3947607143237e+01, 0.6327837846670e+00, + 0.1503498479758e-07, 0.4079248909190e+01, 0.7626583626240e-01, + + 0.1297967708237e-07, 0.6269637122840e+01, 0.1149965630200e+02, + 0.1374416896634e-07, 0.4175657970702e+01, 0.6016468784579e+01, + 0.1783812325219e-07, 0.1476540547560e+01, 0.3301902111895e+02, + 0.1525884228756e-07, 0.4653477715241e+01, 0.9411464614024e+01, + 0.1451067396763e-07, 0.2573001128225e+01, 0.1277945078067e+02, + 0.1297713111950e-07, 0.5612799618771e+01, 0.6549682916313e+01, + 0.1462784012820e-07, 0.4189661623870e+01, 0.1863592847156e+02, + 0.1384185980007e-07, 0.2656915472196e+01, 0.2379164476796e+01, + 0.1221497599801e-07, 0.5612515760138e+01, 0.1257326515556e+02, + 0.1560574525896e-07, 0.4783414317919e+01, 0.1887552587463e+02, + + 0.1544598372036e-07, 0.2694431138063e+01, 0.1820933031200e+02, + 0.1531678928696e-07, 0.4105103489666e+01, 0.2593412433514e+02, + 0.1349321503795e-07, 0.3082437194015e+00, 0.5120601093667e+01, + 0.1252030290917e-07, 0.6124072334087e+01, 0.6993008899458e+01, + 0.1459243816687e-07, 0.3733103981697e+01, 0.3813291813120e-01, + 0.1226103625262e-07, 0.1267127706817e+01, 0.2435678079171e+02, + 0.1019449641504e-07, 0.4367790112269e+01, 0.1725663147538e+02, + 0.1380789433607e-07, 0.3387201768700e+01, 0.2458316379602e+00, + 0.1019453421658e-07, 0.9204143073737e+00, 0.6112403035119e+01, + 0.1297929434405e-07, 0.5786874896426e+01, 0.1249137003520e+02, + + 0.9912677786097e-08, 0.3164232870746e+01, 0.6247047890016e+01, + 0.9829386098599e-08, 0.2586762413351e+01, 0.6453748665772e+01, + 0.1226807746104e-07, 0.6239068436607e+01, 0.5429879531333e+01, + 0.1192691755997e-07, 0.1867380051424e+01, 0.6290122169689e+01, + 0.9836499227081e-08, 0.3424716293727e+00, 0.6319103810876e+01, + 0.9642862564285e-08, 0.5661372990657e+01, 0.8273820945392e+01, + 0.1165184404862e-07, 0.5768367239093e+01, 0.1778273215245e+02, + 0.1175794418818e-07, 0.1657351222943e+01, 0.6276029531202e+01, + 0.1018948635601e-07, 0.6458292350865e+00, 0.1254537627298e+02, + 0.9500383606676e-08, 0.1054306140741e+01, 0.1256517118505e+02, + + 0.1227512202906e-07, 0.2505278379114e+01, 0.2248384854122e+02, + 0.9664792009993e-08, 0.4289737277000e+01, 0.6259197520765e+01, + 0.9613285666331e-08, 0.5500597673141e+01, 0.6306954180126e+01, + 0.1117906736211e-07, 0.2361405953468e+01, 0.1779695906178e+02, + 0.9611378640782e-08, 0.2851310576269e+01, 0.2061856251104e+00, + 0.8845354852370e-08, 0.6208777705343e+01, 0.1692165728891e+01, + 0.1054046966600e-07, 0.5413091423934e+01, 0.2204125344462e+00, + 0.1215539124483e-07, 0.5613969479755e+01, 0.8257698122054e+02, + 0.9932460955209e-08, 0.1106124877015e+01, 0.1017725758696e+02, + 0.8785804715043e-08, 0.2869224476477e+01, 0.9491756770005e+00, + + 0.8538084097562e-08, 0.6159640899344e+01, 0.6393282117669e+01, + 0.8648994369529e-08, 0.1374901198784e+01, 0.4804209201333e+01, + 0.1039063219067e-07, 0.5171080641327e+01, 0.1550861511662e+02, + 0.8867983926439e-08, 0.8317320304902e+00, 0.3903911373650e+01, + 0.8327495955244e-08, 0.3605591969180e+01, 0.6172869583223e+01, + 0.9243088356133e-08, 0.6114299196843e+01, 0.6267823317922e+01, + 0.9205657357835e-08, 0.3675153683737e+01, 0.6298328382969e+01, + 0.1033269714606e-07, 0.3313328813024e+01, 0.5573142801433e+01, + 0.8001706275552e-08, 0.2019980960053e+01, 0.2648454860559e+01, + 0.9171858254191e-08, 0.8992015524177e+00, 0.1498544001348e+03, + + 0.1075327150242e-07, 0.2898669963648e+01, 0.3694923081589e+02, + 0.9884866689828e-08, 0.4946715904478e+01, 0.1140367694411e+02, + 0.9541835576677e-08, 0.2371787888469e+01, 0.1256713221673e+02, + 0.7739903376237e-08, 0.2213775190612e+01, 0.7834121070590e+01, + 0.7311962684106e-08, 0.3429378787739e+01, 0.1192625446156e+02, + 0.9724904869624e-08, 0.6195878564404e+01, 0.2280573557157e+02, + 0.9251628983612e-08, 0.6511509527390e+00, 0.2787043132925e+01, + 0.7320763787842e-08, 0.6001083639421e+01, 0.6282655592598e+01, + 0.7320296650962e-08, 0.3789073265087e+01, 0.6283496108294e+01, + 0.7947032271039e-08, 0.1059659582204e+01, 0.1241073141809e+02, + + 0.9005277053115e-08, 0.1280315624361e+01, 0.6281591679874e+01, + 0.8995601652048e-08, 0.2224439106766e+01, 0.6284560021018e+01, + 0.8288040568796e-08, 0.5234914433867e+01, 0.1241658836951e+02, + 0.6359381347255e-08, 0.4137989441490e+01, 0.1596186371003e+01, + 0.8699572228626e-08, 0.1758411009497e+01, 0.6133512519065e+01, + 0.6456797542736e-08, 0.5919285089994e+01, 0.1685848245639e+02, + 0.7424573475452e-08, 0.5414616938827e+01, 0.4061219149443e+01, + 0.7235671196168e-08, 0.1496516557134e+01, 0.1610006857377e+03, + 0.8104015182733e-08, 0.1919918242764e+01, 0.8460828644453e+00, + 0.8098576535937e-08, 0.3819615855458e+01, 0.3894181736510e+01, + + 0.6275292346625e-08, 0.6244264115141e+01, 0.8531963191132e+00, + 0.6052432989112e-08, 0.5037731872610e+00, 0.1567108171867e+02, + 0.5705651535817e-08, 0.2984557271995e+01, 0.1258692712880e+02, + 0.5789650115138e-08, 0.6087038140697e+01, 0.1193336791622e+02, + 0.5512132153377e-08, 0.5855668994076e+01, 0.1232342296471e+02, + 0.7388890819102e-08, 0.2443128574740e+01, 0.4907302013889e+01, + 0.5467593991798e-08, 0.3017561234194e+01, 0.1884211409667e+02, + 0.6388519802999e-08, 0.5887386712935e+01, 0.5217580628120e+02, + 0.6106777149944e-08, 0.3483461059895e+00, 0.1422690933580e-01, + 0.7383420275489e-08, 0.5417387056707e+01, 0.2358125818164e+02, + + 0.5505208141738e-08, 0.2848193644783e+01, 0.1151388321134e+02, + 0.6310757462877e-08, 0.2349882520828e+01, 0.1041998632314e+02, + 0.6166904929691e-08, 0.5728575944077e+00, 0.6151533897323e+01, + 0.5263442042754e-08, 0.4495796125937e+01, 0.1885275071096e+02, + 0.5591828082629e-08, 0.1355441967677e+01, 0.4337116142245e+00, + 0.5397051680497e-08, 0.1673422864307e+01, 0.6286362197481e+01, + 0.5396992745159e-08, 0.1833502206373e+01, 0.6279789503410e+01, + 0.6572913000726e-08, 0.3331122065824e+01, 0.1176433076753e+02, + 0.5123421866413e-08, 0.2165327142679e+01, 0.1245594543367e+02, + 0.5930495725999e-08, 0.2931146089284e+01, 0.6414617803568e+01, + + 0.6431797403933e-08, 0.4134407994088e+01, 0.1350651127443e+00, + 0.5003182207604e-08, 0.3805420303749e+01, 0.1096996532989e+02, + 0.5587731032504e-08, 0.1082469260599e+01, 0.6062663316000e+01, + 0.5935263407816e-08, 0.8384333678401e+00, 0.5326786718777e+01, + 0.4756019827760e-08, 0.3552588749309e+01, 0.3104930017775e+01, + 0.6599951172637e-08, 0.4320826409528e+01, 0.4087944051283e+02, + 0.5902606868464e-08, 0.4811879454445e+01, 0.5849364236221e+01, + 0.5921147809031e-08, 0.9942628922396e-01, 0.1581959461667e+01, + 0.5505382581266e-08, 0.2466557607764e+01, 0.6503488384892e+01, + 0.5353771071862e-08, 0.4551978748683e+01, 0.1735668374386e+03, + + 0.5063282210946e-08, 0.5710812312425e+01, 0.1248988586463e+02, + 0.5926120403383e-08, 0.1333998428358e+01, 0.2673594526851e+02, + 0.5211016176149e-08, 0.4649315360760e+01, 0.2460261242967e+02, + 0.5347075084894e-08, 0.5512754081205e+01, 0.4171425416666e+01, + 0.4872609773574e-08, 0.1308025299938e+01, 0.5333900173445e+01, + 0.4727711321420e-08, 0.2144908368062e+01, 0.7232251527446e+01, + 0.6029426018652e-08, 0.5567259412084e+01, 0.3227113045244e+03, + 0.4321485284369e-08, 0.5230667156451e+01, 0.9388005868221e+01, + 0.4476406760553e-08, 0.6134081115303e+01, 0.5547199253223e+01, + 0.5835268277420e-08, 0.4783808492071e+01, 0.7285056171570e+02, + + 0.5172183602748e-08, 0.5161817911099e+01, 0.1884570439172e+02, + 0.5693571465184e-08, 0.1381646203111e+01, 0.9723862754494e+02, + 0.4060634965349e-08, 0.3876705259495e+00, 0.4274518229222e+01, + 0.3967398770473e-08, 0.5029491776223e+01, 0.3496032717521e+01, + 0.3943754005255e-08, 0.1923162955490e+01, 0.6244942932314e+01, + 0.4781323427824e-08, 0.4633332586423e+01, 0.2929661536378e+02, + 0.3871483781204e-08, 0.1616650009743e+01, 0.6321208768577e+01, + 0.5141741733997e-08, 0.9817316704659e-01, 0.1232032006293e+02, + 0.4002385978497e-08, 0.3656161212139e+01, 0.7018952447668e+01, + 0.4901092604097e-08, 0.4404098713092e+01, 0.1478866649112e+01, + + 0.3740932630345e-08, 0.5181188732639e+00, 0.6922973089781e+01, + 0.4387283718538e-08, 0.3254859566869e+01, 0.2331413144044e+03, + 0.5019197802033e-08, 0.3086773224677e+01, 0.1715706182245e+02, + 0.3834931695175e-08, 0.2797882673542e+01, 0.1491901785440e+02, + 0.3760413942497e-08, 0.2892676280217e+01, 0.1726726808967e+02, + 0.3719717204628e-08, 0.5861046025739e+01, 0.6297302759782e+01, + 0.4145623530149e-08, 0.2168239627033e+01, 0.1376059875786e+02, + 0.3932788425380e-08, 0.6271811124181e+01, 0.7872148766781e+01, + 0.3686377476857e-08, 0.3936853151404e+01, 0.6268848941110e+01, + 0.3779077950339e-08, 0.1404148734043e+01, 0.4157198507331e+01, + + 0.4091334550598e-08, 0.2452436180854e+01, 0.9779108567966e+01, + 0.3926694536146e-08, 0.6102292739040e+01, 0.1098419223922e+02, + 0.4841000253289e-08, 0.6072760457276e+01, 0.1252801878276e+02, + 0.4949340130240e-08, 0.1154832815171e+01, 0.1617106187867e+03, + 0.3761557737360e-08, 0.5527545321897e+01, 0.3185192151914e+01, + 0.3647396268188e-08, 0.1525035688629e+01, 0.6271346477544e+01, + 0.3932405074189e-08, 0.5570681040569e+01, 0.2139354194808e+02, + 0.3631322501141e-08, 0.1981240601160e+01, 0.6294805223347e+01, + 0.4130007425139e-08, 0.2050060880201e+01, 0.2195415756911e+02, + 0.4433905965176e-08, 0.3277477970321e+01, 0.7445550607224e+01, + + 0.3851814176947e-08, 0.5210690074886e+01, 0.9562891316684e+00, + 0.3485807052785e-08, 0.6653274904611e+00, 0.1161697602389e+02, + 0.3979772816991e-08, 0.1767941436148e+01, 0.2277943724828e+02, + 0.3402607460500e-08, 0.3421746306465e+01, 0.1087398597200e+02, + 0.4049993000926e-08, 0.1127144787547e+01, 0.3163918923335e+00, + 0.3420511182382e-08, 0.4214794779161e+01, 0.1362553364512e+02, + 0.3640772365012e-08, 0.5324905497687e+01, 0.1725304118033e+02, + 0.3323037987501e-08, 0.6135761838271e+01, 0.6279143387820e+01, + 0.4503141663637e-08, 0.1802305450666e+01, 0.1385561574497e+01, + 0.4314560055588e-08, 0.4812299731574e+01, 0.4176041334900e+01, + + 0.3294226949110e-08, 0.3657547059723e+01, 0.6287008313071e+01, + 0.3215657197281e-08, 0.4866676894425e+01, 0.5749861718712e+01, + 0.4129362656266e-08, 0.3809342558906e+01, 0.5905702259363e+01, + 0.3137762976388e-08, 0.2494635174443e+01, 0.2099539292909e+02, + 0.3514010952384e-08, 0.2699961831678e+01, 0.7335344340001e+01, + 0.3327607571530e-08, 0.3318457714816e+01, 0.5436992986000e+01, + 0.3541066946675e-08, 0.4382703582466e+01, 0.1234573916645e+02, + 0.3216179847052e-08, 0.5271066317054e+01, 0.3802769619140e-01, + 0.2959045059570e-08, 0.5819591585302e+01, 0.2670964694522e+02, + 0.3884040326665e-08, 0.5980934960428e+01, 0.6660449441528e+01, + + 0.2922027539886e-08, 0.3337290282483e+01, 0.1375773836557e+01, + 0.4110846382042e-08, 0.5742978187327e+01, 0.4480965020977e+02, + 0.2934508411032e-08, 0.2278075804200e+01, 0.6408777551755e+00, + 0.3966896193000e-08, 0.5835747858477e+01, 0.3773735910827e+00, + 0.3286695827610e-08, 0.5838898193902e+01, 0.3932462625300e-02, + 0.3720643094196e-08, 0.1122212337858e+01, 0.1646033343740e+02, + 0.3285508906174e-08, 0.9182250996416e+00, 0.1081813534213e+02, + 0.3753880575973e-08, 0.5174761973266e+01, 0.5642198095270e+01, + 0.3022129385587e-08, 0.3381611020639e+01, 0.2982630633589e+02, + 0.2798569205621e-08, 0.3546193723922e+01, 0.1937891852345e+02, + + 0.3397872070505e-08, 0.4533203197934e+01, 0.6923953605621e+01, + 0.3708099772977e-08, 0.2756168198616e+01, 0.3066615496545e+02, + 0.3599283541510e-08, 0.1934395469918e+01, 0.6147450479709e+01, + 0.3688702753059e-08, 0.7149920971109e+00, 0.2636725487657e+01, + 0.2681084724003e-08, 0.4899819493154e+01, 0.6816289982179e+01, + 0.3495993460759e-08, 0.1572418915115e+01, 0.6418701221183e+01, + 0.3130770324995e-08, 0.8912190180489e+00, 0.1235996607578e+02, + 0.2744353821941e-08, 0.3800821940055e+01, 0.2059724391010e+02, + 0.2842732906341e-08, 0.2644717440029e+01, 0.2828699048865e+02, + 0.3046882682154e-08, 0.3987793020179e+01, 0.6055599646783e+01, + + 0.2399072455143e-08, 0.9908826440764e+00, 0.6255674361143e+01, + 0.2384306274204e-08, 0.2516149752220e+01, 0.6310477339748e+01, + 0.2977324500559e-08, 0.5849195642118e+01, 0.1652265972112e+02, + 0.3062835258972e-08, 0.1681660100162e+01, 0.1172006883645e+02, + 0.3109682589231e-08, 0.5804143987737e+00, 0.2751146787858e+02, + 0.2903920355299e-08, 0.5800768280123e+01, 0.6510552054109e+01, + 0.2823221989212e-08, 0.9241118370216e+00, 0.5469525544182e+01, + 0.3187949696649e-08, 0.3139776445735e+01, 0.1693792562116e+03, + 0.2922559771655e-08, 0.3549440782984e+01, 0.2630839062450e+00, + 0.2436302066603e-08, 0.4735540696319e+01, 0.3946258593675e+00, + + 0.3049473043606e-08, 0.4998289124561e+01, 0.8390110365991e+01, + 0.2863682575784e-08, 0.6709515671102e+00, 0.2243449970715e+00, + 0.2641750517966e-08, 0.5410978257284e+01, 0.2986433403208e+02, + 0.2704093466243e-08, 0.4778317207821e+01, 0.6129297044991e+01, + 0.2445522177011e-08, 0.6009020662222e+01, 0.1171295538178e+02, + 0.2623608810230e-08, 0.5010449777147e+01, 0.6436854655901e+01, + 0.2079259704053e-08, 0.5980943768809e+01, 0.2019909489111e+02, + 0.2820225596771e-08, 0.2679965110468e+01, 0.5934151399930e+01, + 0.2365221950927e-08, 0.1894231148810e+01, 0.2470570524223e+02, + 0.2359682077149e-08, 0.4220752950780e+01, 0.8671969964381e+01, + + 0.2387577137206e-08, 0.2571783940617e+01, 0.7096626156709e+01, + 0.1982102089816e-08, 0.5169765997119e+00, 0.1727188400790e+02, + 0.2687502389925e-08, 0.6239078264579e+01, 0.7075506709219e+02, + 0.2207751669135e-08, 0.2031184412677e+01, 0.4377611041777e+01, + 0.2618370214274e-08, 0.8266079985979e+00, 0.6632000300961e+01, + 0.2591951887361e-08, 0.8819350522008e+00, 0.4873985990671e+02, + 0.2375055656248e-08, 0.3520944177789e+01, 0.1590676413561e+02, + 0.2472019978911e-08, 0.1551431908671e+01, 0.6612329252343e+00, + 0.2368157127199e-08, 0.4178610147412e+01, 0.3459636466239e+02, + 0.1764846605693e-08, 0.1506764000157e+01, 0.1980094587212e+02, + + 0.2291769608798e-08, 0.2118250611782e+01, 0.2844914056730e-01, + 0.2209997316943e-08, 0.3363255261678e+01, 0.2666070658668e+00, + 0.2292699097923e-08, 0.4200423956460e+00, 0.1484170571900e-02, + 0.1629683015329e-08, 0.2331362582487e+01, 0.3035599730800e+02, + 0.2206492862426e-08, 0.3400274026992e+01, 0.6281667977667e+01, + 0.2205746568257e-08, 0.1066051230724e+00, 0.6284483723224e+01, + 0.2026310767991e-08, 0.2779066487979e+01, 0.2449240616245e+02, + 0.1762977622163e-08, 0.9951450691840e+00, 0.2045286941806e+02, + 0.1368535049606e-08, 0.6402447365817e+00, 0.2473415438279e+02, + 0.1720598775450e-08, 0.2303524214705e+00, 0.1679593901136e+03, + + 0.1702429015449e-08, 0.6164622655048e+01, 0.3338575901272e+03, + 0.1414033197685e-08, 0.3954561185580e+01, 0.1624205518357e+03, + 0.1573768958043e-08, 0.2028286308984e+01, 0.3144167757552e+02, + 0.1650705184447e-08, 0.2304040666128e+01, 0.5267006960365e+02, + 0.1651087618855e-08, 0.2538461057280e+01, 0.8956999012000e+02, + 0.1616409518983e-08, 0.5111054348152e+01, 0.3332657872986e+02, + 0.1537175173581e-08, 0.5601130666603e+01, 0.3852657435933e+02, + 0.1593191980553e-08, 0.2614340453411e+01, 0.2282781046519e+03, + 0.1499480170643e-08, 0.3624721577264e+01, 0.2823723341956e+02, + 0.1493807843235e-08, 0.4214569879008e+01, 0.2876692439167e+02, + + 0.1074571199328e-08, 0.1496911744704e+00, 0.8397383534231e+02, + 0.1074406983417e-08, 0.1187817671922e+01, 0.8401985929482e+02, + 0.9757576855851e-09, 0.2655703035858e+01, 0.7826370942180e+02, + 0.1258432887565e-08, 0.4969896184844e+01, 0.3115650189215e+03, + 0.1240336343282e-08, 0.5192460776926e+01, 0.1784300471910e+03, + 0.9016107005164e-09, 0.1960356923057e+01, 0.5886454391678e+02, + 0.1135392360918e-08, 0.5082427809068e+01, 0.7842370451713e+02, + 0.9216046089565e-09, 0.2793775037273e+01, 0.1014262087719e+03, + 0.1061276615030e-08, 0.3726144311409e+01, 0.5660027930059e+02, + 0.1010110596263e-08, 0.7404080708937e+00, 0.4245678405627e+02, + + 0.7217424756199e-09, 0.2697449980577e-01, 0.2457074661053e+03, + 0.6912003846756e-09, 0.4253296276335e+01, 0.1679936946371e+03, + 0.6871814664847e-09, 0.5148072412354e+01, 0.6053048899753e+02, + 0.4887158016343e-09, 0.2153581148294e+01, 0.9656299901946e+02, + 0.5161802866314e-09, 0.3852750634351e+01, 0.2442876000072e+03, + 0.5652599559057e-09, 0.1233233356270e+01, 0.8365903305582e+02, + 0.4710812608586e-09, 0.5610486976767e+01, 0.3164282286739e+03, + 0.4909977500324e-09, 0.1639629524123e+01, 0.4059982187939e+03, + 0.4772641839378e-09, 0.3737100368583e+01, 0.1805255418145e+03, + 0.4487562567153e-09, 0.1158417054478e+00, 0.8433466158131e+02, + + 0.3943441230497e-09, 0.6243502862796e+00, 0.2568537517081e+03, + 0.3952236913598e-09, 0.3510377382385e+01, 0.2449975330562e+03, + 0.3788898363417e-09, 0.5916128302299e+01, 0.1568131045107e+03, + 0.3738329328831e-09, 0.1042266763456e+01, 0.3948519331910e+03, + 0.2451199165151e-09, 0.1166788435700e+01, 0.1435713242844e+03, + 0.2436734402904e-09, 0.3254726114901e+01, 0.2268582385539e+03, + 0.2213605274325e-09, 0.1687210598530e+01, 0.1658638954901e+03, + 0.1491521204829e-09, 0.2657541786794e+01, 0.2219950288015e+03, + 0.1474995329744e-09, 0.5013089805819e+01, 0.3052819430710e+03, + 0.1661939475656e-09, 0.5495315428418e+01, 0.2526661704812e+03, + + 0.9015946748003e-10, 0.2236989966505e+01, 0.4171445043968e+03 }; + +/* Sun-to-Earth, T^0, Z */ + static const double e0z[] = { + 0.2796207639075e-05, 0.3198701560209e+01, 0.8433466158131e+02, + 0.1016042198142e-05, 0.5422360395913e+01, 0.5507553240374e+01, + 0.8044305033647e-06, 0.3880222866652e+01, 0.5223693906222e+01, + 0.4385347909274e-06, 0.3704369937468e+01, 0.2352866153506e+01, + 0.3186156414906e-06, 0.3999639363235e+01, 0.1577343543434e+01, + 0.2272412285792e-06, 0.3984738315952e+01, 0.1047747311755e+01, + 0.1645620103007e-06, 0.3565412516841e+01, 0.5856477690889e+01, + 0.1815836921166e-06, 0.4984507059020e+01, 0.6283075850446e+01, + 0.1447461676364e-06, 0.3702753570108e+01, 0.9437762937313e+01, + 0.1430760876382e-06, 0.3409658712357e+01, 0.1021328554739e+02, + + 0.1120445753226e-06, 0.4829561570246e+01, 0.1414349524433e+02, + 0.1090232840797e-06, 0.2080729178066e+01, 0.6812766822558e+01, + 0.9715727346551e-07, 0.3476295881948e+01, 0.4694002934110e+01, + 0.1036267136217e-06, 0.4056639536648e+01, 0.7109288135493e+02, + 0.8752665271340e-07, 0.4448159519911e+01, 0.5753384878334e+01, + 0.8331864956004e-07, 0.4991704044208e+01, 0.7084896783808e+01, + 0.6901658670245e-07, 0.4325358994219e+01, 0.6275962395778e+01, + 0.9144536848998e-07, 0.1141826375363e+01, 0.6620890113188e+01, + 0.7205085037435e-07, 0.3624344170143e+01, 0.5296909721118e+00, + 0.7697874654176e-07, 0.5554257458998e+01, 0.1676215758509e+03, + + 0.5197545738384e-07, 0.6251760961735e+01, 0.1807370494127e+02, + 0.5031345378608e-07, 0.2497341091913e+01, 0.4705732307012e+01, + 0.4527110205840e-07, 0.2335079920992e+01, 0.6309374173736e+01, + 0.4753355798089e-07, 0.7094148987474e+00, 0.5884926831456e+01, + 0.4296951977516e-07, 0.1101916352091e+01, 0.6681224869435e+01, + 0.3855341568387e-07, 0.1825495405486e+01, 0.5486777812467e+01, + 0.5253930970990e-07, 0.4424740687208e+01, 0.7860419393880e+01, + 0.4024630496471e-07, 0.5120498157053e+01, 0.1336797263425e+02, + 0.4061069791453e-07, 0.6029771435451e+01, 0.3930209696940e+01, + 0.3797883804205e-07, 0.4435193600836e+00, 0.3154687086868e+01, + + 0.2933033225587e-07, 0.5124157356507e+01, 0.1059381944224e+01, + 0.3503000930426e-07, 0.5421830162065e+01, 0.6069776770667e+01, + 0.3670096214050e-07, 0.4582101667297e+01, 0.1219403291462e+02, + 0.2905609437008e-07, 0.1926566420072e+01, 0.1097707878456e+02, + 0.2466827821713e-07, 0.6090174539834e+00, 0.6496374930224e+01, + 0.2691647295332e-07, 0.1393432595077e+01, 0.2200391463820e+02, + 0.2150554667946e-07, 0.4308671715951e+01, 0.5643178611111e+01, + 0.2237481922680e-07, 0.8133968269414e+00, 0.8635942003952e+01, + 0.1817741038157e-07, 0.3755205127454e+01, 0.3340612434717e+01, + 0.2227820762132e-07, 0.2759558596664e+01, 0.1203646072878e+02, + + 0.1944713772307e-07, 0.5699645869121e+01, 0.1179062909082e+02, + 0.1527340520662e-07, 0.1986749091746e+01, 0.3981490189893e+00, + 0.1577282574914e-07, 0.3205017217983e+01, 0.5088628793478e+01, + 0.1424738825424e-07, 0.6256747903666e+01, 0.2544314396739e+01, + 0.1616563121701e-07, 0.2601671259394e+00, 0.1729818233119e+02, + 0.1401210391692e-07, 0.4686939173506e+01, 0.7058598460518e+01, + 0.1488726974214e-07, 0.2815862451372e+01, 0.2593412433514e+02, + 0.1692626442388e-07, 0.4956894109797e+01, 0.1564752902480e+03, + 0.1123571582910e-07, 0.2381192697696e+01, 0.3738761453707e+01, + 0.9903308606317e-08, 0.4294851657684e+01, 0.9225539266174e+01, + + 0.9174533187191e-08, 0.3075171510642e+01, 0.4164311961999e+01, + 0.8645985631457e-08, 0.5477534821633e+00, 0.8429241228195e+01, + -0.1085876492688e-07, 0.0000000000000e+00, 0.0000000000000e+00, + 0.9264309077815e-08, 0.5968571670097e+01, 0.7079373888424e+01, + 0.8243116984954e-08, 0.1489098777643e+01, 0.1044738781244e+02, + 0.8268102113708e-08, 0.3512977691983e+01, 0.1150676975667e+02, + 0.9043613988227e-08, 0.1290704408221e+00, 0.1101510648075e+02, + 0.7432912038789e-08, 0.1991086893337e+01, 0.2608790314060e+02, + 0.8586233727285e-08, 0.4238357924414e+01, 0.2986433403208e+02, + 0.7612230060131e-08, 0.2911090150166e+01, 0.4732030630302e+01, + + 0.7097787751408e-08, 0.1908938392390e+01, 0.8031092209206e+01, + 0.7640237040175e-08, 0.6129219000168e+00, 0.7962980379786e+00, + 0.7070445688081e-08, 0.1380417036651e+01, 0.2146165377750e+01, + 0.7690770957702e-08, 0.1680504249084e+01, 0.2122839202813e+02, + 0.8051292542594e-08, 0.5127423484511e+01, 0.2942463415728e+01, + 0.5902709104515e-08, 0.2020274190917e+01, 0.7755226100720e+00, + 0.5134567496462e-08, 0.2606778676418e+01, 0.1256615170089e+02, + 0.5525802046102e-08, 0.1613011769663e+01, 0.8018209333619e+00, + 0.5880724784221e-08, 0.4604483417236e+01, 0.4690479774488e+01, + 0.5211699081370e-08, 0.5718964114193e+01, 0.8827390247185e+01, + + 0.4891849573562e-08, 0.3689658932196e+01, 0.2132990797783e+00, + 0.5150246069997e-08, 0.4099769855122e+01, 0.6480980550449e+02, + 0.5102434319633e-08, 0.5660834602509e+01, 0.3379454372902e+02, + 0.5083405254252e-08, 0.9842221218974e+00, 0.4136910472696e+01, + 0.4206562585682e-08, 0.1341363634163e+00, 0.3128388763578e+01, + 0.4663249683579e-08, 0.8130132735866e+00, 0.5216580451554e+01, + 0.4099474416530e-08, 0.5791497770644e+01, 0.4265981595566e+00, + 0.4628251220767e-08, 0.1249802769331e+01, 0.1572083878776e+02, + 0.5024068728142e-08, 0.4795684802743e+01, 0.6290189305114e+01, + 0.5120234327758e-08, 0.3810420387208e+01, 0.5230807360890e+01, + + 0.5524029815280e-08, 0.1029264714351e+01, 0.2397622045175e+03, + 0.4757415718860e-08, 0.3528044781779e+01, 0.1649636139783e+02, + 0.3915786131127e-08, 0.5593889282646e+01, 0.1589072916335e+01, + 0.4869053149991e-08, 0.3299636454433e+01, 0.7632943190217e+01, + 0.3649365703729e-08, 0.1286049002584e+01, 0.6206810014183e+01, + 0.3992493949002e-08, 0.3100307589464e+01, 0.2515860172507e+02, + 0.3320247477418e-08, 0.6212683940807e+01, 0.1216800268190e+02, + 0.3287123739696e-08, 0.4699118445928e+01, 0.7234794171227e+01, + 0.3472776811103e-08, 0.2630507142004e+01, 0.7342457794669e+01, + 0.3423253294767e-08, 0.2946432844305e+01, 0.9623688285163e+01, + + 0.3896173898244e-08, 0.1224834179264e+01, 0.6438496133249e+01, + 0.3388455337924e-08, 0.1543807616351e+01, 0.1494531617769e+02, + 0.3062704716523e-08, 0.1191777572310e+01, 0.8662240327241e+01, + 0.3270075600400e-08, 0.5483498767737e+01, 0.1194447056968e+01, + 0.3101209215259e-08, 0.8000833804348e+00, 0.3772475342596e+02, + 0.2780883347311e-08, 0.4077980721888e+00, 0.5863591145557e+01, + 0.2903605931824e-08, 0.2617490302147e+01, 0.1965104848470e+02, + 0.2682014743119e-08, 0.2634703158290e+01, 0.7238675589263e+01, + 0.2534360108492e-08, 0.6102446114873e+01, 0.6836645152238e+01, + 0.2392564882509e-08, 0.3681820208691e+01, 0.5849364236221e+01, + + 0.2656667254856e-08, 0.6216045388886e+01, 0.6133512519065e+01, + 0.2331242096773e-08, 0.5864949777744e+01, 0.4535059491685e+01, + 0.2287898363668e-08, 0.4566628532802e+01, 0.7477522907414e+01, + 0.2336944521306e-08, 0.2442722126930e+01, 0.1137170464392e+02, + 0.3156632236269e-08, 0.1626628050682e+01, 0.2509084901204e+03, + 0.2982612402766e-08, 0.2803604512609e+01, 0.1748016358760e+01, + 0.2774031674807e-08, 0.4654002897158e+01, 0.8223916695780e+02, + 0.2295236548638e-08, 0.4326518333253e+01, 0.3378142627421e+00, + 0.2190714699873e-08, 0.4519614578328e+01, 0.2908881142201e+02, + 0.2191495845045e-08, 0.3012626912549e+01, 0.1673046366289e+02, + + 0.2492901628386e-08, 0.1290101424052e+00, 0.1543797956245e+03, + 0.1993778064319e-08, 0.3864046799414e+01, 0.1778984560711e+02, + 0.1898146479022e-08, 0.5053777235891e+01, 0.2042657109477e+02, + 0.1918280127634e-08, 0.2222470192548e+01, 0.4165496312290e+02, + 0.1916351061607e-08, 0.8719067257774e+00, 0.7737595720538e+02, + 0.1834720181466e-08, 0.4031491098040e+01, 0.2358125818164e+02, + 0.1249201523806e-08, 0.5938379466835e+01, 0.3301902111895e+02, + 0.1477304050539e-08, 0.6544722606797e+00, 0.9548094718417e+02, + 0.1264316431249e-08, 0.2059072853236e+01, 0.8399684731857e+02, + 0.1203526495039e-08, 0.3644813532605e+01, 0.4558517281984e+02, + + 0.9221681059831e-09, 0.3241815055602e+01, 0.7805158573086e+02, + 0.7849278367646e-09, 0.5043812342457e+01, 0.5217580628120e+02, + 0.7983392077387e-09, 0.5000024502753e+01, 0.1501922143975e+03, + 0.7925395431654e-09, 0.1398734871821e-01, 0.9061773743175e+02, + 0.7640473285886e-09, 0.5067111723130e+01, 0.4951538251678e+02, + 0.5398937754482e-09, 0.5597382200075e+01, 0.1613385000004e+03, + 0.5626247550193e-09, 0.2601338209422e+01, 0.7318837597844e+02, + 0.5525197197855e-09, 0.5814832109256e+01, 0.1432335100216e+03, + 0.5407629837898e-09, 0.3384820609076e+01, 0.3230491187871e+03, + 0.3856739119801e-09, 0.1072391840473e+01, 0.2334791286671e+03, + + 0.3856425239987e-09, 0.2369540393327e+01, 0.1739046517013e+03, + 0.4350867755983e-09, 0.5255575751082e+01, 0.1620484330494e+03, + 0.3844113924996e-09, 0.5482356246182e+01, 0.9757644180768e+02, + 0.2854869155431e-09, 0.9573634763143e+00, 0.1697170704744e+03, + 0.1719227671416e-09, 0.1887203025202e+01, 0.2265204242912e+03, + 0.1527846879755e-09, 0.3982183931157e+01, 0.3341954043900e+03, + 0.1128229264847e-09, 0.2787457156298e+01, 0.3119028331842e+03 }; + +/* Sun-to-Earth, T^1, X */ + static const double e1x[] = { + 0.1234046326004e-05, 0.0000000000000e+00, 0.0000000000000e+00, + 0.5150068824701e-06, 0.6002664557501e+01, 0.1256615170089e+02, + 0.1290743923245e-07, 0.5959437664199e+01, 0.1884922755134e+02, + 0.1068615564952e-07, 0.2015529654209e+01, 0.6283075850446e+01, + 0.2079619142538e-08, 0.1732960531432e+01, 0.6279552690824e+01, + 0.2078009243969e-08, 0.4915604476996e+01, 0.6286599010068e+01, + 0.6206330058856e-09, 0.3616457953824e+00, 0.4705732307012e+01, + 0.5989335313746e-09, 0.3802607304474e+01, 0.6256777527156e+01, + 0.5958495663840e-09, 0.2845866560031e+01, 0.6309374173736e+01, + 0.4866923261539e-09, 0.5213203771824e+01, 0.7755226100720e+00, + + 0.4267785823142e-09, 0.4368189727818e+00, 0.1059381944224e+01, + 0.4610675141648e-09, 0.1837249181372e-01, 0.7860419393880e+01, + 0.3626989993973e-09, 0.2161590545326e+01, 0.5753384878334e+01, + 0.3563071194389e-09, 0.1452631954746e+01, 0.5884926831456e+01, + 0.3557015642807e-09, 0.4470593393054e+01, 0.6812766822558e+01, + 0.3210412089122e-09, 0.5195926078314e+01, 0.6681224869435e+01, + 0.2875473577986e-09, 0.5916256610193e+01, 0.2513230340178e+02, + 0.2842913681629e-09, 0.1149902426047e+01, 0.6127655567643e+01, + 0.2751248215916e-09, 0.5502088574662e+01, 0.6438496133249e+01, + 0.2481432881127e-09, 0.2921989846637e+01, 0.5486777812467e+01, + + 0.2059885976560e-09, 0.3718070376585e+01, 0.7079373888424e+01, + 0.2015522342591e-09, 0.5979395259740e+01, 0.6290189305114e+01, + 0.1995364084253e-09, 0.6772087985494e+00, 0.6275962395778e+01, + 0.1957436436943e-09, 0.2899210654665e+01, 0.5507553240374e+01, + 0.1651609818948e-09, 0.6228206482192e+01, 0.1150676975667e+02, + 0.1822980550699e-09, 0.1469348746179e+01, 0.1179062909082e+02, + 0.1675223159760e-09, 0.3813910555688e+01, 0.7058598460518e+01, + 0.1706491764745e-09, 0.3004380506684e+00, 0.7113454667900e-02, + 0.1392952362615e-09, 0.1440393973406e+01, 0.7962980379786e+00, + 0.1209868266342e-09, 0.4150425791727e+01, 0.4694002934110e+01, + + 0.1009827202611e-09, 0.3290040429843e+01, 0.3738761453707e+01, + 0.1047261388602e-09, 0.4229590090227e+01, 0.6282095334605e+01, + 0.1047006652004e-09, 0.2418967680575e+01, 0.6284056366286e+01, + 0.9609993143095e-10, 0.4627943659201e+01, 0.6069776770667e+01, + 0.9590900593873e-10, 0.1894393939924e+01, 0.4136910472696e+01, + 0.9146249188071e-10, 0.2010647519562e+01, 0.6496374930224e+01, + 0.8545274480290e-10, 0.5529846956226e-01, 0.1194447056968e+01, + 0.8224377881194e-10, 0.1254304102174e+01, 0.1589072916335e+01, + 0.6183529510410e-10, 0.3360862168815e+01, 0.8827390247185e+01, + 0.6259255147141e-10, 0.4755628243179e+01, 0.8429241228195e+01, + + 0.5539291694151e-10, 0.5371746955142e+01, 0.4933208510675e+01, + 0.7328259466314e-10, 0.4927699613906e+00, 0.4535059491685e+01, + 0.6017835843560e-10, 0.5776682001734e-01, 0.1255903824622e+02, + 0.7079827775243e-10, 0.4395059432251e+01, 0.5088628793478e+01, + 0.5170358878213e-10, 0.5154062619954e+01, 0.1176985366291e+02, + 0.4872301838682e-10, 0.6289611648973e+00, 0.6040347114260e+01, + 0.5249869411058e-10, 0.5617272046949e+01, 0.3154687086868e+01, + 0.4716172354411e-10, 0.3965901800877e+01, 0.5331357529664e+01, + 0.4871214940964e-10, 0.4627507050093e+01, 0.1256967486051e+02, + 0.4598076850751e-10, 0.6023631226459e+01, 0.6525804586632e+01, + + 0.4562196089485e-10, 0.4138562084068e+01, 0.3930209696940e+01, + 0.4325493872224e-10, 0.1330845906564e+01, 0.7632943190217e+01, + 0.5673781176748e-10, 0.2558752615657e+01, 0.5729506548653e+01, + 0.3961436642503e-10, 0.2728071734630e+01, 0.7234794171227e+01, + 0.5101868209058e-10, 0.4113444965144e+01, 0.6836645152238e+01, + 0.5257043167676e-10, 0.6195089830590e+01, 0.8031092209206e+01, + 0.5076613989393e-10, 0.2305124132918e+01, 0.7477522907414e+01, + 0.3342169352778e-10, 0.5415998155071e+01, 0.1097707878456e+02, + 0.3545881983591e-10, 0.3727160564574e+01, 0.4164311961999e+01, + 0.3364063738599e-10, 0.2901121049204e+00, 0.1137170464392e+02, + + 0.3357039670776e-10, 0.1652229354331e+01, 0.5223693906222e+01, + 0.4307412268687e-10, 0.4938909587445e+01, 0.1592596075957e+01, + 0.3405769115435e-10, 0.2408890766511e+01, 0.3128388763578e+01, + 0.3001926198480e-10, 0.4862239006386e+01, 0.1748016358760e+01, + 0.2778264787325e-10, 0.5241168661353e+01, 0.7342457794669e+01, + 0.2676159480666e-10, 0.3423593942199e+01, 0.2146165377750e+01, + 0.2954273399939e-10, 0.1881721265406e+01, 0.5368044267797e+00, + 0.3309362888795e-10, 0.1931525677349e+01, 0.8018209333619e+00, + 0.2810283608438e-10, 0.2414659495050e+01, 0.5225775174439e+00, + 0.3378045637764e-10, 0.4238019163430e+01, 0.1554202828031e+00, + + 0.2558134979840e-10, 0.1828225235805e+01, 0.5230807360890e+01, + 0.2273755578447e-10, 0.5858184283998e+01, 0.7084896783808e+01, + 0.2294176037690e-10, 0.4514589779057e+01, 0.1726015463500e+02, + 0.2533506099435e-10, 0.2355717851551e+01, 0.5216580451554e+01, + 0.2716685375812e-10, 0.2221003625100e+01, 0.8635942003952e+01, + 0.2419043435198e-10, 0.5955704951635e+01, 0.4690479774488e+01, + 0.2521232544812e-10, 0.1395676848521e+01, 0.5481254917084e+01, + 0.2630195021491e-10, 0.5727468918743e+01, 0.2629832328990e-01, + 0.2548395840944e-10, 0.2628351859400e-03, 0.1349867339771e+01 }; + +/* Sun-to-Earth, T^1, Y */ + static const double e1y[] = { + 0.9304690546528e-06, 0.0000000000000e+00, 0.0000000000000e+00, + 0.5150715570663e-06, 0.4431807116294e+01, 0.1256615170089e+02, + 0.1290825411056e-07, 0.4388610039678e+01, 0.1884922755134e+02, + 0.4645466665386e-08, 0.5827263376034e+01, 0.6283075850446e+01, + 0.2079625310718e-08, 0.1621698662282e+00, 0.6279552690824e+01, + 0.2078189850907e-08, 0.3344713435140e+01, 0.6286599010068e+01, + 0.6207190138027e-09, 0.5074049319576e+01, 0.4705732307012e+01, + 0.5989826532569e-09, 0.2231842216620e+01, 0.6256777527156e+01, + 0.5961360812618e-09, 0.1274975769045e+01, 0.6309374173736e+01, + 0.4874165471016e-09, 0.3642277426779e+01, 0.7755226100720e+00, + + 0.4283834034360e-09, 0.5148765510106e+01, 0.1059381944224e+01, + 0.4652389287529e-09, 0.4715794792175e+01, 0.7860419393880e+01, + 0.3751707476401e-09, 0.6617207370325e+00, 0.5753384878334e+01, + 0.3559998806198e-09, 0.6155548875404e+01, 0.5884926831456e+01, + 0.3558447558857e-09, 0.2898827297664e+01, 0.6812766822558e+01, + 0.3211116927106e-09, 0.3625813502509e+01, 0.6681224869435e+01, + 0.2875609914672e-09, 0.4345435813134e+01, 0.2513230340178e+02, + 0.2843109704069e-09, 0.5862263940038e+01, 0.6127655567643e+01, + 0.2744676468427e-09, 0.3926419475089e+01, 0.6438496133249e+01, + 0.2481285237789e-09, 0.1351976572828e+01, 0.5486777812467e+01, + + 0.2060338481033e-09, 0.2147556998591e+01, 0.7079373888424e+01, + 0.2015822358331e-09, 0.4408358972216e+01, 0.6290189305114e+01, + 0.2001195944195e-09, 0.5385829822531e+01, 0.6275962395778e+01, + 0.1953667642377e-09, 0.1304933746120e+01, 0.5507553240374e+01, + 0.1839744078713e-09, 0.6173567228835e+01, 0.1179062909082e+02, + 0.1643334294845e-09, 0.4635942997523e+01, 0.1150676975667e+02, + 0.1768051018652e-09, 0.5086283558874e+01, 0.7113454667900e-02, + 0.1674874205489e-09, 0.2243332137241e+01, 0.7058598460518e+01, + 0.1421445397609e-09, 0.6186899771515e+01, 0.7962980379786e+00, + 0.1255163958267e-09, 0.5730238465658e+01, 0.4694002934110e+01, + + 0.1013945281961e-09, 0.1726055228402e+01, 0.3738761453707e+01, + 0.1047294335852e-09, 0.2658801228129e+01, 0.6282095334605e+01, + 0.1047103879392e-09, 0.8481047835035e+00, 0.6284056366286e+01, + 0.9530343962826e-10, 0.3079267149859e+01, 0.6069776770667e+01, + 0.9604637611690e-10, 0.3258679792918e+00, 0.4136910472696e+01, + 0.9153518537177e-10, 0.4398599886584e+00, 0.6496374930224e+01, + 0.8562458214922e-10, 0.4772686794145e+01, 0.1194447056968e+01, + 0.8232525360654e-10, 0.5966220721679e+01, 0.1589072916335e+01, + 0.6150223411438e-10, 0.1780985591923e+01, 0.8827390247185e+01, + 0.6272087858000e-10, 0.3184305429012e+01, 0.8429241228195e+01, + + 0.5540476311040e-10, 0.3801260595433e+01, 0.4933208510675e+01, + 0.7331901699361e-10, 0.5205948591865e+01, 0.4535059491685e+01, + 0.6018528702791e-10, 0.4770139083623e+01, 0.1255903824622e+02, + 0.5150530724804e-10, 0.3574796899585e+01, 0.1176985366291e+02, + 0.6471933741811e-10, 0.2679787266521e+01, 0.5088628793478e+01, + 0.5317460644174e-10, 0.9528763345494e+00, 0.3154687086868e+01, + 0.4832187748783e-10, 0.5329322498232e+01, 0.6040347114260e+01, + 0.4716763555110e-10, 0.2395235316466e+01, 0.5331357529664e+01, + 0.4871509139861e-10, 0.3056663648823e+01, 0.1256967486051e+02, + 0.4598417696768e-10, 0.4452762609019e+01, 0.6525804586632e+01, + + 0.5674189533175e-10, 0.9879680872193e+00, 0.5729506548653e+01, + 0.4073560328195e-10, 0.5939127696986e+01, 0.7632943190217e+01, + 0.5040994945359e-10, 0.4549875824510e+01, 0.8031092209206e+01, + 0.5078185134679e-10, 0.7346659893982e+00, 0.7477522907414e+01, + 0.3769343537061e-10, 0.1071317188367e+01, 0.7234794171227e+01, + 0.4980331365299e-10, 0.2500345341784e+01, 0.6836645152238e+01, + 0.3458236594757e-10, 0.3825159450711e+01, 0.1097707878456e+02, + 0.3578859493602e-10, 0.5299664791549e+01, 0.4164311961999e+01, + 0.3370504646419e-10, 0.5002316301593e+01, 0.1137170464392e+02, + 0.3299873338428e-10, 0.2526123275282e+01, 0.3930209696940e+01, + + 0.4304917318409e-10, 0.3368078557132e+01, 0.1592596075957e+01, + 0.3402418753455e-10, 0.8385495425800e+00, 0.3128388763578e+01, + 0.2778460572146e-10, 0.3669905203240e+01, 0.7342457794669e+01, + 0.2782710128902e-10, 0.2691664812170e+00, 0.1748016358760e+01, + 0.2711725179646e-10, 0.4707487217718e+01, 0.5296909721118e+00, + 0.2981760946340e-10, 0.3190260867816e+00, 0.5368044267797e+00, + 0.2811672977772e-10, 0.3196532315372e+01, 0.7084896783808e+01, + 0.2863454474467e-10, 0.2263240324780e+00, 0.5223693906222e+01, + 0.3333464634051e-10, 0.3498451685065e+01, 0.8018209333619e+00, + 0.3312991747609e-10, 0.5839154477412e+01, 0.1554202828031e+00, + + 0.2813255564006e-10, 0.8268044346621e+00, 0.5225775174439e+00, + 0.2665098083966e-10, 0.3934021725360e+01, 0.5216580451554e+01, + 0.2349795705216e-10, 0.5197620913779e+01, 0.2146165377750e+01, + 0.2330352293961e-10, 0.2984999231807e+01, 0.1726015463500e+02, + 0.2728001683419e-10, 0.6521679638544e+00, 0.8635942003952e+01, + 0.2484061007669e-10, 0.3468955561097e+01, 0.5230807360890e+01, + 0.2646328768427e-10, 0.1013724533516e+01, 0.2629832328990e-01, + 0.2518630264831e-10, 0.6108081057122e+01, 0.5481254917084e+01, + 0.2421901455384e-10, 0.1651097776260e+01, 0.1349867339771e+01, + 0.6348533267831e-11, 0.3220226560321e+01, 0.8433466158131e+02 }; + +/* Sun-to-Earth, T^1, Z */ + static const double e1z[] = { + 0.2278290449966e-05, 0.3413716033863e+01, 0.6283075850446e+01, + 0.5429458209830e-07, 0.0000000000000e+00, 0.0000000000000e+00, + 0.1903240492525e-07, 0.3370592358297e+01, 0.1256615170089e+02, + 0.2385409276743e-09, 0.3327914718416e+01, 0.1884922755134e+02, + 0.8676928342573e-10, 0.1824006811264e+01, 0.5223693906222e+01, + 0.7765442593544e-10, 0.3888564279247e+01, 0.5507553240374e+01, + 0.7066158332715e-10, 0.5194267231944e+01, 0.2352866153506e+01, + 0.7092175288657e-10, 0.2333246960021e+01, 0.8399684731857e+02, + 0.5357582213535e-10, 0.2224031176619e+01, 0.5296909721118e+00, + 0.3828035865021e-10, 0.2156710933584e+01, 0.6279552690824e+01, + + 0.3824857220427e-10, 0.1529755219915e+01, 0.6286599010068e+01, + 0.3286995181628e-10, 0.4879512900483e+01, 0.1021328554739e+02 }; + +/* Sun-to-Earth, T^2, X */ + static const double e2x[] = { + -0.4143818297913e-10, 0.0000000000000e+00, 0.0000000000000e+00, + 0.2171497694435e-10, 0.4398225628264e+01, 0.1256615170089e+02, + 0.9845398442516e-11, 0.2079720838384e+00, 0.6283075850446e+01, + 0.9256833552682e-12, 0.4191264694361e+01, 0.1884922755134e+02, + 0.1022049384115e-12, 0.5381133195658e+01, 0.8399684731857e+02 }; + +/* Sun-to-Earth, T^2, Y */ + static const double e2y[] = { + 0.5063375872532e-10, 0.0000000000000e+00, 0.0000000000000e+00, + 0.2173815785980e-10, 0.2827805833053e+01, 0.1256615170089e+02, + 0.1010231999920e-10, 0.4634612377133e+01, 0.6283075850446e+01, + 0.9259745317636e-12, 0.2620612076189e+01, 0.1884922755134e+02, + 0.1022202095812e-12, 0.3809562326066e+01, 0.8399684731857e+02 }; + +/* Sun-to-Earth, T^2, Z */ + static const double e2z[] = { + 0.9722666114891e-10, 0.5152219582658e+01, 0.6283075850446e+01, + -0.3494819171909e-11, 0.0000000000000e+00, 0.0000000000000e+00, + 0.6713034376076e-12, 0.6440188750495e+00, 0.1256615170089e+02 }; + +/* SSB-to-Sun, T^0, X */ + static const double s0x[] = { + 0.4956757536410e-02, 0.3741073751789e+01, 0.5296909721118e+00, + 0.2718490072522e-02, 0.4016011511425e+01, 0.2132990797783e+00, + 0.1546493974344e-02, 0.2170528330642e+01, 0.3813291813120e-01, + 0.8366855276341e-03, 0.2339614075294e+01, 0.7478166569050e-01, + 0.2936777942117e-03, 0.0000000000000e+00, 0.0000000000000e+00, + 0.1201317439469e-03, 0.4090736353305e+01, 0.1059381944224e+01, + 0.7578550887230e-04, 0.3241518088140e+01, 0.4265981595566e+00, + 0.1941787367773e-04, 0.1012202064330e+01, 0.2061856251104e+00, + 0.1889227765991e-04, 0.3892520416440e+01, 0.2204125344462e+00, + 0.1937896968613e-04, 0.4797779441161e+01, 0.1495633313810e+00, + + 0.1434506110873e-04, 0.3868960697933e+01, 0.5225775174439e+00, + 0.1406659911580e-04, 0.4759766557397e+00, 0.5368044267797e+00, + 0.1179022300202e-04, 0.7774961520598e+00, 0.7626583626240e-01, + 0.8085864460959e-05, 0.3254654471465e+01, 0.3664874755930e-01, + 0.7622752967615e-05, 0.4227633103489e+01, 0.3961708870310e-01, + 0.6209171139066e-05, 0.2791828325711e+00, 0.7329749511860e-01, + 0.4366435633970e-05, 0.4440454875925e+01, 0.1589072916335e+01, + 0.3792124889348e-05, 0.5156393842356e+01, 0.7113454667900e-02, + 0.3154548963402e-05, 0.6157005730093e+01, 0.4194847048887e+00, + 0.3088359882942e-05, 0.2494567553163e+01, 0.6398972393349e+00, + + 0.2788440902136e-05, 0.4934318747989e+01, 0.1102062672231e+00, + 0.3039928456376e-05, 0.4895077702640e+01, 0.6283075850446e+01, + 0.2272258457679e-05, 0.5278394064764e+01, 0.1030928125552e+00, + 0.2162007057957e-05, 0.5802978019099e+01, 0.3163918923335e+00, + 0.1767632855737e-05, 0.3415346595193e-01, 0.1021328554739e+02, + 0.1349413459362e-05, 0.2001643230755e+01, 0.1484170571900e-02, + 0.1170141900476e-05, 0.2424750491620e+01, 0.6327837846670e+00, + 0.1054355266820e-05, 0.3123311487576e+01, 0.4337116142245e+00, + 0.9800822461610e-06, 0.3026258088130e+01, 0.1052268489556e+01, + 0.1091203749931e-05, 0.3157811670347e+01, 0.1162474756779e+01, + + 0.6960236715913e-06, 0.8219570542313e+00, 0.1066495398892e+01, + 0.5689257296909e-06, 0.1323052375236e+01, 0.9491756770005e+00, + 0.6613172135802e-06, 0.2765348881598e+00, 0.8460828644453e+00, + 0.6277702517571e-06, 0.5794064466382e+01, 0.1480791608091e+00, + 0.6304884066699e-06, 0.7323555380787e+00, 0.2243449970715e+00, + 0.4897850467382e-06, 0.3062464235399e+01, 0.3340612434717e+01, + 0.3759148598786e-06, 0.4588290469664e+01, 0.3516457698740e-01, + 0.3110520548195e-06, 0.1374299536572e+01, 0.6373574839730e-01, + 0.3064708359780e-06, 0.4222267485047e+01, 0.1104591729320e-01, + 0.2856347168241e-06, 0.3714202944973e+01, 0.1510475019529e+00, + + 0.2840945514288e-06, 0.2847972875882e+01, 0.4110125927500e-01, + 0.2378951599405e-06, 0.3762072563388e+01, 0.2275259891141e+00, + 0.2714229481417e-06, 0.1036049980031e+01, 0.2535050500000e-01, + 0.2323551717307e-06, 0.4682388599076e+00, 0.8582758298370e-01, + 0.1881790512219e-06, 0.4790565425418e+01, 0.2118763888447e+01, + 0.2261353968371e-06, 0.1669144912212e+01, 0.7181332454670e-01, + 0.2214546389848e-06, 0.3937717281614e+01, 0.2968341143800e-02, + 0.2184915594933e-06, 0.1129169845099e+00, 0.7775000683430e-01, + 0.2000164937936e-06, 0.4030009638488e+01, 0.2093666171530e+00, + 0.1966105136719e-06, 0.8745955786834e+00, 0.2172315424036e+00, + + 0.1904742332624e-06, 0.5919743598964e+01, 0.2022531624851e+00, + 0.1657399705031e-06, 0.2549141484884e+01, 0.7358765972222e+00, + 0.1574070533987e-06, 0.5277533020230e+01, 0.7429900518901e+00, + 0.1832261651039e-06, 0.3064688127777e+01, 0.3235053470014e+00, + 0.1733615346569e-06, 0.3011432799094e+01, 0.1385174140878e+00, + 0.1549124014496e-06, 0.4005569132359e+01, 0.5154640627760e+00, + 0.1637044713838e-06, 0.1831375966632e+01, 0.8531963191132e+00, + 0.1123420082383e-06, 0.1180270407578e+01, 0.1990721704425e+00, + 0.1083754165740e-06, 0.3414101320863e+00, 0.5439178814476e+00, + 0.1156638012655e-06, 0.6130479452594e+00, 0.5257585094865e+00, + + 0.1142548785134e-06, 0.3724761948846e+01, 0.5336234347371e+00, + 0.7921463895965e-07, 0.2435425589361e+01, 0.1478866649112e+01, + 0.7428600285231e-07, 0.3542144398753e+01, 0.2164800718209e+00, + 0.8323211246747e-07, 0.3525058072354e+01, 0.1692165728891e+01, + 0.7257595116312e-07, 0.1364299431982e+01, 0.2101180877357e+00, + 0.7111185833236e-07, 0.2460478875808e+01, 0.4155522422634e+00, + 0.6868090383716e-07, 0.4397327670704e+01, 0.1173197218910e+00, + 0.7226419974175e-07, 0.4042647308905e+01, 0.1265567569334e+01, + 0.6955642383177e-07, 0.2865047906085e+01, 0.9562891316684e+00, + 0.7492139296331e-07, 0.5014278994215e+01, 0.1422690933580e-01, + + 0.6598363128857e-07, 0.2376730020492e+01, 0.6470106940028e+00, + 0.7381147293385e-07, 0.3272990384244e+01, 0.1581959461667e+01, + 0.6402909624032e-07, 0.5302290955138e+01, 0.9597935788730e-01, + 0.6237454263857e-07, 0.5444144425332e+01, 0.7084920306520e-01, + 0.5241198544016e-07, 0.4215359579205e+01, 0.5265099800692e+00, + 0.5144463853918e-07, 0.1218916689916e+00, 0.5328719641544e+00, + 0.5868164772299e-07, 0.2369402002213e+01, 0.7871412831580e-01, + 0.6233195669151e-07, 0.1254922242403e+01, 0.2608790314060e+02, + 0.6068463791422e-07, 0.5679713760431e+01, 0.1114304132498e+00, + 0.4359361135065e-07, 0.6097219641646e+00, 0.1375773836557e+01, + + 0.4686510366826e-07, 0.4786231041431e+01, 0.1143987543936e+00, + 0.3758977287225e-07, 0.1167368068139e+01, 0.1596186371003e+01, + 0.4282051974778e-07, 0.1519471064319e+01, 0.2770348281756e+00, + 0.5153765386113e-07, 0.1860532322984e+01, 0.2228608264996e+00, + 0.4575129387188e-07, 0.7632857887158e+00, 0.1465949902372e+00, + 0.3326844933286e-07, 0.1298219485285e+01, 0.5070101000000e-01, + 0.3748617450984e-07, 0.1046510321062e+01, 0.4903339079539e+00, + 0.2816756661499e-07, 0.3434522346190e+01, 0.2991266627620e+00, + 0.3412750405039e-07, 0.2523766270318e+01, 0.3518164938661e+00, + 0.2655796761776e-07, 0.2904422260194e+01, 0.6256703299991e+00, + + 0.2963597929458e-07, 0.5923900431149e+00, 0.1099462426779e+00, + 0.2539523734781e-07, 0.4851947722567e+01, 0.1256615170089e+02, + 0.2283087914139e-07, 0.3400498595496e+01, 0.6681224869435e+01, + 0.2321309799331e-07, 0.5789099148673e+01, 0.3368040641550e-01, + 0.2549657649750e-07, 0.3991856479792e-01, 0.1169588211447e+01, + 0.2290462303977e-07, 0.2788567577052e+01, 0.1045155034888e+01, + 0.1945398522914e-07, 0.3290896998176e+01, 0.1155361302111e+01, + 0.1849171512638e-07, 0.2698060129367e+01, 0.4452511715700e-02, + 0.1647199834254e-07, 0.3016735644085e+01, 0.4408250688924e+00, + 0.1529530765273e-07, 0.5573043116178e+01, 0.6521991896920e-01, + + 0.1433199339978e-07, 0.1481192356147e+01, 0.9420622223326e+00, + 0.1729134193602e-07, 0.1422817538933e+01, 0.2108507877249e+00, + 0.1716463931346e-07, 0.3469468901855e+01, 0.2157473718317e+00, + 0.1391206061378e-07, 0.6122436220547e+01, 0.4123712502208e+00, + 0.1404746661924e-07, 0.1647765641936e+01, 0.4258542984690e-01, + 0.1410452399455e-07, 0.5989729161964e+01, 0.2258291676434e+00, + 0.1089828772168e-07, 0.2833705509371e+01, 0.4226656969313e+00, + 0.1047374564948e-07, 0.5090690007331e+00, 0.3092784376656e+00, + 0.1358279126532e-07, 0.5128990262836e+01, 0.7923417740620e-01, + 0.1020456476148e-07, 0.9632772880808e+00, 0.1456308687557e+00, + + 0.1033428735328e-07, 0.3223779318418e+01, 0.1795258541446e+01, + 0.1412435841540e-07, 0.2410271572721e+01, 0.1525316725248e+00, + 0.9722759371574e-08, 0.2333531395690e+01, 0.8434341241180e-01, + 0.9657334084704e-08, 0.6199270974168e+01, 0.1272681024002e+01, + 0.1083641148690e-07, 0.2864222292929e+01, 0.7032915397480e-01, + 0.1067318403838e-07, 0.5833458866568e+00, 0.2123349582968e+00, + 0.1062366201976e-07, 0.4307753989494e+01, 0.2142632012598e+00, + 0.1236364149266e-07, 0.2873917870593e+01, 0.1847279083684e+00, + 0.1092759489593e-07, 0.2959887266733e+01, 0.1370332435159e+00, + 0.8912069362899e-08, 0.5141213702562e+01, 0.2648454860559e+01, + + 0.9656467707970e-08, 0.4532182462323e+01, 0.4376440768498e+00, + 0.8098386150135e-08, 0.2268906338379e+01, 0.2880807454688e+00, + 0.7857714675000e-08, 0.4055544260745e+01, 0.2037373330570e+00, + 0.7288455940646e-08, 0.5357901655142e+01, 0.1129145838217e+00, + 0.9450595950552e-08, 0.4264926963939e+01, 0.5272426800584e+00, + 0.9381718247537e-08, 0.7489366976576e-01, 0.5321392641652e+00, + 0.7079052646038e-08, 0.1923311052874e+01, 0.6288513220417e+00, + 0.9259004415344e-08, 0.2970256853438e+01, 0.1606092486742e+00, + 0.8259801499742e-08, 0.3327056314697e+01, 0.8389694097774e+00, + 0.6476334355779e-08, 0.2954925505727e+01, 0.2008557621224e+01, + + 0.5984021492007e-08, 0.9138753105829e+00, 0.2042657109477e+02, + 0.5989546863181e-08, 0.3244464082031e+01, 0.2111650433779e+01, + 0.6233108606023e-08, 0.4995232638403e+00, 0.4305306221819e+00, + 0.6877299149965e-08, 0.2834987233449e+01, 0.9561746721300e-02, + 0.8311234227190e-08, 0.2202951835758e+01, 0.3801276407308e+00, + 0.6599472832414e-08, 0.4478581462618e+01, 0.1063314406849e+01, + 0.6160491096549e-08, 0.5145858696411e+01, 0.1368660381889e+01, + 0.6164772043891e-08, 0.3762976697911e+00, 0.4234171675140e+00, + 0.6363248684450e-08, 0.3162246718685e+01, 0.1253008786510e-01, + 0.6448587520999e-08, 0.3442693302119e+01, 0.5287268506303e+00, + + 0.6431662283977e-08, 0.8977549136606e+00, 0.5306550935933e+00, + 0.6351223158474e-08, 0.4306447410369e+01, 0.5217580628120e+02, + 0.5476721393451e-08, 0.3888529177855e+01, 0.2221856701002e+01, + 0.5341772572619e-08, 0.2655560662512e+01, 0.7466759693650e-01, + 0.5337055758302e-08, 0.5164990735946e+01, 0.7489573444450e-01, + 0.5373120816787e-08, 0.6041214553456e+01, 0.1274714967946e+00, + 0.5392351705426e-08, 0.9177763485932e+00, 0.1055449481598e+01, + 0.6688495850205e-08, 0.3089608126937e+01, 0.2213766559277e+00, + 0.5072003660362e-08, 0.4311316541553e+01, 0.2132517061319e+00, + 0.5070726650455e-08, 0.5790675464444e+00, 0.2133464534247e+00, + + 0.5658012950032e-08, 0.2703945510675e+01, 0.7287631425543e+00, + 0.4835509924854e-08, 0.2975422976065e+01, 0.7160067364790e-01, + 0.6479821978012e-08, 0.1324168733114e+01, 0.2209183458640e-01, + 0.6230636494980e-08, 0.2860103632836e+01, 0.3306188016693e+00, + 0.4649239516213e-08, 0.4832259763403e+01, 0.7796265773310e-01, + 0.6487325792700e-08, 0.2726165825042e+01, 0.3884652414254e+00, + 0.4682823682770e-08, 0.6966602455408e+00, 0.1073608853559e+01, + 0.5704230804976e-08, 0.5669634104606e+01, 0.8731175355560e-01, + 0.6125413585489e-08, 0.1513386538915e+01, 0.7605151500000e-01, + 0.6035825038187e-08, 0.1983509168227e+01, 0.9846002785331e+00, + + 0.4331123462303e-08, 0.2782892992807e+01, 0.4297791515992e+00, + 0.4681107685143e-08, 0.5337232886836e+01, 0.2127790306879e+00, + 0.4669105829655e-08, 0.5837133792160e+01, 0.2138191288687e+00, + 0.5138823602365e-08, 0.3080560200507e+01, 0.7233337363710e-01, + 0.4615856664534e-08, 0.1661747897471e+01, 0.8603097737811e+00, + 0.4496916702197e-08, 0.2112508027068e+01, 0.7381754420900e-01, + 0.4278479042945e-08, 0.5716528462627e+01, 0.7574578717200e-01, + 0.3840525503932e-08, 0.6424172726492e+00, 0.3407705765729e+00, + 0.4866636509685e-08, 0.4919244697715e+01, 0.7722995774390e-01, + 0.3526100639296e-08, 0.2550821052734e+01, 0.6225157782540e-01, + + 0.3939558488075e-08, 0.3939331491710e+01, 0.5268983110410e-01, + 0.4041268772576e-08, 0.2275337571218e+01, 0.3503323232942e+00, + 0.3948761842853e-08, 0.1999324200790e+01, 0.1451108196653e+00, + 0.3258394550029e-08, 0.9121001378200e+00, 0.5296435984654e+00, + 0.3257897048761e-08, 0.3428428660869e+01, 0.5297383457582e+00, + 0.3842559031298e-08, 0.6132927720035e+01, 0.9098186128426e+00, + 0.3109920095448e-08, 0.7693650193003e+00, 0.3932462625300e-02, + 0.3132237775119e-08, 0.3621293854908e+01, 0.2346394437820e+00, + 0.3942189421510e-08, 0.4841863659733e+01, 0.3180992042600e-02, + 0.3796972285340e-08, 0.1814174994268e+01, 0.1862120789403e+00, + + 0.3995640233688e-08, 0.1386990406091e+01, 0.4549093064213e+00, + 0.2875013727414e-08, 0.9178318587177e+00, 0.1905464808669e+01, + 0.3073719932844e-08, 0.2688923811835e+01, 0.3628624111593e+00, + 0.2731016580075e-08, 0.1188259127584e+01, 0.2131850110243e+00, + 0.2729549896546e-08, 0.3702160634273e+01, 0.2134131485323e+00, + 0.3339372892449e-08, 0.7199163960331e+00, 0.2007689919132e+00, + 0.2898833764204e-08, 0.1916709364999e+01, 0.5291709230214e+00, + 0.2894536549362e-08, 0.2424043195547e+01, 0.5302110212022e+00, + 0.3096872473843e-08, 0.4445894977497e+01, 0.2976424921901e+00, + 0.2635672326810e-08, 0.3814366984117e+01, 0.1485980103780e+01, + + 0.3649302697001e-08, 0.2924200596084e+01, 0.6044726378023e+00, + 0.3127954585895e-08, 0.1842251648327e+01, 0.1084620721060e+00, + 0.2616040173947e-08, 0.4155841921984e+01, 0.1258454114666e+01, + 0.2597395859860e-08, 0.1158045978874e+00, 0.2103781122809e+00, + 0.2593286172210e-08, 0.4771850408691e+01, 0.2162200472757e+00, + 0.2481823585747e-08, 0.4608842558889e+00, 0.1062562936266e+01, + 0.2742219550725e-08, 0.1538781127028e+01, 0.5651155736444e+00, + 0.3199558469610e-08, 0.3226647822878e+00, 0.7036329877322e+00, + 0.2666088542957e-08, 0.1967991731219e+00, 0.1400015846597e+00, + 0.2397067430580e-08, 0.3707036669873e+01, 0.2125476091956e+00, + + 0.2376570772738e-08, 0.1182086628042e+01, 0.2140505503610e+00, + 0.2547228007887e-08, 0.4906256820629e+01, 0.1534957940063e+00, + 0.2265575594114e-08, 0.3414949866857e+01, 0.2235935264888e+00, + 0.2464381430585e-08, 0.4599122275378e+01, 0.2091065926078e+00, + 0.2433408527044e-08, 0.2830751145445e+00, 0.2174915669488e+00, + 0.2443605509076e-08, 0.4212046432538e+01, 0.1739420156204e+00, + 0.2319779262465e-08, 0.9881978408630e+00, 0.7530171478090e-01, + 0.2284622835465e-08, 0.5565347331588e+00, 0.7426161660010e-01, + 0.2467268750783e-08, 0.5655708150766e+00, 0.2526561439362e+00, + 0.2808513492782e-08, 0.1418405053408e+01, 0.5636314030725e+00, + + 0.2329528932532e-08, 0.4069557545675e+01, 0.1056200952181e+01, + 0.9698639532817e-09, 0.1074134313634e+01, 0.7826370942180e+02 }; + +/* SSB-to-Sun, T^0, Y */ + static const double s0y[] = { + 0.4955392320126e-02, 0.2170467313679e+01, 0.5296909721118e+00, + 0.2722325167392e-02, 0.2444433682196e+01, 0.2132990797783e+00, + 0.1546579925346e-02, 0.5992779281546e+00, 0.3813291813120e-01, + 0.8363140252966e-03, 0.7687356310801e+00, 0.7478166569050e-01, + 0.3385792683603e-03, 0.0000000000000e+00, 0.0000000000000e+00, + 0.1201192221613e-03, 0.2520035601514e+01, 0.1059381944224e+01, + 0.7587125720554e-04, 0.1669954006449e+01, 0.4265981595566e+00, + 0.1964155361250e-04, 0.5707743963343e+01, 0.2061856251104e+00, + 0.1891900364909e-04, 0.2320960679937e+01, 0.2204125344462e+00, + 0.1937373433356e-04, 0.3226940689555e+01, 0.1495633313810e+00, + + 0.1437139941351e-04, 0.2301626908096e+01, 0.5225775174439e+00, + 0.1406267683099e-04, 0.5188579265542e+01, 0.5368044267797e+00, + 0.1178703080346e-04, 0.5489483248476e+01, 0.7626583626240e-01, + 0.8079835186041e-05, 0.1683751835264e+01, 0.3664874755930e-01, + 0.7623253594652e-05, 0.2656400462961e+01, 0.3961708870310e-01, + 0.6248667483971e-05, 0.4992775362055e+01, 0.7329749511860e-01, + 0.4366353695038e-05, 0.2869706279678e+01, 0.1589072916335e+01, + 0.3829101568895e-05, 0.3572131359950e+01, 0.7113454667900e-02, + 0.3175733773908e-05, 0.4535372530045e+01, 0.4194847048887e+00, + 0.3092437902159e-05, 0.9230153317909e+00, 0.6398972393349e+00, + + 0.2874168812154e-05, 0.3363143761101e+01, 0.1102062672231e+00, + 0.3040119321826e-05, 0.3324250895675e+01, 0.6283075850446e+01, + 0.2699723308006e-05, 0.2917882441928e+00, 0.1030928125552e+00, + 0.2134832683534e-05, 0.4220997202487e+01, 0.3163918923335e+00, + 0.1770412139433e-05, 0.4747318496462e+01, 0.1021328554739e+02, + 0.1377264209373e-05, 0.4305058462401e+00, 0.1484170571900e-02, + 0.1127814538960e-05, 0.8538177240740e+00, 0.6327837846670e+00, + 0.1055608090130e-05, 0.1551800742580e+01, 0.4337116142245e+00, + 0.9802673861420e-06, 0.1459646735377e+01, 0.1052268489556e+01, + 0.1090329461951e-05, 0.1587351228711e+01, 0.1162474756779e+01, + + 0.6959590025090e-06, 0.5534442628766e+01, 0.1066495398892e+01, + 0.5664914529542e-06, 0.6030673003297e+01, 0.9491756770005e+00, + 0.6607787763599e-06, 0.4989507233927e+01, 0.8460828644453e+00, + 0.6269725742838e-06, 0.4222951804572e+01, 0.1480791608091e+00, + 0.6301889697863e-06, 0.5444316669126e+01, 0.2243449970715e+00, + 0.4891042662861e-06, 0.1490552839784e+01, 0.3340612434717e+01, + 0.3457083123290e-06, 0.3030475486049e+01, 0.3516457698740e-01, + 0.3032559967314e-06, 0.2652038793632e+01, 0.1104591729320e-01, + 0.2841133988903e-06, 0.1276744786829e+01, 0.4110125927500e-01, + 0.2855564444432e-06, 0.2143368674733e+01, 0.1510475019529e+00, + + 0.2765157135038e-06, 0.5444186109077e+01, 0.6373574839730e-01, + 0.2382312465034e-06, 0.2190521137593e+01, 0.2275259891141e+00, + 0.2808060365077e-06, 0.5735195064841e+01, 0.2535050500000e-01, + 0.2332175234405e-06, 0.9481985524859e-01, 0.7181332454670e-01, + 0.2322488199659e-06, 0.5180499361533e+01, 0.8582758298370e-01, + 0.1881850258423e-06, 0.3219788273885e+01, 0.2118763888447e+01, + 0.2196111392808e-06, 0.2366941159761e+01, 0.2968341143800e-02, + 0.2183810335519e-06, 0.4825445110915e+01, 0.7775000683430e-01, + 0.2002733093326e-06, 0.2457148995307e+01, 0.2093666171530e+00, + 0.1967111767229e-06, 0.5586291545459e+01, 0.2172315424036e+00, + + 0.1568473250543e-06, 0.3708003123320e+01, 0.7429900518901e+00, + 0.1852528314300e-06, 0.4310638151560e+01, 0.2022531624851e+00, + 0.1832111226447e-06, 0.1494665322656e+01, 0.3235053470014e+00, + 0.1746805502310e-06, 0.1451378500784e+01, 0.1385174140878e+00, + 0.1555730966650e-06, 0.1068040418198e+01, 0.7358765972222e+00, + 0.1554883462559e-06, 0.2442579035461e+01, 0.5154640627760e+00, + 0.1638380568746e-06, 0.2597913420625e+00, 0.8531963191132e+00, + 0.1159938593640e-06, 0.5834512021280e+01, 0.1990721704425e+00, + 0.1083427965695e-06, 0.5054033177950e+01, 0.5439178814476e+00, + 0.1156480369431e-06, 0.5325677432457e+01, 0.5257585094865e+00, + + 0.1141308860095e-06, 0.2153403923857e+01, 0.5336234347371e+00, + 0.7913146470946e-07, 0.8642846847027e+00, 0.1478866649112e+01, + 0.7439752463733e-07, 0.1970628496213e+01, 0.2164800718209e+00, + 0.7280277104079e-07, 0.6073307250609e+01, 0.2101180877357e+00, + 0.8319567719136e-07, 0.1954371928334e+01, 0.1692165728891e+01, + 0.7137705549290e-07, 0.8904989440909e+00, 0.4155522422634e+00, + 0.6900825396225e-07, 0.2825717714977e+01, 0.1173197218910e+00, + 0.7245757216635e-07, 0.2481677513331e+01, 0.1265567569334e+01, + 0.6961165696255e-07, 0.1292955312978e+01, 0.9562891316684e+00, + 0.7571804456890e-07, 0.3427517575069e+01, 0.1422690933580e-01, + + 0.6605425721904e-07, 0.8052192701492e+00, 0.6470106940028e+00, + 0.7375477357248e-07, 0.1705076390088e+01, 0.1581959461667e+01, + 0.7041664951470e-07, 0.4848356967891e+00, 0.9597935788730e-01, + 0.6322199535763e-07, 0.3878069473909e+01, 0.7084920306520e-01, + 0.5244380279191e-07, 0.2645560544125e+01, 0.5265099800692e+00, + 0.5143125704988e-07, 0.4834486101370e+01, 0.5328719641544e+00, + 0.5871866319373e-07, 0.7981472548900e+00, 0.7871412831580e-01, + 0.6300822573871e-07, 0.5979398788281e+01, 0.2608790314060e+02, + 0.6062154271548e-07, 0.4108655402756e+01, 0.1114304132498e+00, + 0.4361912339976e-07, 0.5322624319280e+01, 0.1375773836557e+01, + + 0.4417005920067e-07, 0.6240817359284e+01, 0.2770348281756e+00, + 0.4686806749936e-07, 0.3214977301156e+01, 0.1143987543936e+00, + 0.3758892132305e-07, 0.5879809634765e+01, 0.1596186371003e+01, + 0.5151351332319e-07, 0.2893377688007e+00, 0.2228608264996e+00, + 0.4554683578572e-07, 0.5475427144122e+01, 0.1465949902372e+00, + 0.3442381385338e-07, 0.5992034796640e+01, 0.5070101000000e-01, + 0.2831093954933e-07, 0.5367350273914e+01, 0.3092784376656e+00, + 0.3756267090084e-07, 0.5758171285420e+01, 0.4903339079539e+00, + 0.2816374679892e-07, 0.1863718700923e+01, 0.2991266627620e+00, + 0.3419307025569e-07, 0.9524347534130e+00, 0.3518164938661e+00, + + 0.2904250494239e-07, 0.5304471615602e+01, 0.1099462426779e+00, + 0.2471734511206e-07, 0.1297069793530e+01, 0.6256703299991e+00, + 0.2539620831872e-07, 0.3281126083375e+01, 0.1256615170089e+02, + 0.2281017868007e-07, 0.1829122133165e+01, 0.6681224869435e+01, + 0.2275319473335e-07, 0.5797198160181e+01, 0.3932462625300e-02, + 0.2547755368442e-07, 0.4752697708330e+01, 0.1169588211447e+01, + 0.2285979669317e-07, 0.1223205292886e+01, 0.1045155034888e+01, + 0.1913386560994e-07, 0.1757532993389e+01, 0.1155361302111e+01, + 0.1809020525147e-07, 0.4246116108791e+01, 0.3368040641550e-01, + 0.1649213300201e-07, 0.1445162890627e+01, 0.4408250688924e+00, + + 0.1834972793932e-07, 0.1126917567225e+01, 0.4452511715700e-02, + 0.1439550648138e-07, 0.6160756834764e+01, 0.9420622223326e+00, + 0.1487645457041e-07, 0.4358761931792e+01, 0.4123712502208e+00, + 0.1731729516660e-07, 0.6134456753344e+01, 0.2108507877249e+00, + 0.1717747163567e-07, 0.1898186084455e+01, 0.2157473718317e+00, + 0.1418190430374e-07, 0.4180286741266e+01, 0.6521991896920e-01, + 0.1404844134873e-07, 0.7654053565412e-01, 0.4258542984690e-01, + 0.1409842846538e-07, 0.4418612420312e+01, 0.2258291676434e+00, + 0.1090948346291e-07, 0.1260615686131e+01, 0.4226656969313e+00, + 0.1357577323612e-07, 0.3558248818690e+01, 0.7923417740620e-01, + + 0.1018154061960e-07, 0.5676087241256e+01, 0.1456308687557e+00, + 0.1412073972109e-07, 0.8394392632422e+00, 0.1525316725248e+00, + 0.1030938326496e-07, 0.1653593274064e+01, 0.1795258541446e+01, + 0.1180081567104e-07, 0.1285802592036e+01, 0.7032915397480e-01, + 0.9708510575650e-08, 0.7631889488106e+00, 0.8434341241180e-01, + 0.9637689663447e-08, 0.4630642649176e+01, 0.1272681024002e+01, + 0.1068910429389e-07, 0.5294934032165e+01, 0.2123349582968e+00, + 0.1063716179336e-07, 0.2736266800832e+01, 0.2142632012598e+00, + 0.1234858713814e-07, 0.1302891146570e+01, 0.1847279083684e+00, + 0.8912631189738e-08, 0.3570415993621e+01, 0.2648454860559e+01, + + 0.1036378285534e-07, 0.4236693440949e+01, 0.1370332435159e+00, + 0.9667798501561e-08, 0.2960768892398e+01, 0.4376440768498e+00, + 0.8108314201902e-08, 0.6987781646841e+00, 0.2880807454688e+00, + 0.7648364324628e-08, 0.2499017863863e+01, 0.2037373330570e+00, + 0.7286136828406e-08, 0.3787426951665e+01, 0.1129145838217e+00, + 0.9448237743913e-08, 0.2694354332983e+01, 0.5272426800584e+00, + 0.9374276106428e-08, 0.4787121277064e+01, 0.5321392641652e+00, + 0.7100226287462e-08, 0.3530238792101e+00, 0.6288513220417e+00, + 0.9253056659571e-08, 0.1399478925664e+01, 0.1606092486742e+00, + 0.6636432145504e-08, 0.3479575438447e+01, 0.1368660381889e+01, + + 0.6469975312932e-08, 0.1383669964800e+01, 0.2008557621224e+01, + 0.7335849729765e-08, 0.1243698166898e+01, 0.9561746721300e-02, + 0.8743421205855e-08, 0.3776164289301e+01, 0.3801276407308e+00, + 0.5993635744494e-08, 0.5627122113596e+01, 0.2042657109477e+02, + 0.5981008479693e-08, 0.1674336636752e+01, 0.2111650433779e+01, + 0.6188535145838e-08, 0.5214925208672e+01, 0.4305306221819e+00, + 0.6596074017566e-08, 0.2907653268124e+01, 0.1063314406849e+01, + 0.6630815126226e-08, 0.2127643669658e+01, 0.8389694097774e+00, + 0.6156772830040e-08, 0.5082160803295e+01, 0.4234171675140e+00, + 0.6446960563014e-08, 0.1872100916905e+01, 0.5287268506303e+00, + + 0.6429324424668e-08, 0.5610276103577e+01, 0.5306550935933e+00, + 0.6302232396465e-08, 0.1592152049607e+01, 0.1253008786510e-01, + 0.6399244436159e-08, 0.2746214421532e+01, 0.5217580628120e+02, + 0.5474965172558e-08, 0.2317666374383e+01, 0.2221856701002e+01, + 0.5339293190692e-08, 0.1084724961156e+01, 0.7466759693650e-01, + 0.5334733683389e-08, 0.3594106067745e+01, 0.7489573444450e-01, + 0.5392665782110e-08, 0.5630254365606e+01, 0.1055449481598e+01, + 0.6682075673789e-08, 0.1518480041732e+01, 0.2213766559277e+00, + 0.5079130495960e-08, 0.2739765115711e+01, 0.2132517061319e+00, + 0.5077759793261e-08, 0.5290711290094e+01, 0.2133464534247e+00, + + 0.4832037368310e-08, 0.1404473217200e+01, 0.7160067364790e-01, + 0.6463279674802e-08, 0.6038381695210e+01, 0.2209183458640e-01, + 0.6240592771560e-08, 0.1290170653666e+01, 0.3306188016693e+00, + 0.4672013521493e-08, 0.3261895939677e+01, 0.7796265773310e-01, + 0.6500650750348e-08, 0.1154522312095e+01, 0.3884652414254e+00, + 0.6344161389053e-08, 0.6206111545062e+01, 0.7605151500000e-01, + 0.4682518370646e-08, 0.5409118796685e+01, 0.1073608853559e+01, + 0.5329460015591e-08, 0.1202985784864e+01, 0.7287631425543e+00, + 0.5701588675898e-08, 0.4098715257064e+01, 0.8731175355560e-01, + 0.6030690867211e-08, 0.4132033218460e+00, 0.9846002785331e+00, + + 0.4336256312655e-08, 0.1211415991827e+01, 0.4297791515992e+00, + 0.4688498808975e-08, 0.3765479072409e+01, 0.2127790306879e+00, + 0.4675578609335e-08, 0.4265540037226e+01, 0.2138191288687e+00, + 0.4225578112158e-08, 0.5237566010676e+01, 0.3407705765729e+00, + 0.5139422230028e-08, 0.1507173079513e+01, 0.7233337363710e-01, + 0.4619995093571e-08, 0.9023957449848e-01, 0.8603097737811e+00, + 0.4494776255461e-08, 0.5414930552139e+00, 0.7381754420900e-01, + 0.4274026276788e-08, 0.4145735303659e+01, 0.7574578717200e-01, + 0.5018141789353e-08, 0.3344408829055e+01, 0.3180992042600e-02, + 0.4866163952181e-08, 0.3348534657607e+01, 0.7722995774390e-01, + + 0.4111986020501e-08, 0.4198823597220e+00, 0.1451108196653e+00, + 0.3356142784950e-08, 0.5609144747180e+01, 0.1274714967946e+00, + 0.4070575554551e-08, 0.7028411059224e+00, 0.3503323232942e+00, + 0.3257451857278e-08, 0.5624697983086e+01, 0.5296435984654e+00, + 0.3256973703026e-08, 0.1857842076707e+01, 0.5297383457582e+00, + 0.3830771508640e-08, 0.4562887279931e+01, 0.9098186128426e+00, + 0.3725024005962e-08, 0.2358058692652e+00, 0.1084620721060e+00, + 0.3136763921756e-08, 0.2049731526845e+01, 0.2346394437820e+00, + 0.3795147256194e-08, 0.2432356296933e+00, 0.1862120789403e+00, + 0.2877342229911e-08, 0.5631101279387e+01, 0.1905464808669e+01, + + 0.3076931798805e-08, 0.1117615737392e+01, 0.3628624111593e+00, + 0.2734765945273e-08, 0.5899826516955e+01, 0.2131850110243e+00, + 0.2733405296885e-08, 0.2130562964070e+01, 0.2134131485323e+00, + 0.2898552353410e-08, 0.3462387048225e+00, 0.5291709230214e+00, + 0.2893736103681e-08, 0.8534352781543e+00, 0.5302110212022e+00, + 0.3095717734137e-08, 0.2875061429041e+01, 0.2976424921901e+00, + 0.2636190425832e-08, 0.2242512846659e+01, 0.1485980103780e+01, + 0.3645512095537e-08, 0.1354016903958e+01, 0.6044726378023e+00, + 0.2808173547723e-08, 0.6705114365631e-01, 0.6225157782540e-01, + 0.2625012866888e-08, 0.4775705748482e+01, 0.5268983110410e-01, + + 0.2572233995651e-08, 0.2638924216139e+01, 0.1258454114666e+01, + 0.2604238824792e-08, 0.4826358927373e+01, 0.2103781122809e+00, + 0.2596886385239e-08, 0.3200388483118e+01, 0.2162200472757e+00, + 0.3228057304264e-08, 0.5384848409563e+01, 0.2007689919132e+00, + 0.2481601798252e-08, 0.5173373487744e+01, 0.1062562936266e+01, + 0.2745977498864e-08, 0.6250966149853e+01, 0.5651155736444e+00, + 0.2669878833811e-08, 0.4906001352499e+01, 0.1400015846597e+00, + 0.3203986611711e-08, 0.5034333010005e+01, 0.7036329877322e+00, + 0.3354961227212e-08, 0.6108262423137e+01, 0.4549093064213e+00, + 0.2400407324558e-08, 0.2135399294955e+01, 0.2125476091956e+00, + + 0.2379905859802e-08, 0.5893721933961e+01, 0.2140505503610e+00, + 0.2550844302187e-08, 0.3331940762063e+01, 0.1534957940063e+00, + 0.2268824211001e-08, 0.1843418461035e+01, 0.2235935264888e+00, + 0.2464700891204e-08, 0.3029548547230e+01, 0.2091065926078e+00, + 0.2436814726024e-08, 0.4994717970364e+01, 0.2174915669488e+00, + 0.2443623894745e-08, 0.2645102591375e+01, 0.1739420156204e+00, + 0.2318701783838e-08, 0.5700547397897e+01, 0.7530171478090e-01, + 0.2284448700256e-08, 0.5268898905872e+01, 0.7426161660010e-01, + 0.2468848123510e-08, 0.5276280575078e+01, 0.2526561439362e+00, + 0.2814052350303e-08, 0.6130168623475e+01, 0.5636314030725e+00, + + 0.2243662755220e-08, 0.6631692457995e+00, 0.8886590321940e-01, + 0.2330795855941e-08, 0.2499435487702e+01, 0.1056200952181e+01, + 0.9757679038404e-09, 0.5796846023126e+01, 0.7826370942180e+02 }; + +/* SSB-to-Sun, T^0, Z */ + static const double s0z[] = { + 0.1181255122986e-03, 0.4607918989164e+00, 0.2132990797783e+00, + 0.1127777651095e-03, 0.4169146331296e+00, 0.5296909721118e+00, + 0.4777754401806e-04, 0.4582657007130e+01, 0.3813291813120e-01, + 0.1129354285772e-04, 0.5758735142480e+01, 0.7478166569050e-01, + -0.1149543637123e-04, 0.0000000000000e+00, 0.0000000000000e+00, + 0.3298730512306e-05, 0.5978801994625e+01, 0.4265981595566e+00, + 0.2733376706079e-05, 0.7665413691040e+00, 0.1059381944224e+01, + 0.9426389657270e-06, 0.3710201265838e+01, 0.2061856251104e+00, + 0.8187517749552e-06, 0.3390675605802e+00, 0.2204125344462e+00, + 0.4080447871819e-06, 0.4552296640088e+00, 0.5225775174439e+00, + + 0.3169973017028e-06, 0.3445455899321e+01, 0.5368044267797e+00, + 0.2438098615549e-06, 0.5664675150648e+01, 0.3664874755930e-01, + 0.2601897517235e-06, 0.1931894095697e+01, 0.1495633313810e+00, + 0.2314558080079e-06, 0.3666319115574e+00, 0.3961708870310e-01, + 0.1962549548002e-06, 0.3167411699020e+01, 0.7626583626240e-01, + 0.2180518287925e-06, 0.1544420746580e+01, 0.7113454667900e-02, + 0.1451382442868e-06, 0.1583756740070e+01, 0.1102062672231e+00, + 0.1358439007389e-06, 0.5239941758280e+01, 0.6398972393349e+00, + 0.1050585898028e-06, 0.2266958352859e+01, 0.3163918923335e+00, + 0.1050029870186e-06, 0.2711495250354e+01, 0.4194847048887e+00, + + 0.9934920679800e-07, 0.1116208151396e+01, 0.1589072916335e+01, + 0.1048395331560e-06, 0.3408619600206e+01, 0.1021328554739e+02, + 0.8370147196668e-07, 0.3810459401087e+01, 0.2535050500000e-01, + 0.7989856510998e-07, 0.3769910473647e+01, 0.7329749511860e-01, + 0.5441221655233e-07, 0.2416994903374e+01, 0.1030928125552e+00, + 0.4610812906784e-07, 0.5858503336994e+01, 0.4337116142245e+00, + 0.3923022803444e-07, 0.3354170010125e+00, 0.1484170571900e-02, + 0.2610725582128e-07, 0.5410600646324e+01, 0.6327837846670e+00, + 0.2455279767721e-07, 0.6120216681403e+01, 0.1162474756779e+01, + 0.2375530706525e-07, 0.6055443426143e+01, 0.1052268489556e+01, + + 0.1782967577553e-07, 0.3146108708004e+01, 0.8460828644453e+00, + 0.1581687095238e-07, 0.6255496089819e+00, 0.3340612434717e+01, + 0.1594657672461e-07, 0.3782604300261e+01, 0.1066495398892e+01, + 0.1563448615040e-07, 0.1997775733196e+01, 0.2022531624851e+00, + 0.1463624258525e-07, 0.1736316792088e+00, 0.3516457698740e-01, + 0.1331585056673e-07, 0.4331941830747e+01, 0.9491756770005e+00, + 0.1130634557637e-07, 0.6152017751825e+01, 0.2968341143800e-02, + 0.1028949607145e-07, 0.2101792614637e+00, 0.2275259891141e+00, + 0.1024074971618e-07, 0.4071833211074e+01, 0.5070101000000e-01, + 0.8826956060303e-08, 0.4861633688145e+00, 0.2093666171530e+00, + + 0.8572230171541e-08, 0.5268190724302e+01, 0.4110125927500e-01, + 0.7649332643544e-08, 0.5134543417106e+01, 0.2608790314060e+02, + 0.8581673291033e-08, 0.2920218146681e+01, 0.1480791608091e+00, + 0.8430589300938e-08, 0.3604576619108e+01, 0.2172315424036e+00, + 0.7776165501012e-08, 0.3772942249792e+01, 0.6373574839730e-01, + 0.8311070234408e-08, 0.6200412329888e+01, 0.3235053470014e+00, + 0.6927365212582e-08, 0.4543353113437e+01, 0.8531963191132e+00, + 0.6791574208598e-08, 0.2882188406238e+01, 0.7181332454670e-01, + 0.5593100811839e-08, 0.1776646892780e+01, 0.7429900518901e+00, + 0.4553381853021e-08, 0.3949617611240e+01, 0.7775000683430e-01, + + 0.5758000450068e-08, 0.3859251775075e+01, 0.1990721704425e+00, + 0.4281283457133e-08, 0.1466294631206e+01, 0.2118763888447e+01, + 0.4206935661097e-08, 0.5421776011706e+01, 0.1104591729320e-01, + 0.4213751641837e-08, 0.3412048993322e+01, 0.2243449970715e+00, + 0.5310506239878e-08, 0.5421641370995e+00, 0.5154640627760e+00, + 0.3827450341320e-08, 0.8887314524995e+00, 0.1510475019529e+00, + 0.4292435241187e-08, 0.1405043757194e+01, 0.1422690933580e-01, + 0.3189780702289e-08, 0.1060049293445e+01, 0.1173197218910e+00, + 0.3226611928069e-08, 0.6270858897442e+01, 0.2164800718209e+00, + 0.2893897608830e-08, 0.5117563223301e+01, 0.6470106940028e+00, + + 0.3239852024578e-08, 0.4079092237983e+01, 0.2101180877357e+00, + 0.2956892222200e-08, 0.1594917021704e+01, 0.3092784376656e+00, + 0.2980177912437e-08, 0.5258787667564e+01, 0.4155522422634e+00, + 0.3163725690776e-08, 0.3854589225479e+01, 0.8582758298370e-01, + 0.2662262399118e-08, 0.3561326430187e+01, 0.5257585094865e+00, + 0.2766689135729e-08, 0.3180732086830e+00, 0.1385174140878e+00, + 0.2411600278464e-08, 0.3324798335058e+01, 0.5439178814476e+00, + 0.2483527695131e-08, 0.4169069291947e+00, 0.5336234347371e+00, + 0.7788777276590e-09, 0.1900569908215e+01, 0.5217580628120e+02 }; + +/* SSB-to-Sun, T^1, X */ + static const double s1x[] = { + -0.1296310361520e-07, 0.0000000000000e+00, 0.0000000000000e+00, + 0.8975769009438e-08, 0.1128891609250e+01, 0.4265981595566e+00, + 0.7771113441307e-08, 0.2706039877077e+01, 0.2061856251104e+00, + 0.7538303866642e-08, 0.2191281289498e+01, 0.2204125344462e+00, + 0.6061384579336e-08, 0.3248167319958e+01, 0.1059381944224e+01, + 0.5726994235594e-08, 0.5569981398610e+01, 0.5225775174439e+00, + 0.5616492836424e-08, 0.5057386614909e+01, 0.5368044267797e+00, + 0.1010881584769e-08, 0.3473577116095e+01, 0.7113454667900e-02, + 0.7259606157626e-09, 0.3651858593665e+00, 0.6398972393349e+00, + 0.8755095026935e-09, 0.1662835408338e+01, 0.4194847048887e+00, + + 0.5370491182812e-09, 0.1327673878077e+01, 0.4337116142245e+00, + 0.5743773887665e-09, 0.4250200846687e+01, 0.2132990797783e+00, + 0.4408103140300e-09, 0.3598752574277e+01, 0.1589072916335e+01, + 0.3101892374445e-09, 0.4887822983319e+01, 0.1052268489556e+01, + 0.3209453713578e-09, 0.9702272295114e+00, 0.5296909721118e+00, + 0.3017228286064e-09, 0.5484462275949e+01, 0.1066495398892e+01, + 0.3200700038601e-09, 0.2846613338643e+01, 0.1495633313810e+00, + 0.2137637279911e-09, 0.5692163292729e+00, 0.3163918923335e+00, + 0.1899686386727e-09, 0.2061077157189e+01, 0.2275259891141e+00, + 0.1401994545308e-09, 0.4177771136967e+01, 0.1102062672231e+00, + + 0.1578057810499e-09, 0.5782460597335e+01, 0.7626583626240e-01, + 0.1237713253351e-09, 0.5705900866881e+01, 0.5154640627760e+00, + 0.1313076837395e-09, 0.5163438179576e+01, 0.3664874755930e-01, + 0.1184963304860e-09, 0.3054804427242e+01, 0.6327837846670e+00, + 0.1238130878565e-09, 0.2317292575962e+01, 0.3961708870310e-01, + 0.1015959527736e-09, 0.2194643645526e+01, 0.7329749511860e-01, + 0.9017954423714e-10, 0.2868603545435e+01, 0.1990721704425e+00, + 0.8668024955603e-10, 0.4923849675082e+01, 0.5439178814476e+00, + 0.7756083930103e-10, 0.3014334135200e+01, 0.9491756770005e+00, + 0.7536503401741e-10, 0.2704886279769e+01, 0.1030928125552e+00, + + 0.5483308679332e-10, 0.6010983673799e+01, 0.8531963191132e+00, + 0.5184339620428e-10, 0.1952704573291e+01, 0.2093666171530e+00, + 0.5108658712030e-10, 0.2958575786649e+01, 0.2172315424036e+00, + 0.5019424524650e-10, 0.1736317621318e+01, 0.2164800718209e+00, + 0.4909312625978e-10, 0.3167216416257e+01, 0.2101180877357e+00, + 0.4456638901107e-10, 0.7697579923471e+00, 0.3235053470014e+00, + 0.4227030350925e-10, 0.3490910137928e+01, 0.6373574839730e-01, + 0.4095456040093e-10, 0.5178888984491e+00, 0.6470106940028e+00, + 0.4990537041422e-10, 0.3323887668974e+01, 0.1422690933580e-01, + 0.4321170010845e-10, 0.4288484987118e+01, 0.7358765972222e+00, + + 0.3544072091802e-10, 0.6021051579251e+01, 0.5265099800692e+00, + 0.3480198638687e-10, 0.4600027054714e+01, 0.5328719641544e+00, + 0.3440287244435e-10, 0.4349525970742e+01, 0.8582758298370e-01, + 0.3330628322713e-10, 0.2347391505082e+01, 0.1104591729320e-01, + 0.2973060707184e-10, 0.4789409286400e+01, 0.5257585094865e+00, + 0.2932606766089e-10, 0.5831693799927e+01, 0.5336234347371e+00, + 0.2876972310953e-10, 0.2692638514771e+01, 0.1173197218910e+00, + 0.2827488278556e-10, 0.2056052487960e+01, 0.2022531624851e+00, + 0.2515028239756e-10, 0.7411863262449e+00, 0.9597935788730e-01, + 0.2853033744415e-10, 0.3948481024894e+01, 0.2118763888447e+01 }; + +/* SSB-to-Sun, T^1, Y */ + static const double s1y[] = { + 0.8989047573576e-08, 0.5840593672122e+01, 0.4265981595566e+00, + 0.7815938401048e-08, 0.1129664707133e+01, 0.2061856251104e+00, + 0.7550926713280e-08, 0.6196589104845e+00, 0.2204125344462e+00, + 0.6056556925895e-08, 0.1677494667846e+01, 0.1059381944224e+01, + 0.5734142698204e-08, 0.4000920852962e+01, 0.5225775174439e+00, + 0.5614341822459e-08, 0.3486722577328e+01, 0.5368044267797e+00, + 0.1028678147656e-08, 0.1877141024787e+01, 0.7113454667900e-02, + 0.7270792075266e-09, 0.5077167301739e+01, 0.6398972393349e+00, + 0.8734141726040e-09, 0.9069550282609e-01, 0.4194847048887e+00, + 0.5377371402113e-09, 0.6039381844671e+01, 0.4337116142245e+00, + + 0.4729719431571e-09, 0.2153086311760e+01, 0.2132990797783e+00, + 0.4458052820973e-09, 0.5059830025565e+01, 0.5296909721118e+00, + 0.4406855467908e-09, 0.2027971692630e+01, 0.1589072916335e+01, + 0.3101659310977e-09, 0.3317677981860e+01, 0.1052268489556e+01, + 0.3016749232545e-09, 0.3913703482532e+01, 0.1066495398892e+01, + 0.3198541352656e-09, 0.1275513098525e+01, 0.1495633313810e+00, + 0.2142065389871e-09, 0.5301351614597e+01, 0.3163918923335e+00, + 0.1902615247592e-09, 0.4894943352736e+00, 0.2275259891141e+00, + 0.1613410990871e-09, 0.2449891130437e+01, 0.1102062672231e+00, + 0.1576992165097e-09, 0.4211421447633e+01, 0.7626583626240e-01, + + 0.1241637259894e-09, 0.4140803368133e+01, 0.5154640627760e+00, + 0.1313974830355e-09, 0.3591920305503e+01, 0.3664874755930e-01, + 0.1181697118258e-09, 0.1506314382788e+01, 0.6327837846670e+00, + 0.1238239742779e-09, 0.7461405378404e+00, 0.3961708870310e-01, + 0.1010107068241e-09, 0.6271010795475e+00, 0.7329749511860e-01, + 0.9226316616509e-10, 0.1259158839583e+01, 0.1990721704425e+00, + 0.8664946419555e-10, 0.3353244696934e+01, 0.5439178814476e+00, + 0.7757230468978e-10, 0.1447677295196e+01, 0.9491756770005e+00, + 0.7693168628139e-10, 0.1120509896721e+01, 0.1030928125552e+00, + 0.5487897454612e-10, 0.4439380426795e+01, 0.8531963191132e+00, + + 0.5196118677218e-10, 0.3788856619137e+00, 0.2093666171530e+00, + 0.5110853339935e-10, 0.1386879372016e+01, 0.2172315424036e+00, + 0.5027804534813e-10, 0.1647881805466e+00, 0.2164800718209e+00, + 0.4922485922674e-10, 0.1594315079862e+01, 0.2101180877357e+00, + 0.6155599524400e-10, 0.0000000000000e+00, 0.0000000000000e+00, + 0.4447147832161e-10, 0.5480720918976e+01, 0.3235053470014e+00, + 0.4144691276422e-10, 0.1931371033660e+01, 0.6373574839730e-01, + 0.4099950625452e-10, 0.5229611294335e+01, 0.6470106940028e+00, + 0.5060541682953e-10, 0.1731112486298e+01, 0.1422690933580e-01, + 0.4293615946300e-10, 0.2714571038925e+01, 0.7358765972222e+00, + + 0.3545659845763e-10, 0.4451041444634e+01, 0.5265099800692e+00, + 0.3479112041196e-10, 0.3029385448081e+01, 0.5328719641544e+00, + 0.3438516493570e-10, 0.2778507143731e+01, 0.8582758298370e-01, + 0.3297341285033e-10, 0.7898709807584e+00, 0.1104591729320e-01, + 0.2972585818015e-10, 0.3218785316973e+01, 0.5257585094865e+00, + 0.2931707295017e-10, 0.4260731012098e+01, 0.5336234347371e+00, + 0.2897198149403e-10, 0.1120753978101e+01, 0.1173197218910e+00, + 0.2832293240878e-10, 0.4597682717827e+00, 0.2022531624851e+00, + 0.2864348326612e-10, 0.2169939928448e+01, 0.9597935788730e-01, + 0.2852714675471e-10, 0.2377659870578e+01, 0.2118763888447e+01 }; + +/* SSB-to-Sun, T^1, Z */ + static const double s1z[] = { + 0.5444220475678e-08, 0.1803825509310e+01, 0.2132990797783e+00, + 0.3883412695596e-08, 0.4668616389392e+01, 0.5296909721118e+00, + 0.1334341434551e-08, 0.0000000000000e+00, 0.0000000000000e+00, + 0.3730001266883e-09, 0.5401405918943e+01, 0.2061856251104e+00, + 0.2894929197956e-09, 0.4932415609852e+01, 0.2204125344462e+00, + 0.2857950357701e-09, 0.3154625362131e+01, 0.7478166569050e-01, + 0.2499226432292e-09, 0.3657486128988e+01, 0.4265981595566e+00, + 0.1937705443593e-09, 0.5740434679002e+01, 0.1059381944224e+01, + 0.1374894396320e-09, 0.1712857366891e+01, 0.5368044267797e+00, + 0.1217248678408e-09, 0.2312090870932e+01, 0.5225775174439e+00, + + 0.7961052740870e-10, 0.5283368554163e+01, 0.3813291813120e-01, + 0.4979225949689e-10, 0.4298290471860e+01, 0.4194847048887e+00, + 0.4388552286597e-10, 0.6145515047406e+01, 0.7113454667900e-02, + 0.2586835212560e-10, 0.3019448001809e+01, 0.6398972393349e+00 }; + +/* SSB-to-Sun, T^2, X */ + static const double s2x[] = { + 0.1603551636587e-11, 0.4404109410481e+01, 0.2061856251104e+00, + 0.1556935889384e-11, 0.4818040873603e+00, 0.2204125344462e+00, + 0.1182594414915e-11, 0.9935762734472e+00, 0.5225775174439e+00, + 0.1158794583180e-11, 0.3353180966450e+01, 0.5368044267797e+00, + 0.9597358943932e-12, 0.5567045358298e+01, 0.2132990797783e+00, + 0.6511516579605e-12, 0.5630872420788e+01, 0.4265981595566e+00, + 0.7419792747688e-12, 0.2156188581957e+01, 0.5296909721118e+00, + 0.3951972655848e-12, 0.1981022541805e+01, 0.1059381944224e+01, + 0.4478223877045e-12, 0.0000000000000e+00, 0.0000000000000e+00 }; + +/* SSB-to-Sun, T^2, Y */ + static const double s2y[] = { + 0.1609114495091e-11, 0.2831096993481e+01, 0.2061856251104e+00, + 0.1560330784946e-11, 0.5193058213906e+01, 0.2204125344462e+00, + 0.1183535479202e-11, 0.5707003443890e+01, 0.5225775174439e+00, + 0.1158183066182e-11, 0.1782400404928e+01, 0.5368044267797e+00, + 0.1032868027407e-11, 0.4036925452011e+01, 0.2132990797783e+00, + 0.6540142847741e-12, 0.4058241056717e+01, 0.4265981595566e+00, + 0.7305236491596e-12, 0.6175401942957e+00, 0.5296909721118e+00, + -0.5580725052968e-12, 0.0000000000000e+00, 0.0000000000000e+00, + 0.3946122651015e-12, 0.4108265279171e+00, 0.1059381944224e+01 }; + +/* SSB-to-Sun, T^2, Z */ + static const double s2z[] = { + 0.3749920358054e-12, 0.3230285558668e+01, 0.2132990797783e+00, + 0.2735037220939e-12, 0.6154322683046e+01, 0.5296909721118e+00 }; + +/* Pointers to coefficient arrays, in x,y,z sets */ + static const double *ce0[] = { e0x, e0y, e0z }, + *ce1[] = { e1x, e1y, e1z }, + *ce2[] = { e2x, e2y, e2z }, + *cs0[] = { s0x, s0y, s0z }, + *cs1[] = { s1x, s1y, s1z }, + *cs2[] = { s2x, s2y, s2z }; + const double *coeffs; + +/* Numbers of terms for each component of the model, in x,y,z sets */ + static const int ne0[3] = {(int)(sizeof e0x / sizeof (double) / 3), + (int)(sizeof e0y / sizeof (double) / 3), + (int)(sizeof e0z / sizeof (double) / 3) }, + ne1[3] = {(int)(sizeof e1x / sizeof (double) / 3), + (int)(sizeof e1y / sizeof (double) / 3), + (int)(sizeof e1z / sizeof (double) / 3) }, + ne2[3] = {(int)(sizeof e2x / sizeof (double) / 3), + (int)(sizeof e2y / sizeof (double) / 3), + (int)(sizeof e2z / sizeof (double) / 3) }, + ns0[3] = {(int)(sizeof s0x / sizeof (double) / 3), + (int)(sizeof s0y / sizeof (double) / 3), + (int)(sizeof s0z / sizeof (double) / 3) }, + ns1[3] = {(int)(sizeof s1x / sizeof (double) / 3), + (int)(sizeof s1y / sizeof (double) / 3), + (int)(sizeof s1z / sizeof (double) / 3) }, + ns2[3] = {(int)(sizeof s2x / sizeof (double) / 3), + (int)(sizeof s2y / sizeof (double) / 3), + (int)(sizeof s2z / sizeof (double) / 3) }; + int nterms; + +/* Miscellaneous */ + int jstat, i, j; + double t, t2, xyz, xyzd, a, b, c, ct, p, cp, + ph[3], vh[3], pb[3], vb[3], x, y, z; + +/* ------------------------------------------------------------------ */ + +/* Time since reference epoch, Julian years. */ + t = ((date1 - DJ00) + date2) / DJY; + t2 = t*t; + +/* Set status. */ + jstat = fabs(t) <= 100.0 ? 0 : 1; + +/* X then Y then Z. */ + for (i = 0; i < 3; i++) { + + /* Initialize position and velocity component. */ + xyz = 0.0; + xyzd = 0.0; + + /* ------------------------------------------------ */ + /* Obtain component of Sun to Earth ecliptic vector */ + /* ------------------------------------------------ */ + + /* Sun to Earth, T^0 terms. */ + coeffs = ce0[i]; + nterms = ne0[i]; + for (j = 0; j < nterms; j++) { + a = *coeffs++; + b = *coeffs++; + c = *coeffs++; + p = b + c*t; + xyz += a*cos(p); + xyzd -= a*c*sin(p); + } + + /* Sun to Earth, T^1 terms. */ + coeffs = ce1[i]; + nterms = ne1[i]; + for (j = 0; j < nterms; j++) { + a = *coeffs++; + b = *coeffs++; + c = *coeffs++; + ct = c*t; + p = b + ct; + cp = cos(p); + xyz += a*t*cp; + xyzd += a*( cp - ct*sin(p) ); + } + + /* Sun to Earth, T^2 terms. */ + coeffs = ce2[i]; + nterms = ne2[i]; + for (j = 0; j < nterms; j++) { + a = *coeffs++; + b = *coeffs++; + c = *coeffs++; + ct = c*t; + p = b + ct; + cp = cos(p); + xyz += a*t2*cp; + xyzd += a*t*( 2.0*cp - ct*sin(p) ); + } + + /* Heliocentric Earth position and velocity component. */ + ph[i] = xyz; + vh[i] = xyzd / DJY; + + /* ------------------------------------------------ */ + /* Obtain component of SSB to Earth ecliptic vector */ + /* ------------------------------------------------ */ + + /* SSB to Sun, T^0 terms. */ + coeffs = cs0[i]; + nterms = ns0[i]; + for (j = 0; j < nterms; j++) { + a = *coeffs++; + b = *coeffs++; + c = *coeffs++; + p = b + c*t; + xyz += a*cos(p); + xyzd -= a*c*sin(p); + } + + /* SSB to Sun, T^1 terms. */ + coeffs = cs1[i]; + nterms = ns1[i]; + for (j = 0; j < nterms; j++) { + a = *coeffs++; + b = *coeffs++; + c = *coeffs++; + ct = c*t; + p = b + ct; + cp = cos(p); + xyz += a*t*cp; + xyzd += a*(cp - ct*sin(p)); + } + + /* SSB to Sun, T^2 terms. */ + coeffs = cs2[i]; + nterms = ns2[i]; + for (j = 0; j < nterms; j++) { + a = *coeffs++; + b = *coeffs++; + c = *coeffs++; + ct = c*t; + p = b + ct; + cp = cos(p); + xyz += a*t2*cp; + xyzd += a*t*(2.0*cp - ct*sin(p)); + } + + /* Barycentric Earth position and velocity component. */ + pb[i] = xyz; + vb[i] = xyzd / DJY; + + /* Next Cartesian component. */ + } + +/* Rotate from ecliptic to BCRS coordinates. */ + + x = ph[0]; + y = ph[1]; + z = ph[2]; + pvh[0][0] = x + am12*y + am13*z; + pvh[0][1] = am21*x + am22*y + am23*z; + pvh[0][2] = am32*y + am33*z; + + x = vh[0]; + y = vh[1]; + z = vh[2]; + pvh[1][0] = x + am12*y + am13*z; + pvh[1][1] = am21*x + am22*y + am23*z; + pvh[1][2] = am32*y + am33*z; + + x = pb[0]; + y = pb[1]; + z = pb[2]; + pvb[0][0] = x + am12*y + am13*z; + pvb[0][1] = am21*x + am22*y + am23*z; + pvb[0][2] = am32*y + am33*z; + + x = vb[0]; + y = vb[1]; + z = vb[2]; + pvb[1][0] = x + am12*y + am13*z; + pvb[1][1] = am21*x + am22*y + am23*z; + pvb[1][2] = am32*y + am33*z; + +/* Return the status. */ + return jstat; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/eqec06.c b/src/cpp/3rdparty/sofa/src/eqec06.c new file mode 100644 index 000000000..8f94cc21c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/eqec06.c @@ -0,0 +1,185 @@ +#include "sofa.h" + +void iauEqec06(double date1, double date2, double dr, double dd, + double *dl, double *db) +/* +** - - - - - - - - - - +** i a u E q e c 0 6 +** - - - - - - - - - - +** +** Transformation from ICRS equatorial coordinates to ecliptic +** coordinates (mean equinox and ecliptic of date) using IAU 2006 +** precession model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian date (Note 1) +** dr,dd double ICRS right ascension and declination (radians) +** +** Returned: +** dl,db double ecliptic longitude and latitude (radians) +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) No assumptions are made about whether the coordinates represent +** starlight and embody astrometric effects such as parallax or +** aberration. +** +** 3) The transformation is approximately that from mean J2000.0 right +** ascension and declination to ecliptic longitude and latitude +** (mean equinox and ecliptic of date), with only frame bias (always +** less than 25 mas) to disturb this classical picture. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauEcm06 J2000.0 to ecliptic rotation matrix, IAU 2006 +** iauRxp product of r-matrix and p-vector +** iauC2s unit vector to spherical coordinates +** iauAnp normalize angle into range 0 to 2pi +** iauAnpm normalize angle into range +/- pi +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rm[3][3], v1[3], v2[3], a, b; + + +/* Spherical to Cartesian. */ + iauS2c(dr, dd, v1); + +/* Rotation matrix, ICRS equatorial to ecliptic. */ + iauEcm06(date1, date2, rm); + +/* The transformation from ICRS to ecliptic. */ + iauRxp(rm, v1, v2); + +/* Cartesian to spherical. */ + iauC2s(v2, &a, &b); + +/* Express in conventional ranges. */ + *dl = iauAnp(a); + *db = iauAnpm(b); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/eqeq94.c b/src/cpp/3rdparty/sofa/src/eqeq94.c new file mode 100644 index 000000000..20885065b --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/eqeq94.c @@ -0,0 +1,185 @@ +#include "sofa.h" +#include "sofam.h" + +double iauEqeq94(double date1, double date2) +/* +** - - - - - - - - - - +** i a u E q e q 9 4 +** - - - - - - - - - - +** +** Equation of the equinoxes, IAU 1994 model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TDB date (Note 1) +** +** Returned (function value): +** double equation of the equinoxes (Note 2) +** +** Notes: +** +** 1) The date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The result, which is in radians, operates in the following sense: +** +** Greenwich apparent ST = GMST + equation of the equinoxes +** +** Called: +** iauAnpm normalize angle into range +/- pi +** iauNut80 nutation, IAU 1980 +** iauObl80 mean obliquity, IAU 1980 +** +** References: +** +** IAU Resolution C7, Recommendation 3 (1994). +** +** Capitaine, N. & Gontier, A.-M., 1993, Astron.Astrophys., 275, +** 645-650. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, om, dpsi, deps, eps0, ee; + + +/* Interval between fundamental epoch J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Longitude of the mean ascending node of the lunar orbit on the */ +/* ecliptic, measured from the mean equinox of date. */ + om = iauAnpm((450160.280 + (-482890.539 + + (7.455 + 0.008 * t) * t) * t) * DAS2R + + fmod(-5.0 * t, 1.0) * D2PI); + +/* Nutation components and mean obliquity. */ + iauNut80(date1, date2, &dpsi, &deps); + eps0 = iauObl80(date1, date2); + +/* Equation of the equinoxes. */ + ee = dpsi*cos(eps0) + DAS2R*(0.00264*sin(om) + 0.000063*sin(om+om)); + + return ee; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/era00.c b/src/cpp/3rdparty/sofa/src/era00.c new file mode 100644 index 000000000..7657ea7a4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/era00.c @@ -0,0 +1,189 @@ +#include "sofa.h" +#include "sofam.h" + +double iauEra00(double dj1, double dj2) +/* +** - - - - - - - - - +** i a u E r a 0 0 +** - - - - - - - - - +** +** Earth rotation angle (IAU 2000 model). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** dj1,dj2 double UT1 as a 2-part Julian Date (see note) +** +** Returned (function value): +** double Earth rotation angle (radians), range 0-2pi +** +** Notes: +** +** 1) The UT1 date dj1+dj2 is a Julian Date, apportioned in any +** convenient way between the arguments dj1 and dj2. For example, +** JD(UT1)=2450123.7 could be expressed in any of these ways, +** among others: +** +** dj1 dj2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. The date & time method is +** best matched to the algorithm used: maximum precision is +** delivered when the dj1 argument is for 0hrs UT1 on the day in +** question and the dj2 argument lies in the range 0 to 1, or vice +** versa. +** +** 2) The algorithm is adapted from Expression 22 of Capitaine et al. +** 2000. The time argument has been expressed in days directly, +** and, to retain precision, integer contributions have been +** eliminated. The same formulation is given in IERS Conventions +** (2003), Chap. 5, Eq. 14. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Capitaine N., Guinot B. and McCarthy D.D, 2000, Astron. +** Astrophys., 355, 398-405. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double d1, d2, t, f, theta; + + +/* Days since fundamental epoch. */ + if (dj1 < dj2) { + d1 = dj1; + d2 = dj2; + } else { + d1 = dj2; + d2 = dj1; + } + t = d1 + (d2- DJ00); + +/* Fractional part of T (days). */ + f = fmod(d1, 1.0) + fmod(d2, 1.0); + +/* Earth rotation angle at this UT1. */ + theta = iauAnp(D2PI * (f + 0.7790572732640 + + 0.00273781191135448 * t)); + + return theta; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fad03.c b/src/cpp/3rdparty/sofa/src/fad03.c new file mode 100644 index 000000000..6e09d93cd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fad03.c @@ -0,0 +1,156 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFad03(double t) +/* +** - - - - - - - - - +** i a u F a d 0 3 +** - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean elongation of the Moon from the Sun. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double D, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** is from Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean elongation of the Moon from the Sun (IERS Conventions 2003). */ + a = fmod( 1072260.703692 + + t * ( 1602961601.2090 + + t * ( - 6.3706 + + t * ( 0.006593 + + t * ( - 0.00003169 ) ) ) ), TURNAS ) * DAS2R; + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fae03.c b/src/cpp/3rdparty/sofa/src/fae03.c new file mode 100644 index 000000000..d5ae19bce --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fae03.c @@ -0,0 +1,155 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFae03(double t) +/* +** - - - - - - - - - +** i a u F a e 0 3 +** - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Earth. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Earth, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** comes from Souchay et al. (1999) after Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Earth (IERS Conventions 2003). */ + a = fmod(1.753470314 + 628.3075849991 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/faf03.c b/src/cpp/3rdparty/sofa/src/faf03.c new file mode 100644 index 000000000..e90f442bb --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/faf03.c @@ -0,0 +1,158 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFaf03(double t) +/* +** - - - - - - - - - +** i a u F a f 0 3 +** - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of the Moon minus mean longitude of the ascending +** node. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double F, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** is from Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of the Moon minus that of the ascending node */ +/* (IERS Conventions 2003). */ + a = fmod( 335779.526232 + + t * ( 1739527262.8478 + + t * ( - 12.7512 + + t * ( - 0.001037 + + t * ( 0.00000417 ) ) ) ), TURNAS ) * DAS2R; + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/faju03.c b/src/cpp/3rdparty/sofa/src/faju03.c new file mode 100644 index 000000000..457067e4a --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/faju03.c @@ -0,0 +1,155 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFaju03(double t) +/* +** - - - - - - - - - - +** i a u F a j u 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Jupiter. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Jupiter, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** comes from Souchay et al. (1999) after Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Jupiter (IERS Conventions 2003). */ + a = fmod(0.599546497 + 52.9690962641 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fal03.c b/src/cpp/3rdparty/sofa/src/fal03.c new file mode 100644 index 000000000..48495ca02 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fal03.c @@ -0,0 +1,156 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFal03(double t) +/* +** - - - - - - - - - +** i a u F a l 0 3 +** - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean anomaly of the Moon. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double l, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** is from Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean anomaly of the Moon (IERS Conventions 2003). */ + a = fmod( 485868.249036 + + t * ( 1717915923.2178 + + t * ( 31.8792 + + t * ( 0.051635 + + t * ( - 0.00024470 ) ) ) ), TURNAS ) * DAS2R; + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/falp03.c b/src/cpp/3rdparty/sofa/src/falp03.c new file mode 100644 index 000000000..dd44b38df --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/falp03.c @@ -0,0 +1,156 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFalp03(double t) +/* +** - - - - - - - - - - +** i a u F a l p 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean anomaly of the Sun. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double l', radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** is from Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean anomaly of the Sun (IERS Conventions 2003). */ + a = fmod( 1287104.793048 + + t * ( 129596581.0481 + + t * ( - 0.5532 + + t * ( 0.000136 + + t * ( - 0.00001149 ) ) ) ), TURNAS ) * DAS2R; + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fama03.c b/src/cpp/3rdparty/sofa/src/fama03.c new file mode 100644 index 000000000..451256994 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fama03.c @@ -0,0 +1,155 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFama03(double t) +/* +** - - - - - - - - - - +** i a u F a m a 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Mars. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Mars, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** comes from Souchay et al. (1999) after Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Mars (IERS Conventions 2003). */ + a = fmod(6.203480913 + 334.0612426700 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fame03.c b/src/cpp/3rdparty/sofa/src/fame03.c new file mode 100644 index 000000000..f2571d06d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fame03.c @@ -0,0 +1,155 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFame03(double t) +/* +** - - - - - - - - - - +** i a u F a m e 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Mercury. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Mercury, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** comes from Souchay et al. (1999) after Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Mercury (IERS Conventions 2003). */ + a = fmod(4.402608842 + 2608.7903141574 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fane03.c b/src/cpp/3rdparty/sofa/src/fane03.c new file mode 100644 index 000000000..87cd56cee --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fane03.c @@ -0,0 +1,152 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFane03(double t) +/* +** - - - - - - - - - - +** i a u F a n e 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Neptune. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Neptune, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** is adapted from Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Neptune (IERS Conventions 2003). */ + a = fmod(5.311886287 + 3.8133035638 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/faom03.c b/src/cpp/3rdparty/sofa/src/faom03.c new file mode 100644 index 000000000..1c805900b --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/faom03.c @@ -0,0 +1,157 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFaom03(double t) +/* +** - - - - - - - - - - +** i a u F a o m 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of the Moon's ascending node. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double Omega, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** is from Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J., 1994, Astron.Astrophys. 282, 663-683. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of the Moon's ascending node */ +/* (IERS Conventions 2003). */ + a = fmod( 450160.398036 + + t * ( - 6962890.5431 + + t * ( 7.4722 + + t * ( 0.007702 + + t * ( - 0.00005939 ) ) ) ), TURNAS ) * DAS2R; + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fapa03.c b/src/cpp/3rdparty/sofa/src/fapa03.c new file mode 100644 index 000000000..4a611f7a1 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fapa03.c @@ -0,0 +1,155 @@ +#include "sofa.h" + +double iauFapa03(double t) +/* +** - - - - - - - - - - +** i a u F a p a 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** general accumulated precession in longitude. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double general precession in longitude, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003). It +** is taken from Kinoshita & Souchay (1990) and comes originally +** from Lieske et al. (1977). +** +** References: +** +** Kinoshita, H. and Souchay J. 1990, Celest.Mech. and Dyn.Astron. +** 48, 187 +** +** Lieske, J.H., Lederle, T., Fricke, W. & Morando, B. 1977, +** Astron.Astrophys. 58, 1-16 +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* General accumulated precession in longitude. */ + a = (0.024381750 + 0.00000538691 * t) * t; + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fasa03.c b/src/cpp/3rdparty/sofa/src/fasa03.c new file mode 100644 index 000000000..82c3b32f5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fasa03.c @@ -0,0 +1,155 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFasa03(double t) +/* +** - - - - - - - - - - +** i a u F a s a 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Saturn. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Saturn, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** comes from Souchay et al. (1999) after Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Saturn (IERS Conventions 2003). */ + a = fmod(0.874016757 + 21.3299104960 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/faur03.c b/src/cpp/3rdparty/sofa/src/faur03.c new file mode 100644 index 000000000..3d2a7bf36 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/faur03.c @@ -0,0 +1,152 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFaur03(double t) +/* +** - - - - - - - - - - +** i a u F a u r 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Uranus. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Uranus, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** is adapted from Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Uranus (IERS Conventions 2003). */ + a = fmod(5.481293872 + 7.4781598567 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fave03.c b/src/cpp/3rdparty/sofa/src/fave03.c new file mode 100644 index 000000000..967441c03 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fave03.c @@ -0,0 +1,155 @@ +#include "sofa.h" +#include "sofam.h" + +double iauFave03(double t) +/* +** - - - - - - - - - - +** i a u F a v e 0 3 +** - - - - - - - - - - +** +** Fundamental argument, IERS Conventions (2003): +** mean longitude of Venus. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** t double TDB, Julian centuries since J2000.0 (Note 1) +** +** Returned (function value): +** double mean longitude of Venus, radians (Note 2) +** +** Notes: +** +** 1) Though t is strictly TDB, it is usually more convenient to use +** TT, which makes no significant difference. +** +** 2) The expression used is as adopted in IERS Conventions (2003) and +** comes from Souchay et al. (1999) after Simon et al. (1994). +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double a; + + +/* Mean longitude of Venus (IERS Conventions 2003). */ + a = fmod(3.176146697 + 1021.3285546211 * t, D2PI); + + return a; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fk425.c b/src/cpp/3rdparty/sofa/src/fk425.c new file mode 100644 index 000000000..30d59c4c3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fk425.c @@ -0,0 +1,322 @@ +#include "sofa.h" +#include "sofam.h" + +void iauFk425(double r1950, double d1950, + double dr1950, double dd1950, + double p1950, double v1950, + double *r2000, double *d2000, + double *dr2000, double *dd2000, + double *p2000, double *v2000) +/* +** - - - - - - - - - +** i a u F k 4 2 5 +** - - - - - - - - - +** +** Convert B1950.0 FK4 star catalog data to J2000.0 FK5. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** This function converts a star's catalog data from the old FK4 +** (Bessel-Newcomb) system to the later IAU 1976 FK5 (Fricke) system. +** +** Given: (all B1950.0, FK4) +** r1950,d1950 double B1950.0 RA,Dec (rad) +** dr1950,dd1950 double B1950.0 proper motions (rad/trop.yr) +** p1950 double parallax (arcsec) +** v1950 double radial velocity (km/s, +ve = moving away) +** +** Returned: (all J2000.0, FK5) +** r2000,d2000 double J2000.0 RA,Dec (rad) +** dr2000,dd2000 double J2000.0 proper motions (rad/Jul.yr) +** p2000 double parallax (arcsec) +** v2000 double radial velocity (km/s, +ve = moving away) +** +** Notes: +** +** 1) The proper motions in RA are dRA/dt rather than cos(Dec)*dRA/dt, +** and are per year rather than per century. +** +** 2) The conversion is somewhat complicated, for several reasons: +** +** . Change of standard epoch from B1950.0 to J2000.0. +** +** . An intermediate transition date of 1984 January 1.0 TT. +** +** . A change of precession model. +** +** . Change of time unit for proper motion (tropical to Julian). +** +** . FK4 positions include the E-terms of aberration, to simplify +** the hand computation of annual aberration. FK5 positions +** assume a rigorous aberration computation based on the Earth's +** barycentric velocity. +** +** . The E-terms also affect proper motions, and in particular cause +** objects at large distances to exhibit fictitious proper +** motions. +** +** The algorithm is based on Smith et al. (1989) and Yallop et al. +** (1989), which presented a matrix method due to Standish (1982) as +** developed by Aoki et al. (1983), using Kinoshita's development of +** Andoyer's post-Newcomb precession. The numerical constants from +** Seidelmann (1992) are used canonically. +** +** 3) Conversion from B1950.0 FK4 to J2000.0 FK5 only is provided for. +** Conversions for different epochs and equinoxes would require +** additional treatment for precession, proper motion and E-terms. +** +** 4) In the FK4 catalog the proper motions of stars within 10 degrees +** of the poles do not embody differential E-terms effects and +** should, strictly speaking, be handled in a different manner from +** stars outside these regions. However, given the general lack of +** homogeneity of the star data available for routine astrometry, +** the difficulties of handling positions that may have been +** determined from astrometric fields spanning the polar and non- +** polar regions, the likelihood that the differential E-terms +** effect was not taken into account when allowing for proper motion +** in past astrometry, and the undesirability of a discontinuity in +** the algorithm, the decision has been made in this SOFA algorithm +** to include the effects of differential E-terms on the proper +** motions for all stars, whether polar or not. At epoch J2000.0, +** and measuring "on the sky" rather than in terms of RA change, the +** errors resulting from this simplification are less than +** 1 milliarcsecond in position and 1 milliarcsecond per century in +** proper motion. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** iauPv2s pv-vector to spherical coordinates +** iauPdp scalar product of two p-vectors +** iauPvmpv pv-vector minus pv_vector +** iauPvppv pv-vector plus pv_vector +** iauS2pv spherical coordinates to pv-vector +** iauSxp multiply p-vector by scalar +** +** References: +** +** Aoki, S. et al., 1983, "Conversion matrix of epoch B1950.0 +** FK4-based positions of stars to epoch J2000.0 positions in +** accordance with the new IAU resolutions". Astron.Astrophys. +** 128, 263-267. +** +** Seidelmann, P.K. (ed), 1992, "Explanatory Supplement to the +** Astronomical Almanac", ISBN 0-935702-68-7. +** +** Smith, C.A. et al., 1989, "The transformation of astrometric +** catalog systems to the equinox J2000.0". Astron.J. 97, 265. +** +** Standish, E.M., 1982, "Conversion of positions and proper motions +** from B1950.0 to the IAU system at J2000.0". Astron.Astrophys., +** 115, 1, 20-22. +** +** Yallop, B.D. et al., 1989, "Transformation of mean star places +** from FK4 B1950.0 to FK5 J2000.0 using matrices in 6-space". +** Astron.J. 97, 274. +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Radians per year to arcsec per century */ + const double PMF = 100.0*DR2AS; + +/* Small number to avoid arithmetic problems */ + const double TINY = 1e-30; + +/* Miscellaneous */ + double r, d, ur, ud, px, rv, pxvf, w, rd; + int i, j, k, l; + +/* Pv-vectors */ + double r0[2][3], pv1[2][3], pv2[2][3]; + +/* +** CANONICAL CONSTANTS (Seidelmann 1992) +*/ + +/* Km per sec to AU per tropical century */ +/* = 86400 * 36524.2198782 / 149597870.7 */ + const double VF = 21.095; + +/* Constant pv-vector (cf. Seidelmann 3.591-2, vectors A and Adot) */ + static double a[2][3] = { + { -1.62557e-6, -0.31919e-6, -0.13843e-6 }, + { +1.245e-3, -1.580e-3, -0.659e-3 } + }; + +/* 3x2 matrix of pv-vectors (cf. Seidelmann 3.591-4, matrix M) */ + static double em[2][3][2][3] = { + + { { { +0.9999256782, -0.0111820611, -0.0048579477 }, + { +0.00000242395018, -0.00000002710663, -0.00000001177656 } }, + + { { +0.0111820610, +0.9999374784, -0.0000271765 }, + { +0.00000002710663, +0.00000242397878, -0.00000000006587 } }, + + { { +0.0048579479, -0.0000271474, +0.9999881997, }, + { +0.00000001177656, -0.00000000006582, +0.00000242410173 } } }, + + { { { -0.000551, -0.238565, +0.435739 }, + { +0.99994704, -0.01118251, -0.00485767 } }, + + { { +0.238514, -0.002667, -0.008541 }, + { +0.01118251, +0.99995883, -0.00002718 } }, + + { { -0.435623, +0.012254, +0.002117 }, + { +0.00485767, -0.00002714, +1.00000956 } } } + + }; + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* The FK4 data (units radians and arcsec per tropical century). */ + r = r1950; + d = d1950; + ur = dr1950*PMF; + ud = dd1950*PMF; + px = p1950; + rv = v1950; + +/* Express as a pv-vector. */ + pxvf = px*VF; + w = rv*pxvf; + iauS2pv(r, d, 1.0, ur, ud, w, r0); + +/* Allow for E-terms (cf. Seidelmann 3.591-2). */ + iauPvmpv(r0, a, pv1); + iauSxp(iauPdp(r0[0], a[0]), r0[0], pv2[0]); + iauSxp(iauPdp(r0[0], a[1]), r0[0], pv2[1]); + iauPvppv(pv1, pv2, pv1); + +/* Convert pv-vector to Fricke system (cf. Seidelmann 3.591-3). */ + for ( i = 0; i < 2; i++ ) { + for ( j = 0; j < 3; j++ ) { + w = 0.0; + for ( k = 0; k < 2; k++ ) { + for ( l = 0; l < 3; l++ ) { + w += em[i][j][k][l] * pv1[k][l]; + } + } + pv2[i][j] = w; + } + } + +/* Revert to catalog form. */ + iauPv2s(pv2, &r, &d, &w, &ur, &ud, &rd); + if ( px > TINY ) { + rv = rd/pxvf; + px = px/w; + } + +/* Return the results. */ + *r2000 = iauAnp(r); + *d2000 = d; + *dr2000 = ur/PMF; + *dd2000 = ud/PMF; + *v2000 = rv; + *p2000 = px; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fk45z.c b/src/cpp/3rdparty/sofa/src/fk45z.c new file mode 100644 index 000000000..18e32577a --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fk45z.c @@ -0,0 +1,252 @@ +#include "sofa.h" +#include "sofam.h" + +void iauFk45z(double r1950, double d1950, double bepoch, + double *r2000, double *d2000) +/* +** - - - - - - - - - +** i a u F k 4 5 z +** - - - - - - - - - +** +** Convert a B1950.0 FK4 star position to J2000.0 FK5, assuming zero +** proper motion in the FK5 system. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** This function converts a star's catalog data from the old FK4 +** (Bessel-Newcomb) system to the later IAU 1976 FK5 (Fricke) system, +** in such a way that the FK5 proper motion is zero. Because such a +** star has, in general, a non-zero proper motion in the FK4 system, +** the function requires the epoch at which the position in the FK4 +** system was determined. +** +** Given: +** r1950,d1950 double B1950.0 FK4 RA,Dec at epoch (rad) +** bepoch double Besselian epoch (e.g. 1979.3) +** +** Returned: +** r2000,d2000 double J2000.0 FK5 RA,Dec (rad) +** +** Notes: +** +** 1) The epoch bepoch is strictly speaking Besselian, but if a +** Julian epoch is supplied the result will be affected only to a +** negligible extent. +** +** 2) The method is from Appendix 2 of Aoki et al. (1983), but using +** the constants of Seidelmann (1992). See the function iauFk425 +** for a general introduction to the FK4 to FK5 conversion. +** +** 3) Conversion from equinox B1950.0 FK4 to equinox J2000.0 FK5 only +** is provided for. Conversions for different starting and/or +** ending epochs would require additional treatment for precession, +** proper motion and E-terms. +** +** 4) In the FK4 catalog the proper motions of stars within 10 degrees +** of the poles do not embody differential E-terms effects and +** should, strictly speaking, be handled in a different manner from +** stars outside these regions. However, given the general lack of +** homogeneity of the star data available for routine astrometry, +** the difficulties of handling positions that may have been +** determined from astrometric fields spanning the polar and non- +** polar regions, the likelihood that the differential E-terms +** effect was not taken into account when allowing for proper motion +** in past astrometry, and the undesirability of a discontinuity in +** the algorithm, the decision has been made in this SOFA algorithm +** to include the effects of differential E-terms on the proper +** motions for all stars, whether polar or not. At epoch 2000.0, +** and measuring "on the sky" rather than in terms of RA change, the +** errors resulting from this simplification are less than +** 1 milliarcsecond in position and 1 milliarcsecond per century in +** proper motion. +** +** References: +** +** Aoki, S. et al., 1983, "Conversion matrix of epoch B1950.0 +** FK4-based positions of stars to epoch J2000.0 positions in +** accordance with the new IAU resolutions". Astron.Astrophys. +** 128, 263-267. +** +** Seidelmann, P.K. (ed), 1992, "Explanatory Supplement to the +** Astronomical Almanac", ISBN 0-935702-68-7. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** iauC2s p-vector to spherical +** iauEpb2jd Besselian epoch to Julian date +** iauEpj Julian date to Julian epoch +** iauPdp scalar product of two p-vectors +** iauPmp p-vector minus p-vector +** iauPpsp p-vector plus scaled p-vector +** iauPvu update a pv-vector +** iauS2c spherical to p-vector +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Radians per year to arcsec per century */ + const double PMF = 100.0*DR2AS; + +/* Position and position+velocity vectors */ + double r0[3], p[3], pv[2][3]; + +/* Miscellaneous */ + double w, djm0, djm; + int i, j, k; + +/* +** CANONICAL CONSTANTS (Seidelmann 1992) +*/ + +/* Vectors A and Adot (Seidelmann 3.591-2) */ + static double a[3] = { -1.62557e-6, -0.31919e-6, -0.13843e-6 }; + static double ad[3] = { +1.245e-3, -1.580e-3, -0.659e-3 }; + +/* 3x2 matrix of p-vectors (cf. Seidelmann 3.591-4, matrix M) */ + static double em[2][3][3] = { + { { +0.9999256782, -0.0111820611, -0.0048579477 }, + { +0.0111820610, +0.9999374784, -0.0000271765 }, + { +0.0048579479, -0.0000271474, +0.9999881997 } }, + { { -0.000551, -0.238565, +0.435739 }, + { +0.238514, -0.002667, -0.008541 }, + { -0.435623, +0.012254, +0.002117 } } + }; + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* Spherical coordinates to p-vector. */ + iauS2c(r1950, d1950, r0); + +/* Adjust p-vector A to give zero proper motion in FK5. */ + w = (bepoch - 1950) / PMF; + iauPpsp(a, w, ad, p); + +/* Remove E-terms. */ + iauPpsp(p, -iauPdp(r0,p), r0, p); + iauPmp(r0, p, p); + +/* Convert to Fricke system pv-vector (cf. Seidelmann 3.591-3). */ + for ( i = 0; i < 2; i++ ) { + for ( j = 0; j < 3; j++ ) { + w = 0.0; + for ( k = 0; k < 3; k++ ) { + w += em[i][j][k] * p[k]; + } + pv[i][j] = w; + } + } + +/* Allow for fictitious proper motion. */ + iauEpb2jd(bepoch, &djm0, &djm); + w = (iauEpj(djm0,djm)-2000.0) / PMF; + iauPvu(w, pv, pv); + +/* Revert to spherical coordinates. */ + iauC2s(pv[0], &w, d2000); + *r2000 = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fk524.c b/src/cpp/3rdparty/sofa/src/fk524.c new file mode 100644 index 000000000..bd50a7576 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fk524.c @@ -0,0 +1,334 @@ +#include "sofa.h" +#include "sofam.h" + +void iauFk524(double r2000, double d2000, + double dr2000, double dd2000, + double p2000, double v2000, + double *r1950, double *d1950, + double *dr1950, double *dd1950, + double *p1950, double *v1950) +/* +** - - - - - - - - - +** i a u F k 5 2 4 +** - - - - - - - - - +** +** Convert J2000.0 FK5 star catalog data to B1950.0 FK4. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: (all J2000.0, FK5) +** r2000,d2000 double J2000.0 RA,Dec (rad) +** dr2000,dd2000 double J2000.0 proper motions (rad/Jul.yr) +** p2000 double parallax (arcsec) +** v2000 double radial velocity (km/s, +ve = moving away) +** +** Returned: (all B1950.0, FK4) +** r1950,d1950 double B1950.0 RA,Dec (rad) +** dr1950,dd1950 double B1950.0 proper motions (rad/trop.yr) +** p1950 double parallax (arcsec) +** v1950 double radial velocity (km/s, +ve = moving away) +** +** Notes: +** +** 1) The proper motions in RA are dRA/dt rather than cos(Dec)*dRA/dt, +** and are per year rather than per century. +** +** 2) The conversion is somewhat complicated, for several reasons: +** +** . Change of standard epoch from J2000.0 to B1950.0. +** +** . An intermediate transition date of 1984 January 1.0 TT. +** +** . A change of precession model. +** +** . Change of time unit for proper motion (Julian to tropical). +** +** . FK4 positions include the E-terms of aberration, to simplify +** the hand computation of annual aberration. FK5 positions +** assume a rigorous aberration computation based on the Earth's +** barycentric velocity. +** +** . The E-terms also affect proper motions, and in particular cause +** objects at large distances to exhibit fictitious proper +** motions. +** +** The algorithm is based on Smith et al. (1989) and Yallop et al. +** (1989), which presented a matrix method due to Standish (1982) as +** developed by Aoki et al. (1983), using Kinoshita's development of +** Andoyer's post-Newcomb precession. The numerical constants from +** Seidelmann (1992) are used canonically. +** +** 4) In the FK4 catalog the proper motions of stars within 10 degrees +** of the poles do not embody differential E-terms effects and +** should, strictly speaking, be handled in a different manner from +** stars outside these regions. However, given the general lack of +** homogeneity of the star data available for routine astrometry, +** the difficulties of handling positions that may have been +** determined from astrometric fields spanning the polar and non- +** polar regions, the likelihood that the differential E-terms +** effect was not taken into account when allowing for proper motion +** in past astrometry, and the undesirability of a discontinuity in +** the algorithm, the decision has been made in this SOFA algorithm +** to include the effects of differential E-terms on the proper +** motions for all stars, whether polar or not. At epoch J2000.0, +** and measuring "on the sky" rather than in terms of RA change, the +** errors resulting from this simplification are less than +** 1 milliarcsecond in position and 1 milliarcsecond per century in +** proper motion. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** iauPdp scalar product of two p-vectors +** iauPm modulus of p-vector +** iauPmp p-vector minus p-vector +** iauPpp p-vector pluus p-vector +** iauPv2s pv-vector to spherical coordinates +** iauS2pv spherical coordinates to pv-vector +** iauSxp multiply p-vector by scalar +** +** References: +** +** Aoki, S. et al., 1983, "Conversion matrix of epoch B1950.0 +** FK4-based positions of stars to epoch J2000.0 positions in +** accordance with the new IAU resolutions". Astron.Astrophys. +** 128, 263-267. +** +** Seidelmann, P.K. (ed), 1992, "Explanatory Supplement to the +** Astronomical Almanac", ISBN 0-935702-68-7. +** +** Smith, C.A. et al., 1989, "The transformation of astrometric +** catalog systems to the equinox J2000.0". Astron.J. 97, 265. +** +** Standish, E.M., 1982, "Conversion of positions and proper motions +** from B1950.0 to the IAU system at J2000.0". Astron.Astrophys., +** 115, 1, 20-22. +** +** Yallop, B.D. et al., 1989, "Transformation of mean star places +** from FK4 B1950.0 to FK5 J2000.0 using matrices in 6-space". +** Astron.J. 97, 274. +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Radians per year to arcsec per century */ + const double PMF = 100.0*DR2AS; + +/* Small number to avoid arithmetic problems */ + const double TINY = 1e-30; + +/* Miscellaneous */ + double r, d, ur, ud, px, rv, pxvf, w, rd; + int i, j, k, l; + +/* Vectors, p and pv */ + double r0[2][3], r1[2][3], p1[3], p2[3], pv[2][3]; + +/* +** CANONICAL CONSTANTS (Seidelmann 1992) +*/ + +/* Km per sec to AU per tropical century */ +/* = 86400 * 36524.2198782 / 149597870.7 */ + const double VF = 21.095; + +/* Constant pv-vector (cf. Seidelmann 3.591-2, vectors A and Adot) */ + static double a[2][3] = { + { -1.62557e-6, -0.31919e-6, -0.13843e-6 }, + { +1.245e-3, -1.580e-3, -0.659e-3 } + }; + +/* 3x2 matrix of pv-vectors (cf. Seidelmann 3.592-1, matrix M^-1) */ + static double em[2][3][2][3] = { + + { { { +0.9999256795, +0.0111814828, +0.0048590039, }, + { -0.00000242389840, -0.00000002710544, -0.00000001177742 } }, + + { { -0.0111814828, +0.9999374849, -0.0000271771, }, + { +0.00000002710544, -0.00000242392702, +0.00000000006585 } }, + + { { -0.0048590040, -0.0000271557, +0.9999881946, }, + { +0.00000001177742, +0.00000000006585, -0.00000242404995 } } }, + + { { { -0.000551, +0.238509, -0.435614, }, + { +0.99990432, +0.01118145, +0.00485852 } }, + + { { -0.238560, -0.002667, +0.012254, }, + { -0.01118145, +0.99991613, -0.00002717 } }, + + { { +0.435730, -0.008541, +0.002117, }, + { -0.00485852, -0.00002716, +0.99996684 } } } + + }; + +/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* The FK5 data (units radians and arcsec per Julian century). */ + r = r2000; + d = d2000; + ur = dr2000*PMF; + ud = dd2000*PMF; + px = p2000; + rv = v2000; + +/* Express as a pv-vector. */ + pxvf = px * VF; + w = rv * pxvf; + iauS2pv(r, d, 1.0, ur, ud, w, r0); + +/* Convert pv-vector to Bessel-Newcomb system (cf. Seidelmann 3.592-1). */ + for ( i = 0; i < 2; i++ ) { + for ( j = 0; j < 3; j++ ) { + w = 0.0; + for ( k = 0; k < 2; k++ ) { + for ( l = 0; l < 3; l++ ) { + w += em[i][j][k][l] * r0[k][l]; + } + } + r1[i][j] = w; + } + } + +/* Apply E-terms (equivalent to Seidelmann 3.592-3, one iteration). */ + +/* Direction. */ + w = iauPm(r1[0]); + iauSxp(iauPdp(r1[0],a[0]), r1[0], p1); + iauSxp(w, a[0], p2); + iauPmp(p2, p1, p1); + iauPpp(r1[0], p1, p1); + +/* Recompute length. */ + w = iauPm(p1); + +/* Direction. */ + iauSxp(iauPdp(r1[0],a[0]), r1[0], p1); + iauSxp(w, a[0], p2); + iauPmp(p2, p1, p1); + iauPpp(r1[0], p1, pv[0]); + +/* Derivative. */ + iauSxp(iauPdp(r1[0],a[1]), pv[0], p1); + iauSxp(w, a[1], p2); + iauPmp(p2, p1, p1); + iauPpp(r1[1], p1, pv[1]); + +/* Revert to catalog form. */ + iauPv2s(pv, &r, &d, &w, &ur, &ud, &rd); + if ( px > TINY ) { + rv = rd/pxvf; + px = px/w; + } + +/* Return the results. */ + *r1950 = iauAnp(r); + *d1950 = d; + *dr1950 = ur/PMF; + *dd1950 = ud/PMF; + *p1950 = px; + *v1950 = rv; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fk52h.c b/src/cpp/3rdparty/sofa/src/fk52h.c new file mode 100644 index 000000000..3d091117e --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fk52h.c @@ -0,0 +1,193 @@ +#include "sofa.h" + +void iauFk52h(double r5, double d5, + double dr5, double dd5, double px5, double rv5, + double *rh, double *dh, + double *drh, double *ddh, double *pxh, double *rvh) +/* +** - - - - - - - - - +** i a u F k 5 2 h +** - - - - - - - - - +** +** Transform FK5 (J2000.0) star data into the Hipparcos system. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given (all FK5, equinox J2000.0, epoch J2000.0): +** r5 double RA (radians) +** d5 double Dec (radians) +** dr5 double proper motion in RA (dRA/dt, rad/Jyear) +** dd5 double proper motion in Dec (dDec/dt, rad/Jyear) +** px5 double parallax (arcsec) +** rv5 double radial velocity (km/s, positive = receding) +** +** Returned (all Hipparcos, epoch J2000.0): +** rh double RA (radians) +** dh double Dec (radians) +** drh double proper motion in RA (dRA/dt, rad/Jyear) +** ddh double proper motion in Dec (dDec/dt, rad/Jyear) +** pxh double parallax (arcsec) +** rvh double radial velocity (km/s, positive = receding) +** +** Notes: +** +** 1) This function transforms FK5 star positions and proper motions +** into the system of the Hipparcos catalog. +** +** 2) The proper motions in RA are dRA/dt rather than +** cos(Dec)*dRA/dt, and are per year rather than per century. +** +** 3) The FK5 to Hipparcos transformation is modeled as a pure +** rotation and spin; zonal errors in the FK5 catalog are not +** taken into account. +** +** 4) See also iauH2fk5, iauFk5hz, iauHfk5z. +** +** Called: +** iauStarpv star catalog data to space motion pv-vector +** iauFk5hip FK5 to Hipparcos rotation and spin +** iauRxp product of r-matrix and p-vector +** iauPxp vector product of two p-vectors +** iauPpp p-vector plus p-vector +** iauPvstar space motion pv-vector to star catalog data +** +** Reference: +** +** F.Mignard & M.Froeschle, Astron.Astrophys., 354, 732-739 (2000). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int i; + double pv5[2][3], r5h[3][3], s5h[3], wxp[3], vv[3], pvh[2][3]; + + +/* FK5 barycentric position/velocity pv-vector (normalized). */ + iauStarpv(r5, d5, dr5, dd5, px5, rv5, pv5); + +/* FK5 to Hipparcos orientation matrix and spin vector. */ + iauFk5hip(r5h, s5h); + +/* Make spin units per day instead of per year. */ + for ( i = 0; i < 3; s5h[i++] /= 365.25 ); + +/* Orient the FK5 position into the Hipparcos system. */ + iauRxp(r5h, pv5[0], pvh[0]); + +/* Apply spin to the position giving an extra space motion component. */ + iauPxp(pv5[0], s5h, wxp); + +/* Add this component to the FK5 space motion. */ + iauPpp(wxp, pv5[1], vv); + +/* Orient the FK5 space motion into the Hipparcos system. */ + iauRxp(r5h, vv, pvh[1]); + +/* Hipparcos pv-vector to spherical. */ + iauPvstar(pvh, rh, dh, drh, ddh, pxh, rvh); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fk54z.c b/src/cpp/3rdparty/sofa/src/fk54z.c new file mode 100644 index 000000000..3e2076235 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fk54z.c @@ -0,0 +1,193 @@ +#include "sofa.h" + +void iauFk54z(double r2000, double d2000, double bepoch, + double *r1950, double *d1950, + double *dr1950, double *dd1950) +/* +** - - - - - - - - - +** i a u F k 5 4 z +** - - - - - - - - - +** +** Convert a J2000.0 FK5 star position to B1950.0 FK4, assuming zero +** proper motion in FK5 and parallax. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** r2000,d2000 double J2000.0 FK5 RA,Dec (rad) +** bepoch double Besselian epoch (e.g. 1950.0) +** +** Returned: +** r1950,d1950 double B1950.0 FK4 RA,Dec (rad) at epoch BEPOCH +** dr1950,dd1950 double B1950.0 FK4 proper motions (rad/trop.yr) +** +** Notes: +** +** 1) In contrast to the iauFk524 function, here the FK5 proper +** motions, the parallax and the radial velocity are presumed zero. +** +** 2) This function converts a star position from the IAU 1976 FK5 +** (Fricke) system to the former FK4 (Bessel-Newcomb) system, for +** cases such as distant radio sources where it is presumed there is +** zero parallax and no proper motion. Because of the E-terms of +** aberration, such objects have (in general) non-zero proper motion +** in FK4, and the present function returns those fictitious proper +** motions. +** +** 3) Conversion from B1950.0 FK4 to J2000.0 FK5 only is provided for. +** Conversions involving other equinoxes would require additional +** treatment for precession. +** +** 4) The position returned by this function is in the B1950.0 FK4 +** reference system but at Besselian epoch BEPOCH. For comparison +** with catalogs the BEPOCH argument will frequently be 1950.0. (In +** this context the distinction between Besselian and Julian epoch +** is insignificant.) +** +** 5) The RA component of the returned (fictitious) proper motion is +** dRA/dt rather than cos(Dec)*dRA/dt. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** iauC2s p-vector to spherical +** iauFk524 FK4 to FK5 +** iauS2c spherical to p-vector +** +** This revision: 2020 November 19 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r, d, pr, pd, px, rv, p[3], w, v[3]; + int i; + + +/* FK5 equinox J2000.0 to FK4 equinox B1950.0. */ + iauFk524(r2000, d2000, 0.0, 0.0, 0.0, 0.0, + &r, &d, &pr, &pd, &px, &rv); + +/* Spherical to Cartesian. */ + iauS2c(r, d, p); + +/* Fictitious proper motion (radians per year). */ + v[0] = - pr*p[1] - pd*cos(r)*sin(d); + v[1] = pr*p[0] - pd*sin(r)*sin(d); + v[2] = pd*cos(d); + +/* Apply the motion. */ + w = bepoch - 1950.0; + for ( i = 0; i < 3; i++ ) { + p[i] += w*v[i]; + } + +/* Cartesian to spherical. */ + iauC2s(p, &w, d1950); + *r1950 = iauAnp(w); + +/* Fictitious proper motion. */ + *dr1950 = pr; + *dd1950 = pd; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fk5hip.c b/src/cpp/3rdparty/sofa/src/fk5hip.c new file mode 100644 index 000000000..d423915f5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fk5hip.c @@ -0,0 +1,177 @@ +#include "sofa.h" +#include "sofam.h" + +void iauFk5hip(double r5h[3][3], double s5h[3]) +/* +** - - - - - - - - - - +** i a u F k 5 h i p +** - - - - - - - - - - +** +** FK5 to Hipparcos rotation and spin. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Returned: +** r5h double[3][3] r-matrix: FK5 rotation wrt Hipparcos (Note 2) +** s5h double[3] r-vector: FK5 spin wrt Hipparcos (Note 3) +** +** Notes: +** +** 1) This function models the FK5 to Hipparcos transformation as a +** pure rotation and spin; zonal errors in the FK5 catalogue are +** not taken into account. +** +** 2) The r-matrix r5h operates in the sense: +** +** P_Hipparcos = r5h x P_FK5 +** +** where P_FK5 is a p-vector in the FK5 frame, and P_Hipparcos is +** the equivalent Hipparcos p-vector. +** +** 3) The r-vector s5h represents the time derivative of the FK5 to +** Hipparcos rotation. The units are radians per year (Julian, +** TDB). +** +** Called: +** iauRv2m r-vector to r-matrix +** +** Reference: +** +** F.Mignard & M.Froeschle, Astron.Astrophys., 354, 732-739 (2000). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double v[3]; + +/* FK5 wrt Hipparcos orientation and spin (radians, radians/year) */ + double epx, epy, epz; + double omx, omy, omz; + + + epx = -19.9e-3 * DAS2R; + epy = -9.1e-3 * DAS2R; + epz = 22.9e-3 * DAS2R; + + omx = -0.30e-3 * DAS2R; + omy = 0.60e-3 * DAS2R; + omz = 0.70e-3 * DAS2R; + +/* FK5 to Hipparcos orientation expressed as an r-vector. */ + v[0] = epx; + v[1] = epy; + v[2] = epz; + +/* Re-express as an r-matrix. */ + iauRv2m(v, r5h); + +/* Hipparcos wrt FK5 spin expressed as an r-vector. */ + s5h[0] = omx; + s5h[1] = omy; + s5h[2] = omz; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fk5hz.c b/src/cpp/3rdparty/sofa/src/fk5hz.c new file mode 100644 index 000000000..85101eb65 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fk5hz.c @@ -0,0 +1,211 @@ +#include "sofa.h" +#include "sofam.h" + +void iauFk5hz(double r5, double d5, double date1, double date2, + double *rh, double *dh) +/* +** - - - - - - - - - +** i a u F k 5 h z +** - - - - - - - - - +** +** Transform an FK5 (J2000.0) star position into the system of the +** Hipparcos catalogue, assuming zero Hipparcos proper motion. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** r5 double FK5 RA (radians), equinox J2000.0, at date +** d5 double FK5 Dec (radians), equinox J2000.0, at date +** date1,date2 double TDB date (Notes 1,2) +** +** Returned: +** rh double Hipparcos RA (radians) +** dh double Hipparcos Dec (radians) +** +** Notes: +** +** 1) This function converts a star position from the FK5 system to +** the Hipparcos system, in such a way that the Hipparcos proper +** motion is zero. Because such a star has, in general, a non-zero +** proper motion in the FK5 system, the function requires the date +** at which the position in the FK5 system was determined. +** +** 2) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 3) The FK5 to Hipparcos transformation is modeled as a pure +** rotation and spin; zonal errors in the FK5 catalogue are not +** taken into account. +** +** 4) The position returned by this function is in the Hipparcos +** reference system but at date date1+date2. +** +** 5) See also iauFk52h, iauH2fk5, iauHfk5z. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauFk5hip FK5 to Hipparcos rotation and spin +** iauSxp multiply p-vector by scalar +** iauRv2m r-vector to r-matrix +** iauTrxp product of transpose of r-matrix and p-vector +** iauPxp vector product of two p-vectors +** iauC2s p-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** Reference: +** +** F.Mignard & M.Froeschle, 2000, Astron.Astrophys. 354, 732-739. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, p5e[3], r5h[3][3], s5h[3], vst[3], rst[3][3], p5[3], + ph[3], w; + + +/* Interval from given date to fundamental epoch J2000.0 (JY). */ + t = - ((date1 - DJ00) + date2) / DJY; + +/* FK5 barycentric position vector. */ + iauS2c(r5, d5, p5e); + +/* FK5 to Hipparcos orientation matrix and spin vector. */ + iauFk5hip(r5h, s5h); + +/* Accumulated Hipparcos wrt FK5 spin over that interval. */ + iauSxp(t, s5h, vst); + +/* Express the accumulated spin as a rotation matrix. */ + iauRv2m(vst, rst); + +/* Derotate the vector's FK5 axes back to date. */ + iauTrxp(rst, p5e, p5); + +/* Rotate the vector into the Hipparcos system. */ + iauRxp(r5h, p5, ph); + +/* Hipparcos vector to spherical. */ + iauC2s(ph, &w, dh); + *rh = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fw2m.c b/src/cpp/3rdparty/sofa/src/fw2m.c new file mode 100644 index 000000000..560769f78 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fw2m.c @@ -0,0 +1,189 @@ +#include "sofa.h" + +void iauFw2m(double gamb, double phib, double psi, double eps, + double r[3][3]) +/* +** - - - - - - - - +** i a u F w 2 m +** - - - - - - - - +** +** Form rotation matrix given the Fukushima-Williams angles. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** gamb double F-W angle gamma_bar (radians) +** phib double F-W angle phi_bar (radians) +** psi double F-W angle psi (radians) +** eps double F-W angle epsilon (radians) +** +** Returned: +** r double[3][3] rotation matrix +** +** Notes: +** +** 1) Naming the following points: +** +** e = J2000.0 ecliptic pole, +** p = GCRS pole, +** E = ecliptic pole of date, +** and P = CIP, +** +** the four Fukushima-Williams angles are as follows: +** +** gamb = gamma = epE +** phib = phi = pE +** psi = psi = pEP +** eps = epsilon = EP +** +** 2) The matrix representing the combined effects of frame bias, +** precession and nutation is: +** +** NxPxB = R_1(-eps).R_3(-psi).R_1(phib).R_3(gamb) +** +** 3) The present function can construct three different matrices, +** depending on which angles are supplied as the arguments gamb, +** phib, psi and eps: +** +** o To obtain the nutation x precession x frame bias matrix, +** first generate the four precession angles known conventionally +** as gamma_bar, phi_bar, psi_bar and epsilon_A, then generate +** the nutation components Dpsi and Depsilon and add them to +** psi_bar and epsilon_A, and finally call the present function +** using those four angles as arguments. +** +** o To obtain the precession x frame bias matrix, generate the +** four precession angles and call the present function. +** +** o To obtain the frame bias matrix, generate the four precession +** angles for date J2000.0 and call the present function. +** +** The nutation-only and precession-only matrices can if necessary +** be obtained by combining these three appropriately. +** +** Called: +** iauIr initialize r-matrix to identity +** iauRz rotate around Z-axis +** iauRx rotate around X-axis +** +** References: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Construct the matrix. */ + iauIr(r); + iauRz(gamb, r); + iauRx(phib, r); + iauRz(-psi, r); + iauRx(-eps, r); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/fw2xy.c b/src/cpp/3rdparty/sofa/src/fw2xy.c new file mode 100644 index 000000000..864dfb39d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/fw2xy.c @@ -0,0 +1,171 @@ +#include "sofa.h" + +void iauFw2xy(double gamb, double phib, double psi, double eps, + double *x, double *y) +/* +** - - - - - - - - - +** i a u F w 2 x y +** - - - - - - - - - +** +** CIP X,Y given Fukushima-Williams bias-precession-nutation angles. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** gamb double F-W angle gamma_bar (radians) +** phib double F-W angle phi_bar (radians) +** psi double F-W angle psi (radians) +** eps double F-W angle epsilon (radians) +** +** Returned: +** x,y double CIP unit vector X,Y +** +** Notes: +** +** 1) Naming the following points: +** +** e = J2000.0 ecliptic pole, +** p = GCRS pole +** E = ecliptic pole of date, +** and P = CIP, +** +** the four Fukushima-Williams angles are as follows: +** +** gamb = gamma = epE +** phib = phi = pE +** psi = psi = pEP +** eps = epsilon = EP +** +** 2) The matrix representing the combined effects of frame bias, +** precession and nutation is: +** +** NxPxB = R_1(-epsA).R_3(-psi).R_1(phib).R_3(gamb) +** +** The returned values x,y are elements [2][0] and [2][1] of the +** matrix. Near J2000.0, they are essentially angles in radians. +** +** Called: +** iauFw2m F-W angles to r-matrix +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** +** Reference: +** +** Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r[3][3]; + + +/* Form NxPxB matrix. */ + iauFw2m(gamb, phib, psi, eps, r); + +/* Extract CIP X,Y. */ + iauBpn2xy(r, x, y); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/g2icrs.c b/src/cpp/3rdparty/sofa/src/g2icrs.c new file mode 100644 index 000000000..03df80672 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/g2icrs.c @@ -0,0 +1,212 @@ + +#include "sofa.h" + +void iauG2icrs ( double dl, double db, double *dr, double *dd ) +/* +** - - - - - - - - - - +** i a u G 2 i c r s +** - - - - - - - - - - +** +** Transformation from Galactic Coordinates to ICRS. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** dl double galactic longitude (radians) +** db double galactic latitude (radians) +** +** Returned: +** dr double ICRS right ascension (radians) +** dd double ICRS declination (radians) +** +** Notes: +** +** 1) The IAU 1958 system of Galactic coordinates was defined with +** respect to the now obsolete reference system FK4 B1950.0. When +** interpreting the system in a modern context, several factors have +** to be taken into account: +** +** . The inclusion in FK4 positions of the E-terms of aberration. +** +** . The distortion of the FK4 proper motion system by differential +** Galactic rotation. +** +** . The use of the B1950.0 equinox rather than the now-standard +** J2000.0. +** +** . The frame bias between ICRS and the J2000.0 mean place system. +** +** The Hipparcos Catalogue (Perryman & ESA 1997) provides a rotation +** matrix that transforms directly between ICRS and Galactic +** coordinates with the above factors taken into account. The +** matrix is derived from three angles, namely the ICRS coordinates +** of the Galactic pole and the longitude of the ascending node of +** the galactic equator on the ICRS equator. They are given in +** degrees to five decimal places and for canonical purposes are +** regarded as exact. In the Hipparcos Catalogue the matrix +** elements are given to 10 decimal places (about 20 microarcsec). +** In the present SOFA function the matrix elements have been +** recomputed from the canonical three angles and are given to 30 +** decimal places. +** +** 2) The inverse transformation is performed by the function iauIcrs2g. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** iauAnpm normalize angle into range +/- pi +** iauS2c spherical coordinates to unit vector +** iauTrxp product of transpose of r-matrix and p-vector +** iauC2s p-vector to spherical +** +** Reference: +** Perryman M.A.C. & ESA, 1997, ESA SP-1200, The Hipparcos and Tycho +** catalogues. Astrometric and photometric star catalogues +** derived from the ESA Hipparcos Space Astrometry Mission. ESA +** Publications Division, Noordwijk, Netherlands. +** +** This revision: 2021 January 25 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double v1[3], v2[3]; + +/* +** L2,B2 system of galactic coordinates in the form presented in the +** Hipparcos Catalogue. In degrees: +** +** P = 192.85948 right ascension of the Galactic north pole in ICRS +** Q = 27.12825 declination of the Galactic north pole in ICRS +** R = 32.93192 Galactic longitude of the ascending node of +** the Galactic equator on the ICRS equator +** +** ICRS to galactic rotation matrix, obtained by computing +** R_3(-R) R_1(pi/2-Q) R_3(pi/2+P) to the full precision shown: +*/ + double r[3][3] = { { -0.054875560416215368492398900454, + -0.873437090234885048760383168409, + -0.483835015548713226831774175116 }, + { +0.494109427875583673525222371358, + -0.444829629960011178146614061616, + +0.746982244497218890527388004556 }, + { -0.867666149019004701181616534570, + -0.198076373431201528180486091412, + +0.455983776175066922272100478348 } }; + + +/* Spherical to Cartesian. */ + iauS2c(dl, db, v1); + +/* Galactic to ICRS. */ + iauTrxp(r, v1, v2); + +/* Cartesian to spherical. */ + iauC2s(v2, dr, dd); + +/* Express in conventional ranges. */ + *dr = iauAnp(*dr); + *dd = iauAnpm(*dd); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gc2gd.c b/src/cpp/3rdparty/sofa/src/gc2gd.c new file mode 100644 index 000000000..62fbd433a --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gc2gd.c @@ -0,0 +1,187 @@ +#include "sofa.h" +#include "sofam.h" + +int iauGc2gd ( int n, double xyz[3], + double *elong, double *phi, double *height ) +/* +** - - - - - - - - - +** i a u G c 2 g d +** - - - - - - - - - +** +** Transform geocentric coordinates to geodetic using the specified +** reference ellipsoid. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical transformation. +** +** Given: +** n int ellipsoid identifier (Note 1) +** xyz double[3] geocentric vector (Note 2) +** +** Returned: +** elong double longitude (radians, east +ve, Note 3) +** phi double latitude (geodetic, radians, Note 3) +** height double height above ellipsoid (geodetic, Notes 2,3) +** +** Returned (function value): +** int status: 0 = OK +** -1 = illegal identifier (Note 3) +** -2 = internal error (Note 3) +** +** Notes: +** +** 1) The identifier n is a number that specifies the choice of +** reference ellipsoid. The following are supported: +** +** n ellipsoid +** +** 1 WGS84 +** 2 GRS80 +** 3 WGS72 +** +** The n value has no significance outside the SOFA software. For +** convenience, symbols WGS84 etc. are defined in sofam.h. +** +** 2) The geocentric vector (xyz, given) and height (height, returned) +** are in meters. +** +** 3) An error status -1 means that the identifier n is illegal. An +** error status -2 is theoretically impossible. In all error cases, +** all three results are set to -1e9. +** +** 4) The inverse transformation is performed in the function iauGd2gc. +** +** Called: +** iauEform Earth reference ellipsoids +** iauGc2gde geocentric to geodetic transformation, general +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + double a, f; + + +/* Obtain reference ellipsoid parameters. */ + j = iauEform ( n, &a, &f ); + +/* If OK, transform x,y,z to longitude, geodetic latitude, height. */ + if ( j == 0 ) { + j = iauGc2gde ( a, f, xyz, elong, phi, height ); + if ( j < 0 ) j = -2; + } + +/* Deal with any errors. */ + if ( j < 0 ) { + *elong = -1e9; + *phi = -1e9; + *height = -1e9; + } + +/* Return the status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gc2gde.c b/src/cpp/3rdparty/sofa/src/gc2gde.c new file mode 100644 index 000000000..caa3c1367 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gc2gde.c @@ -0,0 +1,252 @@ +#include "sofa.h" +#include "sofam.h" + +int iauGc2gde ( double a, double f, double xyz[3], + double *elong, double *phi, double *height ) +/* +** - - - - - - - - - - +** i a u G c 2 g d e +** - - - - - - - - - - +** +** Transform geocentric coordinates to geodetic for a reference +** ellipsoid of specified form. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** a double equatorial radius (Notes 2,4) +** f double flattening (Note 3) +** xyz double[3] geocentric vector (Note 4) +** +** Returned: +** elong double longitude (radians, east +ve) +** phi double latitude (geodetic, radians) +** height double height above ellipsoid (geodetic, Note 4) +** +** Returned (function value): +** int status: 0 = OK +** -1 = illegal f +** -2 = illegal a +** +** Notes: +** +** 1) This function is based on the GCONV2H Fortran subroutine by +** Toshio Fukushima (see reference). +** +** 2) The equatorial radius, a, can be in any units, but meters is +** the conventional choice. +** +** 3) The flattening, f, is (for the Earth) a value around 0.00335, +** i.e. around 1/298. +** +** 4) The equatorial radius, a, and the geocentric vector, xyz, +** must be given in the same units, and determine the units of +** the returned height, height. +** +** 5) If an error occurs (status < 0), elong, phi and height are +** unchanged. +** +** 6) The inverse transformation is performed in the function +** iauGd2gce. +** +** 7) The transformation for a standard ellipsoid (such as WGS84) can +** more conveniently be performed by calling iauGc2gd, which uses a +** numerical code to identify the required A and F values. +** +** Reference: +** +** Fukushima, T., "Transformation from Cartesian to geodetic +** coordinates accelerated by Halley's method", J.Geodesy (2006) +** 79: 689-693 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double aeps2, e2, e4t, ec2, ec, b, x, y, z, p2, absz, p, s0, pn, zc, + c0, c02, c03, s02, s03, a02, a0, a03, d0, f0, b0, s1, + cc, s12, cc2; + + +/* ------------- */ +/* Preliminaries */ +/* ------------- */ + +/* Validate ellipsoid parameters. */ + if ( f < 0.0 || f >= 1.0 ) return -1; + if ( a <= 0.0 ) return -2; + +/* Functions of ellipsoid parameters (with further validation of f). */ + aeps2 = a*a * 1e-32; + e2 = (2.0 - f) * f; + e4t = e2*e2 * 1.5; + ec2 = 1.0 - e2; + if ( ec2 <= 0.0 ) return -1; + ec = sqrt(ec2); + b = a * ec; + +/* Cartesian components. */ + x = xyz[0]; + y = xyz[1]; + z = xyz[2]; + +/* Distance from polar axis squared. */ + p2 = x*x + y*y; + +/* Longitude. */ + *elong = p2 > 0.0 ? atan2(y, x) : 0.0; + +/* Unsigned z-coordinate. */ + absz = fabs(z); + +/* Proceed unless polar case. */ + if ( p2 > aeps2 ) { + + /* Distance from polar axis. */ + p = sqrt(p2); + + /* Normalization. */ + s0 = absz / a; + pn = p / a; + zc = ec * s0; + + /* Prepare Newton correction factors. */ + c0 = ec * pn; + c02 = c0 * c0; + c03 = c02 * c0; + s02 = s0 * s0; + s03 = s02 * s0; + a02 = c02 + s02; + a0 = sqrt(a02); + a03 = a02 * a0; + d0 = zc*a03 + e2*s03; + f0 = pn*a03 - e2*c03; + + /* Prepare Halley correction factor. */ + b0 = e4t * s02 * c02 * pn * (a0 - ec); + s1 = d0*f0 - b0*s0; + cc = ec * (f0*f0 - b0*c0); + + /* Evaluate latitude and height. */ + *phi = atan(s1/cc); + s12 = s1 * s1; + cc2 = cc * cc; + *height = (p*cc + absz*s1 - a * sqrt(ec2*s12 + cc2)) / + sqrt(s12 + cc2); + } else { + + /* Exception: pole. */ + *phi = DPI / 2.0; + *height = absz - b; + } + +/* Restore sign of latitude. */ + if ( z < 0 ) *phi = -*phi; + +/* OK status. */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gd2gc.c b/src/cpp/3rdparty/sofa/src/gd2gc.c new file mode 100644 index 000000000..a14324902 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gd2gc.c @@ -0,0 +1,186 @@ +#include "sofa.h" +#include "sofam.h" + +int iauGd2gc ( int n, double elong, double phi, double height, + double xyz[3] ) +/* +** - - - - - - - - - +** i a u G d 2 g c +** - - - - - - - - - +** +** Transform geodetic coordinates to geocentric using the specified +** reference ellipsoid. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical transformation. +** +** Given: +** n int ellipsoid identifier (Note 1) +** elong double longitude (radians, east +ve) +** phi double latitude (geodetic, radians, Note 3) +** height double height above ellipsoid (geodetic, Notes 2,3) +** +** Returned: +** xyz double[3] geocentric vector (Note 2) +** +** Returned (function value): +** int status: 0 = OK +** -1 = illegal identifier (Note 3) +** -2 = illegal case (Note 3) +** +** Notes: +** +** 1) The identifier n is a number that specifies the choice of +** reference ellipsoid. The following are supported: +** +** n ellipsoid +** +** 1 WGS84 +** 2 GRS80 +** 3 WGS72 +** +** The n value has no significance outside the SOFA software. For +** convenience, symbols WGS84 etc. are defined in sofam.h. +** +** 2) The height (height, given) and the geocentric vector (xyz, +** returned) are in meters. +** +** 3) No validation is performed on the arguments elong, phi and +** height. An error status -1 means that the identifier n is +** illegal. An error status -2 protects against cases that would +** lead to arithmetic exceptions. In all error cases, xyz is set +** to zeros. +** +** 4) The inverse transformation is performed in the function iauGc2gd. +** +** Called: +** iauEform Earth reference ellipsoids +** iauGd2gce geodetic to geocentric transformation, general +** iauZp zero p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j; + double a, f; + + +/* Obtain reference ellipsoid parameters. */ + j = iauEform ( n, &a, &f ); + +/* If OK, transform longitude, geodetic latitude, height to x,y,z. */ + if ( j == 0 ) { + j = iauGd2gce ( a, f, elong, phi, height, xyz ); + if ( j != 0 ) j = -2; + } + +/* Deal with any errors. */ + if ( j != 0 ) iauZp ( xyz ); + +/* Return the status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gd2gce.c b/src/cpp/3rdparty/sofa/src/gd2gce.c new file mode 100644 index 000000000..5a58e5889 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gd2gce.c @@ -0,0 +1,190 @@ +#include "sofa.h" +#include "sofam.h" + +int iauGd2gce ( double a, double f, double elong, double phi, + double height, double xyz[3] ) +/* +** - - - - - - - - - - +** i a u G d 2 g c e +** - - - - - - - - - - +** +** Transform geodetic coordinates to geocentric for a reference +** ellipsoid of specified form. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** a double equatorial radius (Notes 1,4) +** f double flattening (Notes 2,4) +** elong double longitude (radians, east +ve) +** phi double latitude (geodetic, radians, Note 4) +** height double height above ellipsoid (geodetic, Notes 3,4) +** +** Returned: +** xyz double[3] geocentric vector (Note 3) +** +** Returned (function value): +** int status: 0 = OK +** -1 = illegal case (Note 4) +** Notes: +** +** 1) The equatorial radius, a, can be in any units, but meters is +** the conventional choice. +** +** 2) The flattening, f, is (for the Earth) a value around 0.00335, +** i.e. around 1/298. +** +** 3) The equatorial radius, a, and the height, height, must be +** given in the same units, and determine the units of the +** returned geocentric vector, xyz. +** +** 4) No validation is performed on individual arguments. The error +** status -1 protects against (unrealistic) cases that would lead +** to arithmetic exceptions. If an error occurs, xyz is unchanged. +** +** 5) The inverse transformation is performed in the function +** iauGc2gde. +** +** 6) The transformation for a standard ellipsoid (such as WGS84) can +** more conveniently be performed by calling iauGd2gc, which uses a +** numerical code to identify the required a and f values. +** +** References: +** +** Green, R.M., Spherical Astronomy, Cambridge University Press, +** (1985) Section 4.5, p96. +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 4.22, p202. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double sp, cp, w, d, ac, as, r; + + +/* Functions of geodetic latitude. */ + sp = sin(phi); + cp = cos(phi); + w = 1.0 - f; + w = w * w; + d = cp*cp + w*sp*sp; + if ( d <= 0.0 ) return -1; + ac = a / sqrt(d); + as = w * ac; + +/* Geocentric vector. */ + r = (ac + height) * cp; + xyz[0] = r * cos(elong); + xyz[1] = r * sin(elong); + xyz[2] = (as + height) * sp; + +/* Success. */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gmst00.c b/src/cpp/3rdparty/sofa/src/gmst00.c new file mode 100644 index 000000000..9f89074c6 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gmst00.c @@ -0,0 +1,198 @@ +#include "sofa.h" +#include "sofam.h" + +double iauGmst00(double uta, double utb, double tta, double ttb) +/* +** - - - - - - - - - - +** i a u G m s t 0 0 +** - - - - - - - - - - +** +** Greenwich mean sidereal time (model consistent with IAU 2000 +** resolutions). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** uta,utb double UT1 as a 2-part Julian Date (Notes 1,2) +** tta,ttb double TT as a 2-part Julian Date (Notes 1,2) +** +** Returned (function value): +** double Greenwich mean sidereal time (radians) +** +** Notes: +** +** 1) The UT1 and TT dates uta+utb and tta+ttb respectively, are both +** Julian Dates, apportioned in any convenient way between the +** argument pairs. For example, JD(UT1)=2450123.7 could be +** expressed in any of these ways, among others: +** +** Part A Part B +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable (in the case of UT; the TT is not at all critical +** in this respect). The J2000 and MJD methods are good compromises +** between resolution and convenience. For UT, the date & time +** method is best matched to the algorithm that is used by the Earth +** Rotation Angle function, called internally: maximum precision is +** delivered when the uta argument is for 0hrs UT1 on the day in +** question and the utb argument lies in the range 0 to 1, or vice +** versa. +** +** 2) Both UT1 and TT are required, UT1 to predict the Earth rotation +** and TT to predict the effects of precession. If UT1 is used for +** both purposes, errors of order 100 microarcseconds result. +** +** 3) This GMST is compatible with the IAU 2000 resolutions and must be +** used only in conjunction with other IAU 2000 compatible +** components such as precession-nutation and equation of the +** equinoxes. +** +** 4) The result is returned in the range 0 to 2pi. +** +** 5) The algorithm is from Capitaine et al. (2003) and IERS +** Conventions 2003. +** +** Called: +** iauEra00 Earth rotation angle, IAU 2000 +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to +** implement the IAU 2000 definition of UT1", Astronomy & +** Astrophysics, 406, 1135-1149 (2003) +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, gmst; + + +/* TT Julian centuries since J2000.0. */ + t = ((tta - DJ00) + ttb) / DJC; + +/* Greenwich Mean Sidereal Time, IAU 2000. */ + gmst = iauAnp(iauEra00(uta, utb) + + ( 0.014506 + + ( 4612.15739966 + + ( 1.39667721 + + ( -0.00009344 + + ( 0.00001882 ) + * t) * t) * t) * t) * DAS2R); + + return gmst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gmst06.c b/src/cpp/3rdparty/sofa/src/gmst06.c new file mode 100644 index 000000000..d6ebc0117 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gmst06.c @@ -0,0 +1,189 @@ +#include "sofa.h" +#include "sofam.h" + +double iauGmst06(double uta, double utb, double tta, double ttb) +/* +** - - - - - - - - - - +** i a u G m s t 0 6 +** - - - - - - - - - - +** +** Greenwich mean sidereal time (consistent with IAU 2006 precession). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** uta,utb double UT1 as a 2-part Julian Date (Notes 1,2) +** tta,ttb double TT as a 2-part Julian Date (Notes 1,2) +** +** Returned (function value): +** double Greenwich mean sidereal time (radians) +** +** Notes: +** +** 1) The UT1 and TT dates uta+utb and tta+ttb respectively, are both +** Julian Dates, apportioned in any convenient way between the +** argument pairs. For example, JD=2450123.7 could be expressed in +** any of these ways, among others: +** +** Part A Part B +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable (in the case of UT; the TT is not at all critical +** in this respect). The J2000 and MJD methods are good compromises +** between resolution and convenience. For UT, the date & time +** method is best matched to the algorithm that is used by the Earth +** rotation angle function, called internally: maximum precision is +** delivered when the uta argument is for 0hrs UT1 on the day in +** question and the utb argument lies in the range 0 to 1, or vice +** versa. +** +** 2) Both UT1 and TT are required, UT1 to predict the Earth rotation +** and TT to predict the effects of precession. If UT1 is used for +** both purposes, errors of order 100 microarcseconds result. +** +** 3) This GMST is compatible with the IAU 2006 precession and must not +** be used with other precession models. +** +** 4) The result is returned in the range 0 to 2pi. +** +** Called: +** iauEra00 Earth rotation angle, IAU 2000 +** iauAnp normalize angle into range 0 to 2pi +** +** Reference: +** +** Capitaine, N., Wallace, P.T. & Chapront, J., 2005, +** Astron.Astrophys. 432, 355 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, gmst; + + +/* TT Julian centuries since J2000.0. */ + t = ((tta - DJ00) + ttb) / DJC; + +/* Greenwich mean sidereal time, IAU 2006. */ + gmst = iauAnp(iauEra00(uta, utb) + + ( 0.014506 + + ( 4612.156534 + + ( 1.3915817 + + ( -0.00000044 + + ( -0.000029956 + + ( -0.0000000368 ) + * t) * t) * t) * t) * t) * DAS2R); + + return gmst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gmst82.c b/src/cpp/3rdparty/sofa/src/gmst82.c new file mode 100644 index 000000000..009e79f5a --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gmst82.c @@ -0,0 +1,203 @@ +#include "sofa.h" +#include "sofam.h" + +double iauGmst82(double dj1, double dj2) +/* +** - - - - - - - - - - +** i a u G m s t 8 2 +** - - - - - - - - - - +** +** Universal Time to Greenwich mean sidereal time (IAU 1982 model). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** dj1,dj2 double UT1 Julian Date (see note) +** +** Returned (function value): +** double Greenwich mean sidereal time (radians) +** +** Notes: +** +** 1) The UT1 date dj1+dj2 is a Julian Date, apportioned in any +** convenient way between the arguments dj1 and dj2. For example, +** JD(UT1)=2450123.7 could be expressed in any of these ways, +** among others: +** +** dj1 dj2 +** +** 2450123.7 0 (JD method) +** 2451545 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. The date & time method is +** best matched to the algorithm used: maximum accuracy (or, at +** least, minimum noise) is delivered when the dj1 argument is for +** 0hrs UT1 on the day in question and the dj2 argument lies in the +** range 0 to 1, or vice versa. +** +** 2) The algorithm is based on the IAU 1982 expression. This is +** always described as giving the GMST at 0 hours UT1. In fact, it +** gives the difference between the GMST and the UT, the steady +** 4-minutes-per-day drawing-ahead of ST with respect to UT. When +** whole days are ignored, the expression happens to equal the GMST +** at 0 hours UT1 each day. +** +** 3) In this function, the entire UT1 (the sum of the two arguments +** dj1 and dj2) is used directly as the argument for the standard +** formula, the constant term of which is adjusted by 12 hours to +** take account of the noon phasing of Julian Date. The UT1 is then +** added, but omitting whole days to conserve accuracy. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Transactions of the International Astronomical Union, +** XVIII B, 67 (1983). +** +** Aoki et al., Astron.Astrophys., 105, 359-361 (1982). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Coefficients of IAU 1982 GMST-UT1 model */ + double A = 24110.54841 - DAYSEC / 2.0; + double B = 8640184.812866; + double C = 0.093104; + double D = -6.2e-6; + +/* The first constant, A, has to be adjusted by 12 hours because the */ +/* UT1 is supplied as a Julian date, which begins at noon. */ + + double d1, d2, t, f, gmst; + + +/* Julian centuries since fundamental epoch. */ + if (dj1 < dj2) { + d1 = dj1; + d2 = dj2; + } else { + d1 = dj2; + d2 = dj1; + } + t = (d1 + (d2 - DJ00)) / DJC; + +/* Fractional part of JD(UT1), in seconds. */ + f = DAYSEC * (fmod(d1, 1.0) + fmod(d2, 1.0)); + +/* GMST at this UT1. */ + gmst = iauAnp(DS2R * ((A + (B + (C + D * t) * t) * t) + f)); + + return gmst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gst00a.c b/src/cpp/3rdparty/sofa/src/gst00a.c new file mode 100644 index 000000000..1e1ec38b0 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gst00a.c @@ -0,0 +1,190 @@ +#include "sofa.h" + +double iauGst00a(double uta, double utb, double tta, double ttb) +/* +** - - - - - - - - - - +** i a u G s t 0 0 a +** - - - - - - - - - - +** +** Greenwich apparent sidereal time (consistent with IAU 2000 +** resolutions). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** uta,utb double UT1 as a 2-part Julian Date (Notes 1,2) +** tta,ttb double TT as a 2-part Julian Date (Notes 1,2) +** +** Returned (function value): +** double Greenwich apparent sidereal time (radians) +** +** Notes: +** +** 1) The UT1 and TT dates uta+utb and tta+ttb respectively, are both +** Julian Dates, apportioned in any convenient way between the +** argument pairs. For example, JD(UT1)=2450123.7 could be +** expressed in any of these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable (in the case of UT; the TT is not at all critical +** in this respect). The J2000 and MJD methods are good compromises +** between resolution and convenience. For UT, the date & time +** method is best matched to the algorithm that is used by the Earth +** Rotation Angle function, called internally: maximum precision is +** delivered when the uta argument is for 0hrs UT1 on the day in +** question and the utb argument lies in the range 0 to 1, or vice +** versa. +** +** 2) Both UT1 and TT are required, UT1 to predict the Earth rotation +** and TT to predict the effects of precession-nutation. If UT1 is +** used for both purposes, errors of order 100 microarcseconds +** result. +** +** 3) This GAST is compatible with the IAU 2000 resolutions and must be +** used only in conjunction with other IAU 2000 compatible +** components such as precession-nutation. +** +** 4) The result is returned in the range 0 to 2pi. +** +** 5) The algorithm is from Capitaine et al. (2003) and IERS +** Conventions 2003. +** +** Called: +** iauGmst00 Greenwich mean sidereal time, IAU 2000 +** iauEe00a equation of the equinoxes, IAU 2000A +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to +** implement the IAU 2000 definition of UT1", Astronomy & +** Astrophysics, 406, 1135-1149 (2003) +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gmst00, ee00a, gst; + + + gmst00 = iauGmst00(uta, utb, tta, ttb); + ee00a = iauEe00a(tta, ttb); + gst = iauAnp(gmst00 + ee00a); + + return gst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gst00b.c b/src/cpp/3rdparty/sofa/src/gst00b.c new file mode 100644 index 000000000..e690b4990 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gst00b.c @@ -0,0 +1,198 @@ +#include "sofa.h" + +double iauGst00b(double uta, double utb) +/* +** - - - - - - - - - - +** i a u G s t 0 0 b +** - - - - - - - - - - +** +** Greenwich apparent sidereal time (consistent with IAU 2000 +** resolutions but using the truncated nutation model IAU 2000B). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** uta,utb double UT1 as a 2-part Julian Date (Notes 1,2) +** +** Returned (function value): +** double Greenwich apparent sidereal time (radians) +** +** Notes: +** +** 1) The UT1 date uta+utb is a Julian Date, apportioned in any +** convenient way between the argument pair. For example, +** JD(UT1)=2450123.7 could be expressed in any of these ways, +** among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. For UT, the date & time +** method is best matched to the algorithm that is used by the Earth +** Rotation Angle function, called internally: maximum precision is +** delivered when the uta argument is for 0hrs UT1 on the day in +** question and the utb argument lies in the range 0 to 1, or vice +** versa. +** +** 2) The result is compatible with the IAU 2000 resolutions, except +** that accuracy has been compromised for the sake of speed and +** convenience in two respects: +** +** . UT is used instead of TDB (or TT) to compute the precession +** component of GMST and the equation of the equinoxes. This +** results in errors of order 0.1 mas at present. +** +** . The IAU 2000B abridged nutation model (McCarthy & Luzum, 2003) +** is used, introducing errors of up to 1 mas. +** +** 3) This GAST is compatible with the IAU 2000 resolutions and must be +** used only in conjunction with other IAU 2000 compatible +** components such as precession-nutation. +** +** 4) The result is returned in the range 0 to 2pi. +** +** 5) The algorithm is from Capitaine et al. (2003) and IERS +** Conventions 2003. +** +** Called: +** iauGmst00 Greenwich mean sidereal time, IAU 2000 +** iauEe00b equation of the equinoxes, IAU 2000B +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to +** implement the IAU 2000 definition of UT1", Astronomy & +** Astrophysics, 406, 1135-1149 (2003) +** +** McCarthy, D.D. & Luzum, B.J., "An abridged model of the +** precession-nutation of the celestial pole", Celestial Mechanics & +** Dynamical Astronomy, 85, 37-49 (2003) +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gmst00, ee00b, gst; + + + gmst00 = iauGmst00(uta, utb, uta, utb); + ee00b = iauEe00b(uta, utb); + gst = iauAnp(gmst00 + ee00b); + + return gst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gst06.c b/src/cpp/3rdparty/sofa/src/gst06.c new file mode 100644 index 000000000..4a5914acb --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gst06.c @@ -0,0 +1,192 @@ +#include "sofa.h" + +double iauGst06(double uta, double utb, double tta, double ttb, + double rnpb[3][3]) +/* +** - - - - - - - - - +** i a u G s t 0 6 +** - - - - - - - - - +** +** Greenwich apparent sidereal time, IAU 2006, given the NPB matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** uta,utb double UT1 as a 2-part Julian Date (Notes 1,2) +** tta,ttb double TT as a 2-part Julian Date (Notes 1,2) +** rnpb double[3][3] nutation x precession x bias matrix +** +** Returned (function value): +** double Greenwich apparent sidereal time (radians) +** +** Notes: +** +** 1) The UT1 and TT dates uta+utb and tta+ttb respectively, are both +** Julian Dates, apportioned in any convenient way between the +** argument pairs. For example, JD(UT1)=2450123.7 could be +** expressed in any of these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable (in the case of UT; the TT is not at all critical +** in this respect). The J2000 and MJD methods are good compromises +** between resolution and convenience. For UT, the date & time +** method is best matched to the algorithm that is used by the Earth +** rotation angle function, called internally: maximum precision is +** delivered when the uta argument is for 0hrs UT1 on the day in +** question and the utb argument lies in the range 0 to 1, or vice +** versa. +** +** 2) Both UT1 and TT are required, UT1 to predict the Earth rotation +** and TT to predict the effects of precession-nutation. If UT1 is +** used for both purposes, errors of order 100 microarcseconds +** result. +** +** 3) Although the function uses the IAU 2006 series for s+XY/2, it is +** otherwise independent of the precession-nutation model and can in +** practice be used with any equinox-based NPB matrix. +** +** 4) The result is returned in the range 0 to 2pi. +** +** Called: +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS06 the CIO locator s, given X,Y, IAU 2006 +** iauAnp normalize angle into range 0 to 2pi +** iauEra00 Earth rotation angle, IAU 2000 +** iauEors equation of the origins, given NPB matrix and s +** +** Reference: +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y, s, era, eors, gst; + + +/* Extract CIP coordinates. */ + iauBpn2xy(rnpb, &x, &y); + +/* The CIO locator, s. */ + s = iauS06(tta, ttb, x, y); + +/* Greenwich apparent sidereal time. */ + era = iauEra00(uta, utb); + eors = iauEors(rnpb, s); + gst = iauAnp(era - eors); + + return gst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gst06a.c b/src/cpp/3rdparty/sofa/src/gst06a.c new file mode 100644 index 000000000..da0b393e3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gst06a.c @@ -0,0 +1,183 @@ +#include "sofa.h" + +double iauGst06a(double uta, double utb, double tta, double ttb) +/* +** - - - - - - - - - - +** i a u G s t 0 6 a +** - - - - - - - - - - +** +** Greenwich apparent sidereal time (consistent with IAU 2000 and 2006 +** resolutions). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** uta,utb double UT1 as a 2-part Julian Date (Notes 1,2) +** tta,ttb double TT as a 2-part Julian Date (Notes 1,2) +** +** Returned (function value): +** double Greenwich apparent sidereal time (radians) +** +** Notes: +** +** 1) The UT1 and TT dates uta+utb and tta+ttb respectively, are both +** Julian Dates, apportioned in any convenient way between the +** argument pairs. For example, JD(UT1)=2450123.7 could be +** expressed in any of these ways, among others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable (in the case of UT; the TT is not at all critical +** in this respect). The J2000 and MJD methods are good compromises +** between resolution and convenience. For UT, the date & time +** method is best matched to the algorithm that is used by the Earth +** rotation angle function, called internally: maximum precision is +** delivered when the uta argument is for 0hrs UT1 on the day in +** question and the utb argument lies in the range 0 to 1, or vice +** versa. +** +** 2) Both UT1 and TT are required, UT1 to predict the Earth rotation +** and TT to predict the effects of precession-nutation. If UT1 is +** used for both purposes, errors of order 100 microarcseconds +** result. +** +** 3) This GAST is compatible with the IAU 2000/2006 resolutions and +** must be used only in conjunction with IAU 2006 precession and +** IAU 2000A nutation. +** +** 4) The result is returned in the range 0 to 2pi. +** +** Called: +** iauPnm06a classical NPB matrix, IAU 2006/2000A +** iauGst06 Greenwich apparent ST, IAU 2006, given NPB matrix +** +** Reference: +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rnpb[3][3], gst; + + +/* Classical nutation x precession x bias matrix, IAU 2000A. */ + iauPnm06a(tta, ttb, rnpb); + +/* Greenwich apparent sidereal time. */ + gst = iauGst06(uta, utb, tta, ttb, rnpb); + + return gst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/gst94.c b/src/cpp/3rdparty/sofa/src/gst94.c new file mode 100644 index 000000000..28839efbf --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/gst94.c @@ -0,0 +1,183 @@ +#include "sofa.h" + +double iauGst94(double uta, double utb) +/* +** - - - - - - - - - +** i a u G s t 9 4 +** - - - - - - - - - +** +** Greenwich apparent sidereal time (consistent with IAU 1982/94 +** resolutions). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** uta,utb double UT1 as a 2-part Julian Date (Notes 1,2) +** +** Returned (function value): +** double Greenwich apparent sidereal time (radians) +** +** Notes: +** +** 1) The UT1 date uta+utb is a Julian Date, apportioned in any +** convenient way between the argument pair. For example, +** JD(UT1)=2450123.7 could be expressed in any of these ways, among +** others: +** +** uta utb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 and MJD methods are good compromises +** between resolution and convenience. For UT, the date & time +** method is best matched to the algorithm that is used by the Earth +** Rotation Angle function, called internally: maximum precision is +** delivered when the uta argument is for 0hrs UT1 on the day in +** question and the utb argument lies in the range 0 to 1, or vice +** versa. +** +** 2) The result is compatible with the IAU 1982 and 1994 resolutions, +** except that accuracy has been compromised for the sake of +** convenience in that UT is used instead of TDB (or TT) to compute +** the equation of the equinoxes. +** +** 3) This GAST must be used only in conjunction with contemporaneous +** IAU standards such as 1976 precession, 1980 obliquity and 1982 +** nutation. It is not compatible with the IAU 2000 resolutions. +** +** 4) The result is returned in the range 0 to 2pi. +** +** Called: +** iauGmst82 Greenwich mean sidereal time, IAU 1982 +** iauEqeq94 equation of the equinoxes, IAU 1994 +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** IAU Resolution C7, Recommendation 3 (1994) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gmst82, eqeq94, gst; + + + gmst82 = iauGmst82(uta, utb); + eqeq94 = iauEqeq94(uta, utb); + gst = iauAnp(gmst82 + eqeq94); + + return gst; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/h2fk5.c b/src/cpp/3rdparty/sofa/src/h2fk5.c new file mode 100644 index 000000000..cd76ab78c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/h2fk5.c @@ -0,0 +1,198 @@ +#include "sofa.h" + +void iauH2fk5(double rh, double dh, + double drh, double ddh, double pxh, double rvh, + double *r5, double *d5, + double *dr5, double *dd5, double *px5, double *rv5) +/* +** - - - - - - - - - +** i a u H 2 f k 5 +** - - - - - - - - - +** +** Transform Hipparcos star data into the FK5 (J2000.0) system. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given (all Hipparcos, epoch J2000.0): +** rh double RA (radians) +** dh double Dec (radians) +** drh double proper motion in RA (dRA/dt, rad/Jyear) +** ddh double proper motion in Dec (dDec/dt, rad/Jyear) +** pxh double parallax (arcsec) +** rvh double radial velocity (km/s, positive = receding) +** +** Returned (all FK5, equinox J2000.0, epoch J2000.0): +** r5 double RA (radians) +** d5 double Dec (radians) +** dr5 double proper motion in RA (dRA/dt, rad/Jyear) +** dd5 double proper motion in Dec (dDec/dt, rad/Jyear) +** px5 double parallax (arcsec) +** rv5 double radial velocity (km/s, positive = receding) +** +** Notes: +** +** 1) This function transforms Hipparcos star positions and proper +** motions into FK5 J2000.0. +** +** 2) The proper motions in RA are dRA/dt rather than +** cos(Dec)*dRA/dt, and are per year rather than per century. +** +** 3) The FK5 to Hipparcos transformation is modeled as a pure +** rotation and spin; zonal errors in the FK5 catalog are not +** taken into account. +** +** 4) See also iauFk52h, iauFk5hz, iauHfk5z. +** +** Called: +** iauStarpv star catalog data to space motion pv-vector +** iauFk5hip FK5 to Hipparcos rotation and spin +** iauRv2m r-vector to r-matrix +** iauRxp product of r-matrix and p-vector +** iauTrxp product of transpose of r-matrix and p-vector +** iauPxp vector product of two p-vectors +** iauPmp p-vector minus p-vector +** iauPvstar space motion pv-vector to star catalog data +** +** Reference: +** +** F.Mignard & M.Froeschle, Astron.Astrophys., 354, 732-739 (2000). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int i; + double pvh[2][3], r5h[3][3], s5h[3], sh[3], wxp[3], vv[3], pv5[2][3]; + + +/* Hipparcos barycentric position/velocity pv-vector (normalized). */ + iauStarpv(rh, dh, drh, ddh, pxh, rvh, pvh); + +/* FK5 to Hipparcos orientation matrix and spin vector. */ + iauFk5hip(r5h, s5h); + +/* Make spin units per day instead of per year. */ + for ( i = 0; i < 3; s5h[i++] /= 365.25 ); + +/* Orient the spin into the Hipparcos system. */ + iauRxp(r5h, s5h, sh); + +/* De-orient the Hipparcos position into the FK5 system. */ + iauTrxp(r5h, pvh[0], pv5[0]); + +/* Apply spin to the position giving an extra space motion component. */ + iauPxp(pvh[0], sh, wxp); + +/* Subtract this component from the Hipparcos space motion. */ + iauPmp(pvh[1], wxp, vv); + +/* De-orient the Hipparcos space motion into the FK5 system. */ + iauTrxp(r5h, vv, pv5[1]); + +/* FK5 pv-vector to spherical. */ + iauPvstar(pv5, r5, d5, dr5, dd5, px5, rv5); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/hd2ae.c b/src/cpp/3rdparty/sofa/src/hd2ae.c new file mode 100644 index 000000000..938478dea --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/hd2ae.c @@ -0,0 +1,191 @@ +#include "sofa.h" +#include "sofam.h" + +void iauHd2ae (double ha, double dec, double phi, + double *az, double *el) +/* +** - - - - - - - - - +** i a u H d 2 a e +** - - - - - - - - - +** +** Equatorial to horizon coordinates: transform hour angle and +** declination to azimuth and altitude. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ha double hour angle (local) +** dec double declination +** phi double site latitude +** +** Returned: +** *az double azimuth +** *el double altitude (informally, elevation) +** +** Notes: +** +** 1) All the arguments are angles in radians. +** +** 2) Azimuth is returned in the range 0-2pi; north is zero, and east +** is +pi/2. Altitude is returned in the range +/- pi/2. +** +** 3) The latitude phi is pi/2 minus the angle between the Earth's +** rotation axis and the adopted zenith. In many applications it +** will be sufficient to use the published geodetic latitude of the +** site. In very precise (sub-arcsecond) applications, phi can be +** corrected for polar motion. +** +** 4) The returned azimuth az is with respect to the rotational north +** pole, as opposed to the ITRS pole, and for sub-arcsecond +** accuracy will need to be adjusted for polar motion if it is to +** be with respect to north on a map of the Earth's surface. +** +** 5) Should the user wish to work with respect to the astronomical +** zenith rather than the geodetic zenith, phi will need to be +** adjusted for deflection of the vertical (often tens of +** arcseconds), and the zero point of the hour angle ha will also +** be affected. +** +** 6) The transformation is the same as Vh = Rz(pi)*Ry(pi/2-phi)*Ve, +** where Vh and Ve are lefthanded unit vectors in the (az,el) and +** (ha,dec) systems respectively and Ry and Rz are rotations about +** first the y-axis and then the z-axis. (n.b. Rz(pi) simply +** reverses the signs of the x and y components.) For efficiency, +** the algorithm is written out rather than calling other utility +** functions. For applications that require even greater +** efficiency, additional savings are possible if constant terms +** such as functions of latitude are computed once and for all. +** +** 7) Again for efficiency, no range checking of arguments is carried +** out. +** +** Last revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double sh, ch, sd, cd, sp, cp, x, y, z, r, a; + + +/* Useful trig functions. */ + sh = sin(ha); + ch = cos(ha); + sd = sin(dec); + cd = cos(dec); + sp = sin(phi); + cp = cos(phi); + +/* Az,Alt unit vector. */ + x = - ch*cd*sp + sd*cp; + y = - sh*cd; + z = ch*cd*cp + sd*sp; + +/* To spherical. */ + r = sqrt(x*x + y*y); + a = (r != 0.0) ? atan2(y,x) : 0.0; + *az = (a < 0.0) ? a+D2PI : a; + *el = atan2(z,r); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/hd2pa.c b/src/cpp/3rdparty/sofa/src/hd2pa.c new file mode 100644 index 000000000..a6736a294 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/hd2pa.c @@ -0,0 +1,164 @@ +#include "sofa.h" + +double iauHd2pa (double ha, double dec, double phi) +/* +** - - - - - - - - - +** i a u H d 2 p a +** - - - - - - - - - +** +** Parallactic angle for a given hour angle and declination. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ha double hour angle +** dec double declination +** phi double site latitude +** +** Returned (function value): +** double parallactic angle +** +** Notes: +** +** 1) All the arguments are angles in radians. +** +** 2) The parallactic angle at a point in the sky is the position +** angle of the vertical, i.e. the angle between the directions to +** the north celestial pole and to the zenith respectively. +** +** 3) The result is returned in the range -pi to +pi. +** +** 4) At the pole itself a zero result is returned. +** +** 5) The latitude phi is pi/2 minus the angle between the Earth's +** rotation axis and the adopted zenith. In many applications it +** will be sufficient to use the published geodetic latitude of the +** site. In very precise (sub-arcsecond) applications, phi can be +** corrected for polar motion. +** +** 6) Should the user wish to work with respect to the astronomical +** zenith rather than the geodetic zenith, phi will need to be +** adjusted for deflection of the vertical (often tens of +** arcseconds), and the zero point of the hour angle ha will also +** be affected. +** +** Reference: +** Smart, W.M., "Spherical Astronomy", Cambridge University Press, +** 6th edition (Green, 1977), p49. +** +** Last revision: 2017 September 12 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double cp, cqsz, sqsz; + + + cp = cos(phi); + sqsz = cp*sin(ha); + cqsz = sin(phi)*cos(dec) - cp*sin(dec)*cos(ha); + return ( ( sqsz != 0.0 || cqsz != 0.0 ) ? atan2(sqsz,cqsz) : 0.0 ); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/hfk5z.c b/src/cpp/3rdparty/sofa/src/hfk5z.c new file mode 100644 index 000000000..31a81625a --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/hfk5z.c @@ -0,0 +1,226 @@ +#include "sofa.h" +#include "sofam.h" + +void iauHfk5z(double rh, double dh, double date1, double date2, + double *r5, double *d5, double *dr5, double *dd5) +/* +** - - - - - - - - - +** i a u H f k 5 z +** - - - - - - - - - +** +** Transform a Hipparcos star position into FK5 J2000.0, assuming +** zero Hipparcos proper motion. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rh double Hipparcos RA (radians) +** dh double Hipparcos Dec (radians) +** date1,date2 double TDB date (Note 1) +** +** Returned (all FK5, equinox J2000.0, date date1+date2): +** r5 double RA (radians) +** d5 double Dec (radians) +** dr5 double FK5 RA proper motion (rad/year, Note 4) +** dd5 double Dec proper motion (rad/year, Note 4) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** 3) The FK5 to Hipparcos transformation is modeled as a pure rotation +** and spin; zonal errors in the FK5 catalogue are not taken into +** account. +** +** 4) It was the intention that Hipparcos should be a close +** approximation to an inertial frame, so that distant objects have +** zero proper motion; such objects have (in general) non-zero +** proper motion in FK5, and this function returns those fictitious +** proper motions. +** +** 5) The position returned by this function is in the FK5 J2000.0 +** reference system but at date date1+date2. +** +** 6) See also iauFk52h, iauH2fk5, iauFk5zhz. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauFk5hip FK5 to Hipparcos rotation and spin +** iauRxp product of r-matrix and p-vector +** iauSxp multiply p-vector by scalar +** iauRxr product of two r-matrices +** iauTrxp product of transpose of r-matrix and p-vector +** iauPxp vector product of two p-vectors +** iauPv2s pv-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** Reference: +** +** F.Mignard & M.Froeschle, 2000, Astron.Astrophys. 354, 732-739. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, ph[3], r5h[3][3], s5h[3], sh[3], vst[3], + rst[3][3], r5ht[3][3], pv5e[2][3], vv[3], + w, r, v; + + +/* Time interval from fundamental epoch J2000.0 to given date (JY). */ + t = ((date1 - DJ00) + date2) / DJY; + +/* Hipparcos barycentric position vector (normalized). */ + iauS2c(rh, dh, ph); + +/* FK5 to Hipparcos orientation matrix and spin vector. */ + iauFk5hip(r5h, s5h); + +/* Rotate the spin into the Hipparcos system. */ + iauRxp(r5h, s5h, sh); + +/* Accumulated Hipparcos wrt FK5 spin over that interval. */ + iauSxp(t, s5h, vst); + +/* Express the accumulated spin as a rotation matrix. */ + iauRv2m(vst, rst); + +/* Rotation matrix: accumulated spin, then FK5 to Hipparcos. */ + iauRxr(r5h, rst, r5ht); + +/* De-orient & de-spin the Hipparcos position into FK5 J2000.0. */ + iauTrxp(r5ht, ph, pv5e[0]); + +/* Apply spin to the position giving a space motion. */ + iauPxp(sh, ph, vv); + +/* De-orient & de-spin the Hipparcos space motion into FK5 J2000.0. */ + iauTrxp(r5ht, vv, pv5e[1]); + +/* FK5 position/velocity pv-vector to spherical. */ + iauPv2s(pv5e, &w, d5, &r, dr5, dd5, &v); + *r5 = iauAnp(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/icrs2g.c b/src/cpp/3rdparty/sofa/src/icrs2g.c new file mode 100644 index 000000000..c55a92cc6 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/icrs2g.c @@ -0,0 +1,211 @@ +#include "sofa.h" + +void iauIcrs2g ( double dr, double dd, double *dl, double *db ) +/* +** - - - - - - - - - - +** i a u I c r s 2 g +** - - - - - - - - - - +** +** Transformation from ICRS to Galactic Coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** dr double ICRS right ascension (radians) +** dd double ICRS declination (radians) +** +** Returned: +** dl double galactic longitude (radians) +** db double galactic latitude (radians) +** +** Notes: +** +** 1) The IAU 1958 system of Galactic coordinates was defined with +** respect to the now obsolete reference system FK4 B1950.0. When +** interpreting the system in a modern context, several factors have +** to be taken into account: +** +** . The inclusion in FK4 positions of the E-terms of aberration. +** +** . The distortion of the FK4 proper motion system by differential +** Galactic rotation. +** +** . The use of the B1950.0 equinox rather than the now-standard +** J2000.0. +** +** . The frame bias between ICRS and the J2000.0 mean place system. +** +** The Hipparcos Catalogue (Perryman & ESA 1997) provides a rotation +** matrix that transforms directly between ICRS and Galactic +** coordinates with the above factors taken into account. The +** matrix is derived from three angles, namely the ICRS coordinates +** of the Galactic pole and the longitude of the ascending node of +** the galactic equator on the ICRS equator. They are given in +** degrees to five decimal places and for canonical purposes are +** regarded as exact. In the Hipparcos Catalogue the matrix +** elements are given to 10 decimal places (about 20 microarcsec). +** In the present SOFA function the matrix elements have been +** recomputed from the canonical three angles and are given to 30 +** decimal places. +** +** 2) The inverse transformation is performed by the function iauG2icrs. +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** iauAnpm normalize angle into range +/- pi +** iauS2c spherical coordinates to unit vector +** iauRxp product of r-matrix and p-vector +** iauC2s p-vector to spherical +** +** Reference: +** Perryman M.A.C. & ESA, 1997, ESA SP-1200, The Hipparcos and Tycho +** catalogues. Astrometric and photometric star catalogues +** derived from the ESA Hipparcos Space Astrometry Mission. ESA +** Publications Division, Noordwijk, Netherlands. +** +** This revision: 2021 January 25 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double v1[3], v2[3]; + +/* +** L2,B2 system of galactic coordinates in the form presented in the +** Hipparcos Catalogue. In degrees: +** +** P = 192.85948 right ascension of the Galactic north pole in ICRS +** Q = 27.12825 declination of the Galactic north pole in ICRS +** R = 32.93192 Galactic longitude of the ascending node of +** the Galactic equator on the ICRS equator +** +** ICRS to galactic rotation matrix, obtained by computing +** R_3(-R) R_1(pi/2-Q) R_3(pi/2+P) to the full precision shown: +*/ + double r[3][3] = { { -0.054875560416215368492398900454, + -0.873437090234885048760383168409, + -0.483835015548713226831774175116 }, + { +0.494109427875583673525222371358, + -0.444829629960011178146614061616, + +0.746982244497218890527388004556 }, + { -0.867666149019004701181616534570, + -0.198076373431201528180486091412, + +0.455983776175066922272100478348 } }; + + +/* Spherical to Cartesian. */ + iauS2c(dr, dd, v1); + +/* ICRS to Galactic. */ + iauRxp(r, v1, v2); + +/* Cartesian to spherical. */ + iauC2s(v2, dl, db); + +/* Express in conventional ranges. */ + *dl = iauAnp(*dl); + *db = iauAnpm(*db); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ir.c b/src/cpp/3rdparty/sofa/src/ir.c new file mode 100644 index 000000000..dca9abb7f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ir.c @@ -0,0 +1,133 @@ +#include "sofa.h" + +void iauIr(double r[3][3]) +/* +** - - - - - - +** i a u I r +** - - - - - - +** +** Initialize an r-matrix to the identity matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Returned: +** r double[3][3] r-matrix +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + r[0][0] = 1.0; + r[0][1] = 0.0; + r[0][2] = 0.0; + r[1][0] = 0.0; + r[1][1] = 1.0; + r[1][2] = 0.0; + r[2][0] = 0.0; + r[2][1] = 0.0; + r[2][2] = 1.0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/jd2cal.c b/src/cpp/3rdparty/sofa/src/jd2cal.c new file mode 100644 index 000000000..6d452584c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/jd2cal.c @@ -0,0 +1,251 @@ +#include "sofa.h" +#include "sofam.h" +#include + +int iauJd2cal(double dj1, double dj2, + int *iy, int *im, int *id, double *fd) +/* +** - - - - - - - - - - +** i a u J d 2 c a l +** - - - - - - - - - - +** +** Julian Date to Gregorian year, month, day, and fraction of a day. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** dj1,dj2 double Julian Date (Notes 1, 2) +** +** Returned (arguments): +** iy int year +** im int month +** id int day +** fd double fraction of day +** +** Returned (function value): +** int status: +** 0 = OK +** -1 = unacceptable date (Note 1) +** +** Notes: +** +** 1) The earliest valid date is -68569.5 (-4900 March 1). The +** largest value accepted is 1e9. +** +** 2) The Julian Date is apportioned in any convenient way between +** the arguments dj1 and dj2. For example, JD=2450123.7 could +** be expressed in any of these ways, among others: +** +** dj1 dj2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** Separating integer and fraction uses the "compensated summation" +** algorithm of Kahan-Neumaier to preserve as much precision as +** possible irrespective of the jd1+jd2 apportionment. +** +** 3) In early eras the conversion is from the "proleptic Gregorian +** calendar"; no account is taken of the date(s) of adoption of +** the Gregorian calendar, nor is the AD/BC numbering convention +** observed. +** +** References: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 12.92 (p604). +** +** Klein, A., A Generalized Kahan-Babuska-Summation-Algorithm. +** Computing, 76, 279-293 (2006), Section 3. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Minimum and maximum allowed JD */ + const double DJMIN = -68569.5; + const double DJMAX = 1e9; + + long jd, i, l, n, k; + double dj, f1, f2, d, s, cs, v[2], x, t, f; + + +/* Verify date is acceptable. */ + dj = dj1 + dj2; + if (dj < DJMIN || dj > DJMAX) return -1; + +/* Separate day and fraction (where -0.5 <= fraction < 0.5). */ + d = dnint(dj1); + f1 = dj1 - d; + jd = (long) d; + d = dnint(dj2); + f2 = dj2 - d; + jd += (long) d; + +/* Compute f1+f2+0.5 using compensated summation (Klein 2006). */ + s = 0.5; + cs = 0.0; + v[0] = f1; + v[1] = f2; + for ( i = 0; i < 2; i++ ) { + x = v[i]; + t = s + x; + cs += fabs(s) >= fabs(x) ? (s-t) + x : (x-t) + s; + s = t; + if ( s >= 1.0 ) { + jd++; + s -= 1.0; + } + } + f = s + cs; + cs = f - s; + +/* Deal with negative f. */ + if ( f < 0.0 ) { + + /* Compensated summation: assume that |s| <= 1.0. */ + f = s + 1.0; + cs += (1.0-f) + s; + s = f; + f = s + cs; + cs = f - s; + jd--; + } + +/* Deal with f that is 1.0 or more (when rounded to double). */ + if ( (f-1.0) >= -DBL_EPSILON/4.0 ) { + + /* Compensated summation: assume that |s| <= 1.0. */ + t = s - 1.0; + cs += (s-t) - 1.0; + s = t; + f = s + cs; + if ( -DBL_EPSILON/2.0 < f ) { + jd++; + f = gmax(f, 0.0); + } + } + +/* Express day in Gregorian calendar. */ + l = jd + 68569L; + n = (4L * l) / 146097L; + l -= (146097L * n + 3L) / 4L; + i = (4000L * (l + 1L)) / 1461001L; + l -= (1461L * i) / 4L - 31L; + k = (80L * l) / 2447L; + *id = (int) (l - (2447L * k) / 80L); + l = k / 11L; + *im = (int) (k + 2L - 12L * l); + *iy = (int) (100L * (n - 49L) + i + l); + *fd = f; + +/* Success. */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/jdcalf.c b/src/cpp/3rdparty/sofa/src/jdcalf.c new file mode 100644 index 000000000..931891cd8 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/jdcalf.c @@ -0,0 +1,226 @@ +#include "sofa.h" +#include "sofam.h" + +int iauJdcalf(int ndp, double dj1, double dj2, int iymdf[4]) +/* +** - - - - - - - - - - +** i a u J d c a l f +** - - - - - - - - - - +** +** Julian Date to Gregorian Calendar, expressed in a form convenient +** for formatting messages: rounded to a specified precision. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ndp int number of decimal places of days in fraction +** dj1,dj2 double dj1+dj2 = Julian Date (Note 1) +** +** Returned: +** iymdf int[4] year, month, day, fraction in Gregorian +** calendar +** +** Returned (function value): +** int status: +** -1 = date out of range +** 0 = OK +** +1 = NDP not 0-9 (interpreted as 0) +** +** Notes: +** +** 1) The Julian Date is apportioned in any convenient way between +** the arguments dj1 and dj2. For example, JD=2450123.7 could +** be expressed in any of these ways, among others: +** +** dj1 dj2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** 2) In early eras the conversion is from the "Proleptic Gregorian +** Calendar"; no account is taken of the date(s) of adoption of +** the Gregorian Calendar, nor is the AD/BC numbering convention +** observed. +** +** 3) See also the function iauJd2cal. +** +** 4) The number of decimal places ndp should be 4 or less if internal +** overflows are to be avoided on platforms which use 16-bit +** integers. +** +** Called: +** iauJd2cal JD to Gregorian calendar +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 12.92 (p604). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int j, js; + double denom, d1, d2, f1, f2, d, djd, f, rf; + + +/* Denominator of fraction (e.g. 100 for 2 decimal places). */ + if ((ndp >= 0) && (ndp <= 9)) { + j = 0; + denom = pow(10.0, ndp); + } else { + j = 1; + denom = 1.0; + } + +/* Copy the date, big then small. */ + if (fabs(dj1) >= fabs(dj2)) { + d1 = dj1; + d2 = dj2; + } else { + d1 = dj2; + d2 = dj1; + } + +/* Realign to midnight (without rounding error). */ + d1 -= 0.5; + +/* Separate day and fraction (as precisely as possible). */ + d = dnint(d1); + f1 = d1 - d; + djd = d; + d = dnint(d2); + f2 = d2 - d; + djd += d; + d = dnint(f1 + f2); + f = (f1 - d) + f2; + if (f < 0.0) { + f += 1.0; + d -= 1.0; + } + djd += d; + +/* Round the total fraction to the specified number of places. */ + rf = dnint(f*denom) / denom; + +/* Re-align to noon. */ + djd += 0.5; + +/* Convert to Gregorian calendar. */ + js = iauJd2cal(djd, rf, &iymdf[0], &iymdf[1], &iymdf[2], &f); + if (js == 0) { + iymdf[3] = (int) dnint(f * denom); + } else { + j = js; + } + +/* Return the status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ld.c b/src/cpp/3rdparty/sofa/src/ld.c new file mode 100644 index 000000000..3ce8588bd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ld.c @@ -0,0 +1,203 @@ +#include "sofa.h" +#include "sofam.h" + +void iauLd(double bm, double p[3], double q[3], double e[3], + double em, double dlim, double p1[3]) +/* +** - - - - - - +** i a u L d +** - - - - - - +** +** Apply light deflection by a solar-system body, as part of +** transforming coordinate direction into natural direction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** bm double mass of the gravitating body (solar masses) +** p double[3] direction from observer to source (unit vector) +** q double[3] direction from body to source (unit vector) +** e double[3] direction from body to observer (unit vector) +** em double distance from body to observer (au) +** dlim double deflection limiter (Note 4) +** +** Returned: +** p1 double[3] observer to deflected source (unit vector) +** +** Notes: +** +** 1) The algorithm is based on Expr. (70) in Klioner (2003) and +** Expr. (7.63) in the Explanatory Supplement (Urban & Seidelmann +** 2013), with some rearrangement to minimize the effects of machine +** precision. +** +** 2) The mass parameter bm can, as required, be adjusted in order to +** allow for such effects as quadrupole field. +** +** 3) The barycentric position of the deflecting body should ideally +** correspond to the time of closest approach of the light ray to +** the body. +** +** 4) The deflection limiter parameter dlim is phi^2/2, where phi is +** the angular separation (in radians) between source and body at +** which limiting is applied. As phi shrinks below the chosen +** threshold, the deflection is artificially reduced, reaching zero +** for phi = 0. +** +** 5) The returned vector p1 is not normalized, but the consequential +** departure from unit magnitude is always negligible. +** +** 6) The arguments p and p1 can be the same array. +** +** 7) To accumulate total light deflection taking into account the +** contributions from several bodies, call the present function for +** each body in succession, in decreasing order of distance from the +** observer. +** +** 8) For efficiency, validation is omitted. The supplied vectors must +** be of unit magnitude, and the deflection limiter non-zero and +** positive. +** +** References: +** +** Urban, S. & Seidelmann, P. K. (eds), Explanatory Supplement to +** the Astronomical Almanac, 3rd ed., University Science Books +** (2013). +** +** Klioner, Sergei A., "A practical relativistic model for micro- +** arcsecond astrometry in space", Astr. J. 125, 1580-1597 (2003). +** +** Called: +** iauPdp scalar product of two p-vectors +** iauPxp vector product of two p-vectors +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int i; + double qpe[3], qdqpe, w, eq[3], peq[3]; + + +/* q . (q + e). */ + for (i = 0; i < 3; i++) { + qpe[i] = q[i] + e[i]; + } + qdqpe = iauPdp(q, qpe); + +/* 2 x G x bm / ( em x c^2 x ( q . (q + e) ) ). */ + w = bm * SRS / em / gmax(qdqpe,dlim); + +/* p x (e x q). */ + iauPxp(e, q, eq); + iauPxp(p, eq, peq); + +/* Apply the deflection. */ + for (i = 0; i < 3; i++) { + p1[i] = p[i] + w*peq[i]; + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ldn.c b/src/cpp/3rdparty/sofa/src/ldn.c new file mode 100644 index 000000000..3848d7b6e --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ldn.c @@ -0,0 +1,225 @@ +#include "sofa.h" +#include "sofam.h" + +void iauLdn(int n, iauLDBODY b[], double ob[3], double sc[3], + double sn[3]) +/*+ +** - - - - - - - +** i a u L d n +** - - - - - - - +** +** For a star, apply light deflection by multiple solar-system bodies, +** as part of transforming coordinate direction into natural direction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** n int number of bodies (note 1) +** b iauLDBODY[n] data for each of the n bodies (Notes 1,2): +** bm double mass of the body (solar masses, Note 3) +** dl double deflection limiter (Note 4) +** pv [2][3] barycentric PV of the body (au, au/day) +** ob double[3] barycentric position of the observer (au) +** sc double[3] observer to star coord direction (unit vector) +** +** Returned: +** sn double[3] observer to deflected star (unit vector) +** +** 1) The array b contains n entries, one for each body to be +** considered. If n = 0, no gravitational light deflection will be +** applied, not even for the Sun. +** +** 2) The array b should include an entry for the Sun as well as for +** any planet or other body to be taken into account. The entries +** should be in the order in which the light passes the body. +** +** 3) In the entry in the b array for body i, the mass parameter +** b[i].bm can, as required, be adjusted in order to allow for such +** effects as quadrupole field. +** +** 4) The deflection limiter parameter b[i].dl is phi^2/2, where phi is +** the angular separation (in radians) between star and body at +** which limiting is applied. As phi shrinks below the chosen +** threshold, the deflection is artificially reduced, reaching zero +** for phi = 0. Example values suitable for a terrestrial +** observer, together with masses, are as follows: +** +** body i b[i].bm b[i].dl +** +** Sun 1.0 6e-6 +** Jupiter 0.00095435 3e-9 +** Saturn 0.00028574 3e-10 +** +** 5) For cases where the starlight passes the body before reaching the +** observer, the body is placed back along its barycentric track by +** the light time from that point to the observer. For cases where +** the body is "behind" the observer no such shift is applied. If +** a different treatment is preferred, the user has the option of +** instead using the iauLd function. Similarly, iauLd can be used +** for cases where the source is nearby, not a star. +** +** 6) The returned vector sn is not normalized, but the consequential +** departure from unit magnitude is always negligible. +** +** 7) The arguments sc and sn can be the same array. +** +** 8) For efficiency, validation is omitted. The supplied masses must +** be greater than zero, the position and velocity vectors must be +** right, and the deflection limiter greater than zero. +** +** Reference: +** +** Urban, S. & Seidelmann, P. K. (eds), Explanatory Supplement to +** the Astronomical Almanac, 3rd ed., University Science Books +** (2013), Section 7.2.4. +** +** Called: +** iauCp copy p-vector +** iauPdp scalar product of two p-vectors +** iauPmp p-vector minus p-vector +** iauPpsp p-vector plus scaled p-vector +** iauPn decompose p-vector into modulus and direction +** iauLd light deflection by a solar-system body +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Light time for 1 au (days) */ + const double CR = AULT/DAYSEC; + + int i; + double v[3], dt, ev[3], em, e[3]; + + +/* Star direction prior to deflection. */ + iauCp(sc, sn); + +/* Body by body. */ + for ( i = 0; i < n; i++ ) { + + /* Body to observer vector at epoch of observation (au). */ + iauPmp ( ob, b[i].pv[0], v ); + + /* Minus the time since the light passed the body (days). */ + dt = iauPdp(sn,v) * CR; + + /* Neutralize if the star is "behind" the observer. */ + dt = gmin(dt, 0.0); + + /* Backtrack the body to the time the light was passing the body. */ + iauPpsp(v, -dt, b[i].pv[1], ev); + + /* Body to observer vector as magnitude and direction. */ + iauPn(ev, &em, e); + + /* Apply light deflection for this body. */ + iauLd ( b[i].bm, sn, sn, e, em, b[i].dl, sn ); + + /* Next body. */ + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ldsun.c b/src/cpp/3rdparty/sofa/src/ldsun.c new file mode 100644 index 000000000..bad468c50 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ldsun.c @@ -0,0 +1,156 @@ +#include "sofa.h" + +void iauLdsun(double p[3], double e[3], double em, double p1[3]) +/* +** - - - - - - - - - +** i a u L d s u n +** - - - - - - - - - +** +** Deflection of starlight by the Sun. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** p double[3] direction from observer to star (unit vector) +** e double[3] direction from Sun to observer (unit vector) +** em double distance from Sun to observer (au) +** +** Returned: +** p1 double[3] observer to deflected star (unit vector) +** +** Notes: +** +** 1) The source is presumed to be sufficiently distant that its +** directions seen from the Sun and the observer are essentially +** the same. +** +** 2) The deflection is restrained when the angle between the star and +** the center of the Sun is less than a threshold value, falling to +** zero deflection for zero separation. The chosen threshold value +** is within the solar limb for all solar-system applications, and +** is about 5 arcminutes for the case of a terrestrial observer. +** +** 3) The arguments p and p1 can be the same array. +** +** Called: +** iauLd light deflection by a solar-system body +** +** This revision: 2016 June 16 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double em2, dlim; + + +/* Deflection limiter (smaller for distant observers). */ + em2 = em*em; + if ( em2 < 1.0 ) em2 = 1.0; + dlim = 1e-6 / (em2 > 1.0 ? em2 : 1.0); + +/* Apply the deflection. */ + iauLd(1.0, p, p, e, em, dlim, p1); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/lteceq.c b/src/cpp/3rdparty/sofa/src/lteceq.c new file mode 100644 index 000000000..e64609314 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/lteceq.c @@ -0,0 +1,181 @@ +#include "sofa.h" + +void iauLteceq(double epj, double dl, double db, double *dr, double *dd) +/* +** - - - - - - - - - - +** i a u L t e c e q +** - - - - - - - - - - +** +** Transformation from ecliptic coordinates (mean equinox and ecliptic +** of date) to ICRS RA,Dec, using a long-term precession model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian epoch (TT) +** dl,db double ecliptic longitude and latitude (radians) +** +** Returned: +** dr,dd double ICRS right ascension and declination (radians) +** +** 1) No assumptions are made about whether the coordinates represent +** starlight and embody astrometric effects such as parallax or +** aberration. +** +** 2) The transformation is approximately that from ecliptic longitude +** and latitude (mean equinox and ecliptic of date) to mean J2000.0 +** right ascension and declination, with only frame bias (always +** less than 25 mas) to disturb this classical picture. +** +** 3) The Vondrak et al. (2011, 2012) 400 millennia precession model +** agrees with the IAU 2006 precession at J2000.0 and stays within +** 100 microarcseconds during the 20th and 21st centuries. It is +** accurate to a few arcseconds throughout the historical period, +** worsening to a few tenths of a degree at the end of the +** +/- 200,000 year time span. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauLtecm J2000.0 to ecliptic rotation matrix, long term +** iauTrxp product of transpose of r-matrix and p-vector +** iauC2s unit vector to spherical coordinates +** iauAnp normalize angle into range 0 to 2pi +** iauAnpm normalize angle into range +/- pi +** +** References: +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession +** expressions, valid for long time intervals, Astron.Astrophys. 534, +** A22 +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession +** expressions, valid for long time intervals (Corrigendum), +** Astron.Astrophys. 541, C1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rm[3][3], v1[3], v2[3], a, b; + + +/* Spherical to Cartesian. */ + iauS2c(dl, db, v1); + +/* Rotation matrix, ICRS equatorial to ecliptic. */ + iauLtecm(epj, rm); + +/* The transformation from ecliptic to ICRS. */ + iauTrxp(rm, v1, v2); + +/* Cartesian to spherical. */ + iauC2s(v2, &a, &b); + +/* Express in conventional ranges. */ + *dr = iauAnp(a); + *dd = iauAnpm(b); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ltecm.c b/src/cpp/3rdparty/sofa/src/ltecm.c new file mode 100644 index 000000000..38a0c3d3f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ltecm.c @@ -0,0 +1,201 @@ +#include "sofa.h" +#include "sofam.h" + +void iauLtecm(double epj, double rm[3][3]) +/* +** - - - - - - - - - +** i a u L t e c m +** - - - - - - - - - +** +** ICRS equatorial to ecliptic rotation matrix, long-term. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian epoch (TT) +** +** Returned: +** rm double[3][3] ICRS to ecliptic rotation matrix +** +** Notes: +** +** 1) The matrix is in the sense +** +** E_ep = rm x P_ICRS, +** +** where P_ICRS is a vector with respect to ICRS right ascension +** and declination axes and E_ep is the same vector with respect to +** the (inertial) ecliptic and equinox of epoch epj. +** +** 2) P_ICRS is a free vector, merely a direction, typically of unit +** magnitude, and not bound to any particular spatial origin, such +** as the Earth, Sun or SSB. No assumptions are made about whether +** it represents starlight and embodies astrometric effects such as +** parallax or aberration. The transformation is approximately that +** between mean J2000.0 right ascension and declination and ecliptic +** longitude and latitude, with only frame bias (always less than +** 25 mas) to disturb this classical picture. +** +** 3) The Vondrak et al. (2011, 2012) 400 millennia precession model +** agrees with the IAU 2006 precession at J2000.0 and stays within +** 100 microarcseconds during the 20th and 21st centuries. It is +** accurate to a few arcseconds throughout the historical period, +** worsening to a few tenths of a degree at the end of the +** +/- 200,000 year time span. +** +** Called: +** iauLtpequ equator pole, long term +** iauLtpecl ecliptic pole, long term +** iauPxp vector product +** iauPn normalize vector +** +** References: +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession +** expressions, valid for long time intervals, Astron.Astrophys. 534, +** A22 +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession +** expressions, valid for long time intervals (Corrigendum), +** Astron.Astrophys. 541, C1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Frame bias (IERS Conventions 2010, Eqs. 5.21 and 5.33) */ + const double dx = -0.016617 * DAS2R, + de = -0.0068192 * DAS2R, + dr = -0.0146 * DAS2R; + + double p[3], z[3], w[3], s, x[3], y[3]; + + +/* Equator pole. */ + iauLtpequ(epj, p); + +/* Ecliptic pole (bottom row of equatorial to ecliptic matrix). */ + iauLtpecl(epj, z); + +/* Equinox (top row of matrix). */ + iauPxp(p, z, w); + iauPn(w, &s, x); + +/* Middle row of matrix. */ + iauPxp(z, x, y); + +/* Combine with frame bias. */ + rm[0][0] = x[0] - x[1]*dr + x[2]*dx; + rm[0][1] = x[0]*dr + x[1] + x[2]*de; + rm[0][2] = - x[0]*dx - x[1]*de + x[2]; + rm[1][0] = y[0] - y[1]*dr + y[2]*dx; + rm[1][1] = y[0]*dr + y[1] + y[2]*de; + rm[1][2] = - y[0]*dx - y[1]*de + y[2]; + rm[2][0] = z[0] - z[1]*dr + z[2]*dx; + rm[2][1] = z[0]*dr + z[1] + z[2]*de; + rm[2][2] = - z[0]*dx - z[1]*de + z[2]; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/lteqec.c b/src/cpp/3rdparty/sofa/src/lteqec.c new file mode 100644 index 000000000..9244b0218 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/lteqec.c @@ -0,0 +1,182 @@ +#include "sofa.h" + +void iauLteqec(double epj, double dr, double dd, double *dl, double *db) +/* +** - - - - - - - - - - +** i a u L t e q e c +** - - - - - - - - - - +** +** Transformation from ICRS equatorial coordinates to ecliptic +** coordinates (mean equinox and ecliptic of date) using a long-term +** precession model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian epoch (TT) +** dr,dd double ICRS right ascension and declination (radians) +** +** Returned: +** dl,db double ecliptic longitude and latitude (radians) +** +** 1) No assumptions are made about whether the coordinates represent +** starlight and embody astrometric effects such as parallax or +** aberration. +** +** 2) The transformation is approximately that from mean J2000.0 right +** ascension and declination to ecliptic longitude and latitude +** (mean equinox and ecliptic of date), with only frame bias (always +** less than 25 mas) to disturb this classical picture. +** +** 3) The Vondrak et al. (2011, 2012) 400 millennia precession model +** agrees with the IAU 2006 precession at J2000.0 and stays within +** 100 microarcseconds during the 20th and 21st centuries. It is +** accurate to a few arcseconds throughout the historical period, +** worsening to a few tenths of a degree at the end of the +** +/- 200,000 year time span. +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauLtecm J2000.0 to ecliptic rotation matrix, long term +** iauRxp product of r-matrix and p-vector +** iauC2s unit vector to spherical coordinates +** iauAnp normalize angle into range 0 to 2pi +** iauAnpm normalize angle into range +/- pi +** +** References: +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession +** expressions, valid for long time intervals, Astron.Astrophys. 534, +** A22 +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession +** expressions, valid for long time intervals (Corrigendum), +** Astron.Astrophys. 541, C1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rm[3][3], v1[3], v2[3], a, b; + + +/* Spherical to Cartesian. */ + iauS2c(dr, dd, v1); + +/* Rotation matrix, ICRS equatorial to ecliptic. */ + iauLtecm(epj, rm); + +/* The transformation from ICRS to ecliptic. */ + iauRxp(rm, v1, v2); + +/* Cartesian to spherical. */ + iauC2s(v2, &a, &b); + +/* Express in conventional ranges. */ + *dl = iauAnp(a); + *db = iauAnpm(b); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ltp.c b/src/cpp/3rdparty/sofa/src/ltp.c new file mode 100644 index 000000000..a8b23c794 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ltp.c @@ -0,0 +1,183 @@ +#include "sofa.h" + +void iauLtp(double epj, double rp[3][3]) +/* +** - - - - - - - +** i a u L t p +** - - - - - - - +** +** Long-term precession matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian epoch (TT) +** +** Returned: +** rp double[3][3] precession matrix, J2000.0 to date +** +** Notes: +** +** 1) The matrix is in the sense +** +** P_date = rp x P_J2000, +** +** where P_J2000 is a vector with respect to the J2000.0 mean +** equator and equinox and P_date is the same vector with respect to +** the equator and equinox of epoch epj. +** +** 2) The Vondrak et al. (2011, 2012) 400 millennia precession model +** agrees with the IAU 2006 precession at J2000.0 and stays within +** 100 microarcseconds during the 20th and 21st centuries. It is +** accurate to a few arcseconds throughout the historical period, +** worsening to a few tenths of a degree at the end of the +** +/- 200,000 year time span. +** +** Called: +** iauLtpequ equator pole, long term +** iauLtpecl ecliptic pole, long term +** iauPxp vector product +** iauPn normalize vector +** +** References: +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession +** expressions, valid for long time intervals, Astron.Astrophys. 534, +** A22 +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession +** expressions, valid for long time intervals (Corrigendum), +** Astron.Astrophys. 541, C1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int i; + double peqr[3], pecl[3], v[3], w, eqx[3]; + + +/* Equator pole (bottom row of matrix). */ + iauLtpequ(epj, peqr); + +/* Ecliptic pole. */ + iauLtpecl(epj, pecl); + +/* Equinox (top row of matrix). */ + iauPxp(peqr, pecl, v); + iauPn(v, &w, eqx); + +/* Middle row of matrix. */ + iauPxp(peqr, eqx, v); + +/* Assemble the matrix. */ + for ( i = 0; i < 3; i++ ) { + rp[0][i] = eqx[i]; + rp[1][i] = v[i]; + rp[2][i] = peqr[i]; + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ltpb.c b/src/cpp/3rdparty/sofa/src/ltpb.c new file mode 100644 index 000000000..2074c62c2 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ltpb.c @@ -0,0 +1,177 @@ +#include "sofa.h" +#include "sofam.h" + +void iauLtpb(double epj, double rpb[3][3]) +/* +** - - - - - - - - +** i a u L t p b +** - - - - - - - - +** +** Long-term precession matrix, including ICRS frame bias. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian epoch (TT) +** +** Returned: +** rpb double[3][3] precession-bias matrix, J2000.0 to date +** +** Notes: +** +** 1) The matrix is in the sense +** +** P_date = rpb x P_ICRS, +** +** where P_ICRS is a vector in the Geocentric Celestial Reference +** System, and P_date is the vector with respect to the Celestial +** Intermediate Reference System at that date but with nutation +** neglected. +** +** 2) A first order frame bias formulation is used, of sub- +** microarcsecond accuracy compared with a full 3D rotation. +** +** 3) The Vondrak et al. (2011, 2012) 400 millennia precession model +** agrees with the IAU 2006 precession at J2000.0 and stays within +** 100 microarcseconds during the 20th and 21st centuries. It is +** accurate to a few arcseconds throughout the historical period, +** worsening to a few tenths of a degree at the end of the +** +/- 200,000 year time span. +** +** References: +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession +** expressions, valid for long time intervals, Astron.Astrophys. 534, +** A22 +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession +** expressions, valid for long time intervals (Corrigendum), +** Astron.Astrophys. 541, C1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Frame bias (IERS Conventions 2010, Eqs. 5.21 and 5.33) */ + const double dx = -0.016617 * DAS2R, + de = -0.0068192 * DAS2R, + dr = -0.0146 * DAS2R; + + int i; + double rp[3][3]; + + +/* Precession matrix. */ + iauLtp(epj, rp); + +/* Apply the bias. */ + for ( i = 0; i < 3; i++ ) { + rpb[i][0] = rp[i][0] - rp[i][1]*dr + rp[i][2]*dx; + rpb[i][1] = rp[i][0]*dr + rp[i][1] + rp[i][2]*de; + rpb[i][2] = -rp[i][0]*dx - rp[i][1]*de + rp[i][2]; + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ltpecl.c b/src/cpp/3rdparty/sofa/src/ltpecl.c new file mode 100644 index 000000000..23a09b9b5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ltpecl.c @@ -0,0 +1,221 @@ +#include "sofa.h" +#include "sofam.h" + +void iauLtpecl(double epj, double vec[3]) +/* +** - - - - - - - - - - +** i a u L t p e c l +** - - - - - - - - - - +** +** Long-term precession of the ecliptic. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian epoch (TT) +** +** Returned: +** vec double[3] ecliptic pole unit vector +** +** Notes: +** +** 1) The returned vector is with respect to the J2000.0 mean equator +** and equinox. +** +** 2) The Vondrak et al. (2011, 2012) 400 millennia precession model +** agrees with the IAU 2006 precession at J2000.0 and stays within +** 100 microarcseconds during the 20th and 21st centuries. It is +** accurate to a few arcseconds throughout the historical period, +** worsening to a few tenths of a degree at the end of the +** +/- 200,000 year time span. +** +** References: +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession +** expressions, valid for long time intervals, Astron.Astrophys. 534, +** A22 +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession +** expressions, valid for long time intervals (Corrigendum), +** Astron.Astrophys. 541, C1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Obliquity at J2000.0 (radians). */ + static const double eps0 = 84381.406 * DAS2R; + +/* Polynomial coefficients */ + enum { NPOL = 4 }; + static const double pqpol[2][NPOL] = { + { 5851.607687, + -0.1189000, + -0.00028913, + 0.000000101}, + {-1600.886300, + 1.1689818, + -0.00000020, + -0.000000437} + }; + +/* Periodic coefficients */ + static const double pqper[][5] = { + { 708.15,-5486.751211,-684.661560, 667.666730,-5523.863691}, + {2309.00, -17.127623,2446.283880,-2354.886252, -549.747450}, + {1620.00, -617.517403, 399.671049, -428.152441, -310.998056}, + { 492.20, 413.442940,-356.652376, 376.202861, 421.535876}, + {1183.00, 78.614193,-186.387003, 184.778874, -36.776172}, + { 622.00, -180.732815,-316.800070, 335.321713, -145.278396}, + { 882.00, -87.676083, 198.296701, -185.138669, -34.744450}, + { 547.00, 46.140315, 101.135679, -120.972830, 22.885731} + }; + static const int NPER = (int) ( sizeof pqper / 5 / sizeof (double) ); + +/* Miscellaneous */ + int i; + double t, p, q, w, a, s, c; + + +/* Centuries since J2000. */ + t = ( epj - 2000.0 ) / 100.0; + +/* Initialize P_A and Q_A accumulators. */ + p = 0.0; + q = 0.0; + +/* Periodic terms. */ + w = D2PI*t; + for ( i = 0; i < NPER; i++ ) { + a = w/pqper[i][0]; + s = sin(a); + c = cos(a); + p += c*pqper[i][1] + s*pqper[i][3]; + q += c*pqper[i][2] + s*pqper[i][4]; + } + +/* Polynomial terms. */ + w = 1.0; + for ( i = 0; i < NPOL; i++ ) { + p += pqpol[0][i]*w; + q += pqpol[1][i]*w; + w *= t; + } + +/* P_A and Q_A (radians). */ + p *= DAS2R; + q *= DAS2R; + +/* Form the ecliptic pole vector. */ + w = 1.0 - p*p - q*q; + w = w < 0.0 ? 0.0 : sqrt(w); + s = sin(eps0); + c = cos(eps0); + vec[0] = p; + vec[1] = - q*c - w*s; + vec[2] = - q*s + w*c; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ltpequ.c b/src/cpp/3rdparty/sofa/src/ltpequ.c new file mode 100644 index 000000000..ea41f694c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ltpequ.c @@ -0,0 +1,221 @@ +#include "sofa.h" +#include "sofam.h" + +void iauLtpequ(double epj, double veq[3]) +/* +** - - - - - - - - - - +** i a u L t p e q u +** - - - - - - - - - - +** +** Long-term precession of the equator. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epj double Julian epoch (TT) +** +** Returned: +** veq double[3] equator pole unit vector +** +** Notes: +** +** 1) The returned vector is with respect to the J2000.0 mean equator +** and equinox. +** +** 2) The Vondrak et al. (2011, 2012) 400 millennia precession model +** agrees with the IAU 2006 precession at J2000.0 and stays within +** 100 microarcseconds during the 20th and 21st centuries. It is +** accurate to a few arcseconds throughout the historical period, +** worsening to a few tenths of a degree at the end of the +** +/- 200,000 year time span. +** +** References: +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession +** expressions, valid for long time intervals, Astron.Astrophys. 534, +** A22 +** +** Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession +** expressions, valid for long time intervals (Corrigendum), +** Astron.Astrophys. 541, C1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Polynomial coefficients */ + enum { NPOL = 4 }; + static const double xypol[2][NPOL] = { + { 5453.282155, + 0.4252841, + -0.00037173, + -0.000000152}, + {-73750.930350, + -0.7675452, + -0.00018725, + 0.000000231} + }; + +/* Periodic coefficients */ + static const double xyper[][5] = { + { 256.75, -819.940624,75004.344875,81491.287984, 1558.515853}, + { 708.15,-8444.676815, 624.033993, 787.163481, 7774.939698}, + { 274.20, 2600.009459, 1251.136893, 1251.296102,-2219.534038}, + { 241.45, 2755.175630,-1102.212834,-1257.950837,-2523.969396}, + {2309.00, -167.659835,-2660.664980,-2966.799730, 247.850422}, + { 492.20, 871.855056, 699.291817, 639.744522, -846.485643}, + { 396.10, 44.769698, 153.167220, 131.600209,-1393.124055}, + { 288.90, -512.313065, -950.865637, -445.040117, 368.526116}, + { 231.10, -819.415595, 499.754645, 584.522874, 749.045012}, + {1610.00, -538.071099, -145.188210, -89.756563, 444.704518}, + { 620.00, -189.793622, 558.116553, 524.429630, 235.934465}, + { 157.87, -402.922932, -23.923029, -13.549067, 374.049623}, + { 220.30, 179.516345, -165.405086, -210.157124, -171.330180}, + {1200.00, -9.814756, 9.344131, -44.919798, -22.899655} + }; + static const int NPER = (int) ( sizeof xyper / 5 / sizeof (double) ); + +/* Miscellaneous */ + int i; + double t, x, y, w, a, s, c; + + +/* Centuries since J2000. */ + t = ( epj - 2000.0 ) / 100.0; + +/* Initialize X and Y accumulators. */ + x = 0.0; + y = 0.0; + +/* Periodic terms. */ + w = D2PI * t; + for ( i = 0; i < NPER; i++ ) { + a = w / xyper[i][0]; + s = sin(a); + c = cos(a); + x += c*xyper[i][1] + s*xyper[i][3]; + y += c*xyper[i][2] + s*xyper[i][4]; + } + +/* Polynomial terms. */ + w = 1.0; + for ( i = 0; i < NPOL; i++ ) { + x += xypol[0][i]*w; + y += xypol[1][i]*w; + w *= t; + } + +/* X and Y (direction cosines). */ + x *= DAS2R; + y *= DAS2R; + +/* Form the equator pole vector. */ + veq[0] = x; + veq[1] = y; + w = 1.0 - x*x - y*y; + veq[2] = w < 0.0 ? 0.0 : sqrt(w); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/makefile b/src/cpp/3rdparty/sofa/src/makefile new file mode 100644 index 000000000..5a20ecb6c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/makefile @@ -0,0 +1,895 @@ +#----------------------------------------------------------------------- +# +# Description: make file for the ANSI-C version of SOFA. This +# make file creates a Unix .a library. Designed for Linux/gcc but +# can be adapted for other platforms or run in an appropriate way +# by means of the macros CCOMPC (compiler command), CFLAGF (qualifiers +# for compiling functions) and CFLAGX (qualifiers for compiling +# executables). +# +# Usage: +# +# To build the library: +# +# make +# +# To install the library and include files: +# +# make install +# +# To delete all object files: +# +# make clean +# +# To build and run the test program using the installed library: +# +# make test +# +# Also: +# make all same as make +# make uninstall deinstall the library and header files +# make check test the build +# make installcheck same as make test +# make distclean delete all generated binaries +# make realclean same as distclean +# +# Last revision: 2021 April 18 +# +# Copyright International Astronomical Union. All rights reserved. +# +#----------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# +# DEFINITIONS +# +#----------------------------------------------------------------------- + +#----YOU MAY HAVE TO MODIFY THE NEXT FEW DEFINITIONS----- + +# Specify the installation home directory. + +INSTALL_DIR = $(HOME) + +# Specify the installation directory for the library. + +SOFA_LIB_DIR = $(INSTALL_DIR)/lib/ + +# Specify the installation directory for the include files. + +SOFA_INC_DIR = $(INSTALL_DIR)/include/ + +# This software is compilable only by ANSI C compilers - give the name +# of your preferred C compiler (CCOMPC) and compilation flags (CFLAGF +# for functions, CFLAGX for executables) here. + +CCOMPC = gcc +CFLAGF = -c -pedantic -Wall -O +CFLAGX = -pedantic -Wall -O + +#----YOU SHOULDN'T HAVE TO MODIFY ANYTHING BELOW THIS LINE--------- + +SHELL = /bin/sh + +# The list of installation directories. + +INSTALL_DIRS = $(SOFA_LIB_DIR) $(SOFA_INC_DIR) + +# Name the SOFA/C library in its source and target locations. + +SOFA_LIB_NAME = libsofa_c.a +SOFA_LIB = $(SOFA_LIB_DIR)$(SOFA_LIB_NAME) + +# Name the SOFA/C testbed in its source and target locations. + +SOFA_TEST_NAME = t_sofa_c.c +SOFA_TEST = t_sofa_c + +# Name the SOFA/C includes in their source and target locations. + +SOFA_INC_NAMES = sofa.h sofam.h +SOFA_INC = $(SOFA_INC_DIR)sofa.h $(SOFA_INC_DIR)sofam.h + +# The list of SOFA/C library object files. + +SOFA_OBS = iauA2af.o \ + iauA2tf.o \ + iauAb.o \ + iauAe2hd.o \ + iauAf2a.o \ + iauAnp.o \ + iauAnpm.o \ + iauApcg.o \ + iauApcg13.o \ + iauApci.o \ + iauApci13.o \ + iauApco.o \ + iauApco13.o \ + iauApcs.o \ + iauApcs13.o \ + iauAper.o \ + iauAper13.o \ + iauApio.o \ + iauApio13.o \ + iauAtcc13.o \ + iauAtccq.o \ + iauAtci13.o \ + iauAtciq.o \ + iauAtciqn.o \ + iauAtciqz.o \ + iauAtco13.o \ + iauAtic13.o \ + iauAticq.o \ + iauAticqn.o \ + iauAtio13.o \ + iauAtioq.o \ + iauAtoc13.o \ + iauAtoi13.o \ + iauAtoiq.o \ + iauBi00.o \ + iauBp00.o \ + iauBp06.o \ + iauBpn2xy.o \ + iauC2i00a.o \ + iauC2i00b.o \ + iauC2i06a.o \ + iauC2ibpn.o \ + iauC2ixy.o \ + iauC2ixys.o \ + iauC2s.o \ + iauC2t00a.o \ + iauC2t00b.o \ + iauC2t06a.o \ + iauC2tcio.o \ + iauC2teqx.o \ + iauC2tpe.o \ + iauC2txy.o \ + iauCal2jd.o \ + iauCp.o \ + iauCpv.o \ + iauCr.o \ + iauD2dtf.o \ + iauD2tf.o \ + iauDat.o \ + iauDtdb.o \ + iauDtf2d.o \ + iauEceq06.o \ + iauEcm06.o \ + iauEe00.o \ + iauEe00a.o \ + iauEe00b.o \ + iauEe06a.o \ + iauEect00.o \ + iauEform.o \ + iauEo06a.o \ + iauEors.o \ + iauEpb.o \ + iauEpb2jd.o \ + iauEpj.o \ + iauEpj2jd.o \ + iauEpv00.o \ + iauEqec06.o \ + iauEqeq94.o \ + iauEra00.o \ + iauFad03.o \ + iauFae03.o \ + iauFaf03.o \ + iauFaju03.o \ + iauFal03.o \ + iauFalp03.o \ + iauFama03.o \ + iauFame03.o \ + iauFane03.o \ + iauFaom03.o \ + iauFapa03.o \ + iauFasa03.o \ + iauFaur03.o \ + iauFave03.o \ + iauFk425.o \ + iauFk45z.o \ + iauFk524.o \ + iauFk52h.o \ + iauFk54z.o \ + iauFk5hip.o \ + iauFk5hz.o \ + iauFw2m.o \ + iauFw2xy.o \ + iauG2icrs.o \ + iauGc2gd.o \ + iauGc2gde.o \ + iauGd2gc.o \ + iauGd2gce.o \ + iauGmst00.o \ + iauGmst06.o \ + iauGmst82.o \ + iauGst00a.o \ + iauGst00b.o \ + iauGst06.o \ + iauGst06a.o \ + iauGst94.o \ + iauH2fk5.o \ + iauHd2ae.o \ + iauHd2pa.o \ + iauHfk5z.o \ + iauIcrs2g.o \ + iauIr.o \ + iauJd2cal.o \ + iauJdcalf.o \ + iauLd.o \ + iauLdn.o \ + iauLdsun.o \ + iauLteceq.o \ + iauLtecm.o \ + iauLteqec.o \ + iauLtp.o \ + iauLtpb.o \ + iauLtpecl.o \ + iauLtpequ.o \ + iauMoon98.o \ + iauNum00a.o \ + iauNum00b.o \ + iauNum06a.o \ + iauNumat.o \ + iauNut00a.o \ + iauNut00b.o \ + iauNut06a.o \ + iauNut80.o \ + iauNutm80.o \ + iauObl06.o \ + iauObl80.o \ + iauP06e.o \ + iauP2pv.o \ + iauP2s.o \ + iauPap.o \ + iauPas.o \ + iauPb06.o \ + iauPdp.o \ + iauPfw06.o \ + iauPlan94.o \ + iauPm.o \ + iauPmat00.o \ + iauPmat06.o \ + iauPmat76.o \ + iauPmp.o \ + iauPmpx.o \ + iauPmsafe.o \ + iauPn.o \ + iauPn00.o \ + iauPn00a.o \ + iauPn00b.o \ + iauPn06.o \ + iauPn06a.o \ + iauPnm00a.o \ + iauPnm00b.o \ + iauPnm06a.o \ + iauPnm80.o \ + iauPom00.o \ + iauPpp.o \ + iauPpsp.o \ + iauPr00.o \ + iauPrec76.o \ + iauPv2p.o \ + iauPv2s.o \ + iauPvdpv.o \ + iauPvm.o \ + iauPvmpv.o \ + iauPvppv.o \ + iauPvstar.o \ + iauPvtob.o \ + iauPvu.o \ + iauPvup.o \ + iauPvxpv.o \ + iauPxp.o \ + iauRefco.o \ + iauRm2v.o \ + iauRv2m.o \ + iauRx.o \ + iauRxp.o \ + iauRxpv.o \ + iauRxr.o \ + iauRy.o \ + iauRz.o \ + iauS00.o \ + iauS00a.o \ + iauS00b.o \ + iauS06.o \ + iauS06a.o \ + iauS2c.o \ + iauS2p.o \ + iauS2pv.o \ + iauS2xpv.o \ + iauSepp.o \ + iauSeps.o \ + iauSp00.o \ + iauStarpm.o \ + iauStarpv.o \ + iauSxp.o \ + iauSxpv.o \ + iauTaitt.o \ + iauTaiut1.o \ + iauTaiutc.o \ + iauTcbtdb.o \ + iauTcgtt.o \ + iauTdbtcb.o \ + iauTdbtt.o \ + iauTf2a.o \ + iauTf2d.o \ + iauTpors.o \ + iauTporv.o \ + iauTpsts.o \ + iauTpstv.o \ + iauTpxes.o \ + iauTpxev.o \ + iauTr.o \ + iauTrxp.o \ + iauTrxpv.o \ + iauTttai.o \ + iauTttcg.o \ + iauTttdb.o \ + iauTtut1.o \ + iauUt1tai.o \ + iauUt1tt.o \ + iauUt1utc.o \ + iauUtctai.o \ + iauUtcut1.o \ + iauXy06.o \ + iauXys00a.o \ + iauXys00b.o \ + iauXys06a.o \ + iauZp.o \ + iauZpv.o \ + iauZr.o + +#----------------------------------------------------------------------- +# +# TARGETS +# +#----------------------------------------------------------------------- + +# Build (but do not install) the library. +all : $(SOFA_LIB_NAME) + -@ echo "" + -@ echo "*** Now type 'make test'" \ + " to install the library and run tests ***" + -@ echo "" + +# Install the library and header files. +install $(SOFA_LIB) : $(INSTALL_DIRS) $(SOFA_LIB_NAME) $(SOFA_INC) + cp $(SOFA_LIB_NAME) $(SOFA_LIB_DIR) + +# Deinstall the library and header files. +uninstall: + - $(RM) $(SOFA_LIB) $(SOFA_INC) + +# Test the build. +check: $(SOFA_TEST_NAME) $(SOFA_INC_NAMES) $(SOFA_LIB_NAME) + $(CCOMPC) $(CFLAGX) $(SOFA_TEST_NAME) $(SOFA_LIB_NAME) \ + -I. -lm -o $(SOFA_TEST) + ./$(SOFA_TEST) + +# Test the installed library. +installcheck test: $(SOFA_TEST_NAME) $(SOFA_INC) $(SOFA_LIB) + $(CCOMPC) $(CFLAGX) $(SOFA_TEST_NAME) -I$(SOFA_INC_DIR) \ + -L$(SOFA_LIB_DIR) -lsofa_c -lm -o $(SOFA_TEST) + ./$(SOFA_TEST) + +# Delete object files. +clean : + - $(RM) $(SOFA_OBS) + +# Delete all generated binaries in the current directory. +realclean distclean : clean + - $(RM) $(SOFA_LIB_NAME) $(SOFA_TEST) + +# Create the installation directories if not already present. +$(INSTALL_DIRS): + mkdir -p $@ + +# Build the library. +$(SOFA_LIB_NAME): $(SOFA_OBS) + ar ru $(SOFA_LIB_NAME) $? + +# Install the header files. +$(SOFA_INC) : $(INSTALL_DIRS) $(SOFA_INC_NAMES) + cp $(SOFA_INC_NAMES) $(SOFA_INC_DIR) + +#----------------------------------------------------------------------- + +# The list of object file dependencies + +iauA2af.o : a2af.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ a2af.c +iauA2tf.o : a2tf.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ a2tf.c +iauAb.o : ab.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ab.c +iauAe2hd.o : ae2hd.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ae2hd.c +iauAf2a.o : af2a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ af2a.c +iauAnp.o : anp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ anp.c +iauAnpm.o : anpm.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ anpm.c +iauApcg.o : apcg.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apcg.c +iauApcg13.o : apcg13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apcg13.c +iauApci.o : apci.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apci.c +iauApci13.o : apci13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apci13.c +iauApco.o : apco.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apco.c +iauApco13.o : apco13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apco13.c +iauApcs.o : apcs.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apcs.c +iauApcs13.o : apcs13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apcs13.c +iauAper.o : aper.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ aper.c +iauAper13.o : aper13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ aper13.c +iauApio.o : apio.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apio.c +iauApio13.o : apio13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ apio13.c +iauAtcc13.o : atcc13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atcc13.c +iauAtccq.o : atccq.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atccq.c +iauAtci13.o : atci13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atci13.c +iauAtciq.o : atciq.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atciq.c +iauAtciqn.o : atciqn.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atciqn.c +iauAtciqz.o : atciqz.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atciqz.c +iauAtco13.o : atco13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atco13.c +iauAtic13.o : atic13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atic13.c +iauAticq.o : aticq.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ aticq.c +iauAticqn.o : aticqn.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ aticqn.c +iauAtio13.o : atio13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atio13.c +iauAtioq.o : atioq.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atioq.c +iauAtoc13.o : atoc13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atoc13.c +iauAtoi13.o : atoi13.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atoi13.c +iauAtoiq.o : atoiq.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ atoiq.c +iauBi00.o : bi00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ bi00.c +iauBp00.o : bp00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ bp00.c +iauBp06.o : bp06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ bp06.c +iauBpn2xy.o : bpn2xy.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ bpn2xy.c +iauC2i00a.o : c2i00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2i00a.c +iauC2i00b.o : c2i00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2i00b.c +iauC2i06a.o : c2i06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2i06a.c +iauC2ibpn.o : c2ibpn.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2ibpn.c +iauC2ixy.o : c2ixy.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2ixy.c +iauC2ixys.o : c2ixys.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2ixys.c +iauC2s.o : c2s.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2s.c +iauC2t00a.o : c2t00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2t00a.c +iauC2t00b.o : c2t00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2t00b.c +iauC2t06a.o : c2t06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2t06a.c +iauC2tcio.o : c2tcio.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2tcio.c +iauC2teqx.o : c2teqx.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2teqx.c +iauC2tpe.o : c2tpe.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2tpe.c +iauC2txy.o : c2txy.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ c2txy.c +iauCal2jd.o : cal2jd.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ cal2jd.c +iauCp.o : cp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ cp.c +iauCpv.o : cpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ cpv.c +iauCr.o : cr.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ cr.c +iauD2dtf.o : d2dtf.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ d2dtf.c +iauD2tf.o : d2tf.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ d2tf.c +iauDat.o : dat.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ dat.c +iauDtdb.o : dtdb.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ dtdb.c +iauDtf2d.o : dtf2d.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ dtf2d.c +iauEceq06.o : eceq06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ eceq06.c +iauEcm06.o : ecm06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ecm06.c +iauEe00.o : ee00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ee00.c +iauEe00a.o : ee00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ee00a.c +iauEe00b.o : ee00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ee00b.c +iauEe06a.o : ee06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ee06a.c +iauEect00.o : eect00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ eect00.c +iauEform.o : eform.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ eform.c +iauEo06a.o : eo06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ eo06a.c +iauEors.o : eors.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ eors.c +iauEpb.o : epb.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ epb.c +iauEpb2jd.o : epb2jd.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ epb2jd.c +iauEpj.o : epj.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ epj.c +iauEpj2jd.o : epj2jd.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ epj2jd.c +iauEpv00.o : epv00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ epv00.c +iauEqec06.o : eqec06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ eqec06.c +iauEqeq94.o : eqeq94.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ eqeq94.c +iauEra00.o : era00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ era00.c +iauFad03.o : fad03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fad03.c +iauFae03.o : fae03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fae03.c +iauFaf03.o : faf03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ faf03.c +iauFaju03.o : faju03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ faju03.c +iauFal03.o : fal03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fal03.c +iauFalp03.o : falp03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ falp03.c +iauFama03.o : fama03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fama03.c +iauFame03.o : fame03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fame03.c +iauFane03.o : fane03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fane03.c +iauFaom03.o : faom03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ faom03.c +iauFapa03.o : fapa03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fapa03.c +iauFasa03.o : fasa03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fasa03.c +iauFaur03.o : faur03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ faur03.c +iauFave03.o : fave03.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fave03.c +iauFk425.o : fk425.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fk425.c +iauFk45z.o : fk45z.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fk45z.c +iauFk524.o : fk524.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fk524.c +iauFk52h.o : fk52h.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fk52h.c +iauFk54z.o : fk54z.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fk54z.c +iauFk5hip.o : fk5hip.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fk5hip.c +iauFk5hz.o : fk5hz.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fk5hz.c +iauFw2m.o : fw2m.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fw2m.c +iauFw2xy.o : fw2xy.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ fw2xy.c +iauG2icrs.o : g2icrs.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ g2icrs.c +iauGc2gd.o : gc2gd.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gc2gd.c +iauGc2gde.o : gc2gde.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gc2gde.c +iauGd2gc.o : gd2gc.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gd2gc.c +iauGd2gce.o : gd2gce.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gd2gce.c +iauGmst00.o : gmst00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gmst00.c +iauGmst06.o : gmst06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gmst06.c +iauGmst82.o : gmst82.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gmst82.c +iauGst00a.o : gst00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gst00a.c +iauGst00b.o : gst00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gst00b.c +iauGst06.o : gst06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gst06.c +iauGst06a.o : gst06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gst06a.c +iauGst94.o : gst94.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ gst94.c +iauH2fk5.o : h2fk5.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ h2fk5.c +iauHd2ae.o : hd2ae.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ hd2ae.c +iauHd2pa.o : hd2pa.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ hd2pa.c +iauHfk5z.o : hfk5z.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ hfk5z.c +iauIcrs2g.o : icrs2g.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ icrs2g.c +iauIr.o : ir.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ir.c +iauJd2cal.o : jd2cal.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ jd2cal.c +iauJdcalf.o : jdcalf.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ jdcalf.c +iauLd.o : ld.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ld.c +iauLdn.o : ldn.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ldn.c +iauLdsun.o : ldsun.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ldsun.c +iauLteceq.o : lteceq.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ lteceq.c +iauLtecm.o : ltecm.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ltecm.c +iauLteqec.o : lteqec.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ lteqec.c +iauLtp.o : ltp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ltp.c +iauLtpb.o : ltpb.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ltpb.c +iauLtpecl.o : ltpecl.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ltpecl.c +iauLtpequ.o : ltpequ.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ltpequ.c +iauMoon98.o : moon98.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ moon98.c +iauNum00a.o : num00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ num00a.c +iauNum00b.o : num00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ num00b.c +iauNum06a.o : num06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ num06a.c +iauNumat.o : numat.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ numat.c +iauNut00a.o : nut00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ nut00a.c +iauNut00b.o : nut00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ nut00b.c +iauNut06a.o : nut06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ nut06a.c +iauNut80.o : nut80.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ nut80.c +iauNutm80.o : nutm80.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ nutm80.c +iauObl06.o : obl06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ obl06.c +iauObl80.o : obl80.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ obl80.c +iauP06e.o : p06e.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ p06e.c +iauP2pv.o : p2pv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ p2pv.c +iauP2s.o : p2s.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ p2s.c +iauPap.o : pap.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pap.c +iauPas.o : pas.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pas.c +iauPb06.o : pb06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pb06.c +iauPdp.o : pdp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pdp.c +iauPfw06.o : pfw06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pfw06.c +iauPlan94.o : plan94.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ plan94.c +iauPm.o : pm.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pm.c +iauPmat00.o : pmat00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pmat00.c +iauPmat06.o : pmat06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pmat06.c +iauPmat76.o : pmat76.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pmat76.c +iauPmp.o : pmp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pmp.c +iauPmpx.o : pmpx.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pmpx.c +iauPmsafe.o : pmsafe.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pmsafe.c +iauPn.o : pn.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pn.c +iauPn00.o : pn00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pn00.c +iauPn00a.o : pn00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pn00a.c +iauPn00b.o : pn00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pn00b.c +iauPn06.o : pn06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pn06.c +iauPn06a.o : pn06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pn06a.c +iauPnm00a.o : pnm00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pnm00a.c +iauPnm00b.o : pnm00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pnm00b.c +iauPnm06a.o : pnm06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pnm06a.c +iauPnm80.o : pnm80.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pnm80.c +iauPom00.o : pom00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pom00.c +iauPpp.o : ppp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ppp.c +iauPpsp.o : ppsp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ppsp.c +iauPr00.o : pr00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pr00.c +iauPrec76.o : prec76.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ prec76.c +iauPv2p.o : pv2p.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pv2p.c +iauPv2s.o : pv2s.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pv2s.c +iauPvdpv.o : pvdpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvdpv.c +iauPvm.o : pvm.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvm.c +iauPvmpv.o : pvmpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvmpv.c +iauPvppv.o : pvppv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvppv.c +iauPvstar.o : pvstar.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvstar.c +iauPvtob.o : pvtob.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvtob.c +iauPvu.o : pvu.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvu.c +iauPvup.o : pvup.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvup.c +iauPvxpv.o : pvxpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pvxpv.c +iauPxp.o : pxp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ pxp.c +iauRefco.o : refco.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ refco.c +iauRm2v.o : rm2v.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ rm2v.c +iauRv2m.o : rv2m.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ rv2m.c +iauRx.o : rx.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ rx.c +iauRxp.o : rxp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ rxp.c +iauRxpv.o : rxpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ rxpv.c +iauRxr.o : rxr.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ rxr.c +iauRy.o : ry.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ry.c +iauRz.o : rz.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ rz.c +iauS00.o : s00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s00.c +iauS00a.o : s00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s00a.c +iauS00b.o : s00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s00b.c +iauS06.o : s06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s06.c +iauS06a.o : s06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s06a.c +iauS2c.o : s2c.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s2c.c +iauS2p.o : s2p.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s2p.c +iauS2pv.o : s2pv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s2pv.c +iauS2xpv.o : s2xpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ s2xpv.c +iauSepp.o : sepp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ sepp.c +iauSeps.o : seps.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ seps.c +iauSp00.o : sp00.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ sp00.c +iauStarpm.o : starpm.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ starpm.c +iauStarpv.o : starpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ starpv.c +iauSxp.o : sxp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ sxp.c +iauSxpv.o : sxpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ sxpv.c +iauTaitt.o : taitt.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ taitt.c +iauTaiut1.o : taiut1.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ taiut1.c +iauTaiutc.o : taiutc.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ taiutc.c +iauTcbtdb.o : tcbtdb.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tcbtdb.c +iauTcgtt.o : tcgtt.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tcgtt.c +iauTdbtcb.o : tdbtcb.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tdbtcb.c +iauTdbtt.o : tdbtt.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tdbtt.c +iauTf2a.o : tf2a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tf2a.c +iauTf2d.o : tf2d.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tf2d.c +iauTpors.o : tpors.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tpors.c +iauTporv.o : tporv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tporv.c +iauTpsts.o : tpsts.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tpsts.c +iauTpstv.o : tpstv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tpstv.c +iauTpxes.o : tpxes.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tpxes.c +iauTpxev.o : tpxev.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tpxev.c +iauTr.o : tr.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tr.c +iauTrxp.o : trxp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ trxp.c +iauTrxpv.o : trxpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ trxpv.c +iauTttai.o : tttai.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tttai.c +iauTttcg.o : tttcg.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tttcg.c +iauTttdb.o : tttdb.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ tttdb.c +iauTtut1.o : ttut1.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ttut1.c +iauUt1tai.o : ut1tai.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ut1tai.c +iauUt1tt.o : ut1tt.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ut1tt.c +iauUt1utc.o : ut1utc.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ ut1utc.c +iauUtctai.o : utctai.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ utctai.c +iauUtcut1.o : utcut1.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ utcut1.c +iauXy06.o : xy06.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ xy06.c +iauXys00a.o : xys00a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ xys00a.c +iauXys00b.o : xys00b.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ xys00b.c +iauXys06a.o : xys06a.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ xys06a.c +iauZp.o : zp.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ zp.c +iauZpv.o : zpv.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ zpv.c +iauZr.o : zr.c sofa.h sofam.h + $(CCOMPC) $(CFLAGF) -o $@ zr.c + +#----------------------------------------------------------------------- diff --git a/src/cpp/3rdparty/sofa/src/moon98.c b/src/cpp/3rdparty/sofa/src/moon98.c new file mode 100644 index 000000000..0ba9787ce --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/moon98.c @@ -0,0 +1,654 @@ +#include "sofa.h" +#include "sofam.h" +#include + +void iauMoon98 ( double date1, double date2, double pv[2][3] ) +/* +** - - - - - - - - - - +** i a u M o o n 9 8 +** - - - - - - - - - - +** +** Approximate geocentric position and velocity of the Moon. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** n.b. Not IAU-endorsed and without canonical status. +** +** Given: +** date1 double TT date part A (Notes 1,4) +** date2 double TT date part B (Notes 1,4) +** +** Returned: +** pv double[2][3] Moon p,v, GCRS (AU, AU/d, Note 5) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. The limited +** accuracy of the present algorithm is such that any of the methods +** is satisfactory. +** +** 2) This function is a full implementation of the algorithm +** published by Meeus (see reference) except that the light-time +** correction to the Moon's mean longitude has been omitted. +** +** 3) Comparisons with ELP/MPP02 over the interval 1950-2100 gave RMS +** errors of 2.9 arcsec in geocentric direction, 6.1 km in position +** and 36 mm/s in velocity. The worst case errors were 18.3 arcsec +** in geocentric direction, 31.7 km in position and 172 mm/s in +** velocity. +** +** 4) The original algorithm is expressed in terms of "dynamical time", +** which can either be TDB or TT without any significant change in +** accuracy. UT cannot be used without incurring significant errors +** (30 arcsec in the present era) due to the Moon's 0.5 arcsec/sec +** movement. +** +** 5) The result is with respect to the GCRS (the same as J2000.0 mean +** equator and equinox to within 23 mas). +** +** 6) Velocity is obtained by a complete analytical differentiation +** of the Meeus model. +** +** 7) The Meeus algorithm generates position and velocity in mean +** ecliptic coordinates of date, which the present function then +** rotates into GCRS. Because the ecliptic system is precessing, +** there is a coupling between this spin (about 1.4 degrees per +** century) and the Moon position that produces a small velocity +** contribution. In the present function this effect is neglected +** as it corresponds to a maximum difference of less than 3 mm/s and +** increases the RMS error by only 0.4%. +** +** References: +** +** Meeus, J., Astronomical Algorithms, 2nd edition, Willmann-Bell, +** 1998, p337. +** +** Simon, J.L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G. & Laskar, J., Astron.Astrophys., 1994, 282, 663 +** +** Defined in sofam.h: +** DAU astronomical unit (m) +** DJC days per Julian century +** DJ00 reference epoch (J2000.0), Julian Date +** DD2R degrees to radians +** +** Called: +** iauS2pv spherical coordinates to pv-vector +** iauPfw06 bias-precession F-W angles, IAU 2006 +** iauIr initialize r-matrix to identity +** iauRz rotate around Z-axis +** iauRx rotate around X-axis +** iauRxpv product of r-matrix and pv-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* +** Coefficients for fundamental arguments: +** +** . Powers of time in Julian centuries +** . Units are degrees. +*/ + +/* Moon's mean longitude (wrt mean equinox and ecliptic of date) */ + static double elp0 = 218.31665436, /* Simon et al. (1994). */ + elp1 = 481267.88123421, + elp2 = -0.0015786, + elp3 = 1.0 / 538841.0, + elp4 = -1.0 / 65194000.0; + double elp, delp; + +/* Moon's mean elongation */ + static double d0 = 297.8501921, + d1 = 445267.1114034, + d2 = -0.0018819, + d3 = 1.0 / 545868.0, + d4 = 1.0 / 113065000.0; + double d, dd; + +/* Sun's mean anomaly */ + static double em0 = 357.5291092, + em1 = 35999.0502909, + em2 = -0.0001536, + em3 = 1.0 / 24490000.0, + em4 = 0.0; + double em, dem; + +/* Moon's mean anomaly */ + static double emp0 = 134.9633964, + emp1 = 477198.8675055, + emp2 = 0.0087414, + emp3 = 1.0 / 69699.0, + emp4 = -1.0 / 14712000.0; + double emp, demp; + +/* Mean distance of the Moon from its ascending node */ + static double f0 = 93.2720950, + f1 = 483202.0175233, + f2 = -0.0036539, + f3 = 1.0 / 3526000.0, + f4 = 1.0 / 863310000.0; + double f, df; + +/* +** Other arguments +*/ + +/* Meeus A_1, due to Venus (deg) */ + static double a10 = 119.75, + a11 = 131.849; + double a1, da1; + +/* Meeus A_2, due to Jupiter (deg) */ + static double a20 = 53.09, + a21 = 479264.290; + double a2, da2; + +/* Meeus A_3, due to sidereal motion of the Moon in longitude (deg) */ + static double a30 = 313.45, + a31 = 481266.484; + double a3, da3; + +/* Coefficients for Meeus "additive terms" (deg) */ + static double al1 = 0.003958, + al2 = 0.001962, + al3 = 0.000318; + static double ab1 = -0.002235, + ab2 = 0.000382, + ab3 = 0.000175, + ab4 = 0.000175, + ab5 = 0.000127, + ab6 = -0.000115; + +/* Fixed term in distance (m) */ + static double r0 = 385000560.0; + +/* Coefficients for (dimensionless) E factor */ + static double e1 = -0.002516, + e2 = -0.0000074; + double e, de, esq, desq; + +/* +** Coefficients for Moon longitude and distance series +*/ + struct termlr { + int nd; /* multiple of D in argument */ + int nem; /* " " M " " */ + int nemp; /* " " M' " " */ + int nf; /* " " F " " */ + double coefl; /* coefficient of L sine argument (deg) */ + double coefr; /* coefficient of R cosine argument (m) */ + }; + +static struct termlr tlr[] = {{0, 0, 1, 0, 6.288774, -20905355.0}, + {2, 0, -1, 0, 1.274027, -3699111.0}, + {2, 0, 0, 0, 0.658314, -2955968.0}, + {0, 0, 2, 0, 0.213618, -569925.0}, + {0, 1, 0, 0, -0.185116, 48888.0}, + {0, 0, 0, 2, -0.114332, -3149.0}, + {2, 0, -2, 0, 0.058793, 246158.0}, + {2, -1, -1, 0, 0.057066, -152138.0}, + {2, 0, 1, 0, 0.053322, -170733.0}, + {2, -1, 0, 0, 0.045758, -204586.0}, + {0, 1, -1, 0, -0.040923, -129620.0}, + {1, 0, 0, 0, -0.034720, 108743.0}, + {0, 1, 1, 0, -0.030383, 104755.0}, + {2, 0, 0, -2, 0.015327, 10321.0}, + {0, 0, 1, 2, -0.012528, 0.0}, + {0, 0, 1, -2, 0.010980, 79661.0}, + {4, 0, -1, 0, 0.010675, -34782.0}, + {0, 0, 3, 0, 0.010034, -23210.0}, + {4, 0, -2, 0, 0.008548, -21636.0}, + {2, 1, -1, 0, -0.007888, 24208.0}, + {2, 1, 0, 0, -0.006766, 30824.0}, + {1, 0, -1, 0, -0.005163, -8379.0}, + {1, 1, 0, 0, 0.004987, -16675.0}, + {2, -1, 1, 0, 0.004036, -12831.0}, + {2, 0, 2, 0, 0.003994, -10445.0}, + {4, 0, 0, 0, 0.003861, -11650.0}, + {2, 0, -3, 0, 0.003665, 14403.0}, + {0, 1, -2, 0, -0.002689, -7003.0}, + {2, 0, -1, 2, -0.002602, 0.0}, + {2, -1, -2, 0, 0.002390, 10056.0}, + {1, 0, 1, 0, -0.002348, 6322.0}, + {2, -2, 0, 0, 0.002236, -9884.0}, + {0, 1, 2, 0, -0.002120, 5751.0}, + {0, 2, 0, 0, -0.002069, 0.0}, + {2, -2, -1, 0, 0.002048, -4950.0}, + {2, 0, 1, -2, -0.001773, 4130.0}, + {2, 0, 0, 2, -0.001595, 0.0}, + {4, -1, -1, 0, 0.001215, -3958.0}, + {0, 0, 2, 2, -0.001110, 0.0}, + {3, 0, -1, 0, -0.000892, 3258.0}, + {2, 1, 1, 0, -0.000810, 2616.0}, + {4, -1, -2, 0, 0.000759, -1897.0}, + {0, 2, -1, 0, -0.000713, -2117.0}, + {2, 2, -1, 0, -0.000700, 2354.0}, + {2, 1, -2, 0, 0.000691, 0.0}, + {2, -1, 0, -2, 0.000596, 0.0}, + {4, 0, 1, 0, 0.000549, -1423.0}, + {0, 0, 4, 0, 0.000537, -1117.0}, + {4, -1, 0, 0, 0.000520, -1571.0}, + {1, 0, -2, 0, -0.000487, -1739.0}, + {2, 1, 0, -2, -0.000399, 0.0}, + {0, 0, 2, -2, -0.000381, -4421.0}, + {1, 1, 1, 0, 0.000351, 0.0}, + {3, 0, -2, 0, -0.000340, 0.0}, + {4, 0, -3, 0, 0.000330, 0.0}, + {2, -1, 2, 0, 0.000327, 0.0}, + {0, 2, 1, 0, -0.000323, 1165.0}, + {1, 1, -1, 0, 0.000299, 0.0}, + {2, 0, 3, 0, 0.000294, 0.0}, + {2, 0, -1, -2, 0.000000, 8752.0}}; + + static int NLR = ( sizeof tlr / sizeof ( struct termlr ) ); + +/* +** Coefficients for Moon latitude series +*/ + struct termb { + int nd; /* multiple of D in argument */ + int nem; /* " " M " " */ + int nemp; /* " " M' " " */ + int nf; /* " " F " " */ + double coefb; /* coefficient of B sine argument (deg) */ + }; + +static struct termb tb[] = {{0, 0, 0, 1, 5.128122}, + {0, 0, 1, 1, 0.280602}, + {0, 0, 1, -1, 0.277693}, + {2, 0, 0, -1, 0.173237}, + {2, 0, -1, 1, 0.055413}, + {2, 0, -1, -1, 0.046271}, + {2, 0, 0, 1, 0.032573}, + {0, 0, 2, 1, 0.017198}, + {2, 0, 1, -1, 0.009266}, + {0, 0, 2, -1, 0.008822}, + {2, -1, 0, -1, 0.008216}, + {2, 0, -2, -1, 0.004324}, + {2, 0, 1, 1, 0.004200}, + {2, 1, 0, -1, -0.003359}, + {2, -1, -1, 1, 0.002463}, + {2, -1, 0, 1, 0.002211}, + {2, -1, -1, -1, 0.002065}, + {0, 1, -1, -1, -0.001870}, + {4, 0, -1, -1, 0.001828}, + {0, 1, 0, 1, -0.001794}, + {0, 0, 0, 3, -0.001749}, + {0, 1, -1, 1, -0.001565}, + {1, 0, 0, 1, -0.001491}, + {0, 1, 1, 1, -0.001475}, + {0, 1, 1, -1, -0.001410}, + {0, 1, 0, -1, -0.001344}, + {1, 0, 0, -1, -0.001335}, + {0, 0, 3, 1, 0.001107}, + {4, 0, 0, -1, 0.001021}, + {4, 0, -1, 1, 0.000833}, + {0, 0, 1, -3, 0.000777}, + {4, 0, -2, 1, 0.000671}, + {2, 0, 0, -3, 0.000607}, + {2, 0, 2, -1, 0.000596}, + {2, -1, 1, -1, 0.000491}, + {2, 0, -2, 1, -0.000451}, + {0, 0, 3, -1, 0.000439}, + {2, 0, 2, 1, 0.000422}, + {2, 0, -3, -1, 0.000421}, + {2, 1, -1, 1, -0.000366}, + {2, 1, 0, 1, -0.000351}, + {4, 0, 0, 1, 0.000331}, + {2, -1, 1, 1, 0.000315}, + {2, -2, 0, -1, 0.000302}, + {0, 0, 1, 3, -0.000283}, + {2, 1, 1, -1, -0.000229}, + {1, 1, 0, -1, 0.000223}, + {1, 1, 0, 1, 0.000223}, + {0, 1, -2, -1, -0.000220}, + {2, 1, -1, -1, -0.000220}, + {1, 0, 1, 1, -0.000185}, + {2, -1, -2, -1, 0.000181}, + {0, 1, 2, 1, -0.000177}, + {4, 0, -2, -1, 0.000176}, + {4, -1, -1, -1, 0.000166}, + {1, 0, 1, -1, -0.000164}, + {4, 0, 1, -1, 0.000132}, + {1, 0, -1, -1, -0.000119}, + {4, -1, 0, -1, 0.000115}, + {2, -2, 0, 1, 0.000107}}; + + static int NB = ( sizeof tb / sizeof ( struct termb ) ); + +/* Miscellaneous */ + int n, i; + double t, elpmf, delpmf, vel, vdel, vr, vdr, a1mf, da1mf, a1pf, + da1pf, dlpmp, slpmp, vb, vdb, v, dv, emn, empn, dn, fn, en, + den, arg, darg, farg, coeff, el, del, r, dr, b, db, gamb, + phib, psib, epsa, rm[3][3]; + +/* ------------------------------------------------------------------ */ + +/* Centuries since J2000.0 */ + t = ((date1 - DJ00) + date2) / DJC; + +/* --------------------- */ +/* Fundamental arguments */ +/* --------------------- */ + +/* Arguments (radians) and derivatives (radians per Julian century) + for the current date. */ + +/* Moon's mean longitude. */ + elp = DD2R * fmod ( elp0 + + ( elp1 + + ( elp2 + + ( elp3 + + elp4 * t ) * t ) * t ) * t, 360.0 ); + delp = DD2R * ( elp1 + + ( elp2 * 2.0 + + ( elp3 * 3.0 + + elp4 * 4.0 * t ) * t ) * t ); + +/* Moon's mean elongation. */ + d = DD2R * fmod ( d0 + + ( d1 + + ( d2 + + ( d3 + + d4 * t ) * t ) * t ) * t, 360.0 ); + dd = DD2R * ( d1 + + ( d2 * 2.0 + + ( d3 * 3.0 + + d4 * 4.0 * t ) * t ) * t ); + +/* Sun's mean anomaly. */ + em = DD2R * fmod ( em0 + + ( em1 + + ( em2 + + ( em3 + + em4 * t ) * t ) * t ) * t, 360.0 ); + dem = DD2R * ( em1 + + ( em2 * 2.0 + + ( em3 * 3.0 + + em4 * 4.0 * t ) * t ) * t ); + +/* Moon's mean anomaly. */ + emp = DD2R * fmod ( emp0 + + ( emp1 + + ( emp2 + + ( emp3 + + emp4 * t ) * t ) * t ) * t, 360.0 ); + demp = DD2R * ( emp1 + + ( emp2 * 2.0 + + ( emp3 * 3.0 + + emp4 * 4.0 * t ) * t ) * t ); + +/* Mean distance of the Moon from its ascending node. */ + f = DD2R * fmod ( f0 + + ( f1 + + ( f2 + + ( f3 + + f4 * t ) * t ) * t ) * t, 360.0 ); + df = DD2R * ( f1 + + ( f2 * 2.0 + + ( f3 * 3.0 + + f4 * 4.0 * t ) * t ) * t ); + +/* Meeus further arguments. */ + a1 = DD2R * ( a10 + a11*t ); + da1 = DD2R * al1; + a2 = DD2R * ( a20 + a21*t ); + da2 = DD2R * a21; + a3 = DD2R * ( a30 + a31*t ); + da3 = DD2R * a31; + +/* E-factor, and square. */ + e = 1.0 + ( e1 + e2*t ) * t; + de = e1 + 2.0*e2*t; + esq = e*e; + desq = 2.0*e*de; + +/* Use the Meeus additive terms (deg) to start off the summations. */ + elpmf = elp - f; + delpmf = delp - df; + vel = al1 * sin(a1) + + al2 * sin(elpmf) + + al3 * sin(a2); + vdel = al1 * cos(a1) * da1 + + al2 * cos(elpmf) * delpmf + + al3 * cos(a2) * da2; + + vr = 0.0; + vdr = 0.0; + + a1mf = a1 - f; + da1mf = da1 - df; + a1pf = a1 + f; + da1pf = da1 + df; + dlpmp = elp - emp; + slpmp = elp + emp; + vb = ab1 * sin(elp) + + ab2 * sin(a3) + + ab3 * sin(a1mf) + + ab4 * sin(a1pf) + + ab5 * sin(dlpmp) + + ab6 * sin(slpmp); + vdb = ab1 * cos(elp) * delp + + ab2 * cos(a3) * da3 + + ab3 * cos(a1mf) * da1mf + + ab4 * cos(a1pf) * da1pf + + ab5 * cos(dlpmp) * (delp-demp) + + ab6 * cos(slpmp) * (delp+demp); + +/* ----------------- */ +/* Series expansions */ +/* ----------------- */ + +/* Longitude and distance plus derivatives. */ + for ( n = NLR-1; n >= 0; n-- ) { + dn = (double) tlr[n].nd; + emn = (double) ( i = tlr[n].nem ); + empn = (double) tlr[n].nemp; + fn = (double) tlr[n].nf; + switch ( abs(i) ) { + case 1: + en = e; + den = de; + break; + case 2: + en = esq; + den = desq; + break; + default: + en = 1.0; + den = 0.0; + } + arg = dn*d + emn*em + empn*emp + fn*f; + darg = dn*dd + emn*dem + empn*demp + fn*df; + farg = sin(arg); + v = farg * en; + dv = cos(arg)*darg*en + farg*den; + coeff = tlr[n].coefl; + vel += coeff * v; + vdel += coeff * dv; + farg = cos(arg); + v = farg * en; + dv = -sin(arg)*darg*en + farg*den; + coeff = tlr[n].coefr; + vr += coeff * v; + vdr += coeff * dv; + } + el = elp + DD2R*vel; + del = ( delp + DD2R*vdel ) / DJC; + r = ( vr + r0 ) / DAU; + dr = vdr / DAU / DJC; + +/* Latitude plus derivative. */ + for ( n = NB-1; n >= 0; n-- ) { + dn = (double) tb[n].nd; + emn = (double) ( i = tb[n].nem ); + empn = (double) tb[n].nemp; + fn = (double) tb[n].nf; + switch ( abs(i) ) { + case 1: + en = e; + den = de; + break; + case 2: + en = esq; + den = desq; + break; + default: + en = 1.0; + den = 0.0; + } + arg = dn*d + emn*em + empn*emp + fn*f; + darg = dn*dd + emn*dem + empn*demp + fn*df; + farg = sin(arg); + v = farg * en; + dv = cos(arg)*darg*en + farg*den; + coeff = tb[n].coefb; + vb += coeff * v; + vdb += coeff * dv; + } + b = vb * DD2R; + db = vdb * DD2R / DJC; + +/* ------------------------------ */ +/* Transformation into final form */ +/* ------------------------------ */ + +/* Longitude, latitude to x, y, z (AU). */ + iauS2pv ( el, b, r, del, db, dr, pv ); + +/* IAU 2006 Fukushima-Williams bias+precession angles. */ + iauPfw06 ( date1, date2, &gamb, &phib, &psib, &epsa ); + +/* Mean ecliptic coordinates to GCRS rotation matrix. */ + iauIr ( rm ); + iauRz ( psib, rm ); + iauRx ( -phib, rm ); + iauRz ( -gamb, rm ); + +/* Rotate the Moon position and velocity into GCRS (Note 6). */ + iauRxpv ( rm, pv, pv ); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/num00a.c b/src/cpp/3rdparty/sofa/src/num00a.c new file mode 100644 index 000000000..98f7bbfbe --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/num00a.c @@ -0,0 +1,171 @@ +#include "sofa.h" + +void iauNum00a(double date1, double date2, double rmatn[3][3]) +/* +** - - - - - - - - - - +** i a u N u m 0 0 a +** - - - - - - - - - - +** +** Form the matrix of nutation for a given date, IAU 2000A model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rmatn double[3][3] nutation matrix +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(true) = rmatn * V(mean), where +** the p-vector V(true) is with respect to the true equatorial triad +** of date and the p-vector V(mean) is with respect to the mean +** equatorial triad of date. +** +** 3) A faster, but slightly less accurate, result (about 1 mas) can be +** obtained by using instead the iauNum00b function. +** +** Called: +** iauPn00a bias/precession/nutation, IAU 2000A +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 3.222-3 (p114). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsi, deps, epsa, rb[3][3], rp[3][3], rbp[3][3], rbpn[3][3]; + + +/* Obtain the required matrix (discarding other results). */ + iauPn00a(date1, date2, + &dpsi, &deps, &epsa, rb, rp, rbp, rmatn, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/num00b.c b/src/cpp/3rdparty/sofa/src/num00b.c new file mode 100644 index 000000000..1678241a5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/num00b.c @@ -0,0 +1,171 @@ +#include "sofa.h" + +void iauNum00b(double date1, double date2, double rmatn[3][3]) +/* +** - - - - - - - - - - +** i a u N u m 0 0 b +** - - - - - - - - - - +** +** Form the matrix of nutation for a given date, IAU 2000B model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rmatn double[3][3] nutation matrix +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(true) = rmatn * V(mean), where +** the p-vector V(true) is with respect to the true equatorial triad +** of date and the p-vector V(mean) is with respect to the mean +** equatorial triad of date. +** +** 3) The present function is faster, but slightly less accurate (about +** 1 mas), than the iauNum00a function. +** +** Called: +** iauPn00b bias/precession/nutation, IAU 2000B +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 3.222-3 (p114). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsi, deps, epsa, rb[3][3], rp[3][3], rbp[3][3], rbpn[3][3]; + + +/* Obtain the required matrix (discarding other results). */ + iauPn00b(date1, date2, + &dpsi, &deps, &epsa, rb, rp, rbp, rmatn, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/num06a.c b/src/cpp/3rdparty/sofa/src/num06a.c new file mode 100644 index 000000000..eb19e2c70 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/num06a.c @@ -0,0 +1,175 @@ +#include "sofa.h" + +void iauNum06a(double date1, double date2, double rmatn[3][3]) +/* +** - - - - - - - - - - +** i a u N u m 0 6 a +** - - - - - - - - - - +** +** Form the matrix of nutation for a given date, IAU 2006/2000A model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rmatn double[3][3] nutation matrix +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(true) = rmatn * V(mean), where +** the p-vector V(true) is with respect to the true equatorial triad +** of date and the p-vector V(mean) is with respect to the mean +** equatorial triad of date. +** +** Called: +** iauObl06 mean obliquity, IAU 2006 +** iauNut06a nutation, IAU 2006/2000A +** iauNumat form nutation matrix +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 3.222-3 (p114). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double eps, dp, de; + + +/* Mean obliquity. */ + eps = iauObl06(date1, date2); + +/* Nutation components. */ + iauNut06a(date1, date2, &dp, &de); + +/* Nutation matrix. */ + iauNumat(eps, dp, de, rmatn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/numat.c b/src/cpp/3rdparty/sofa/src/numat.c new file mode 100644 index 000000000..1e0ec29e8 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/numat.c @@ -0,0 +1,159 @@ +#include "sofa.h" + +void iauNumat(double epsa, double dpsi, double deps, double rmatn[3][3]) +/* +** - - - - - - - - - +** i a u N u m a t +** - - - - - - - - - +** +** Form the matrix of nutation. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** epsa double mean obliquity of date (Note 1) +** dpsi,deps double nutation (Note 2) +** +** Returned: +** rmatn double[3][3] nutation matrix (Note 3) +** +** Notes: +** +** +** 1) The supplied mean obliquity epsa, must be consistent with the +** precession-nutation models from which dpsi and deps were obtained. +** +** 2) The caller is responsible for providing the nutation components; +** they are in longitude and obliquity, in radians and are with +** respect to the equinox and ecliptic of date. +** +** 3) The matrix operates in the sense V(true) = rmatn * V(mean), +** where the p-vector V(true) is with respect to the true +** equatorial triad of date and the p-vector V(mean) is with +** respect to the mean equatorial triad of date. +** +** Called: +** iauIr initialize r-matrix to identity +** iauRx rotate around X-axis +** iauRz rotate around Z-axis +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 3.222-3 (p114). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Build the rotation matrix. */ + iauIr(rmatn); + iauRx(epsa, rmatn); + iauRz(-dpsi, rmatn); + iauRx(-(epsa + deps), rmatn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/nut00a.c b/src/cpp/3rdparty/sofa/src/nut00a.c new file mode 100644 index 000000000..b57a285c4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/nut00a.c @@ -0,0 +1,2098 @@ +#include "sofa.h" +#include "sofam.h" + +void iauNut00a(double date1, double date2, double *dpsi, double *deps) +/* +** - - - - - - - - - - +** i a u N u t 0 0 a +** - - - - - - - - - - +** +** Nutation, IAU 2000A model (MHB2000 luni-solar and planetary nutation +** with free core nutation omitted). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsi,deps double nutation, luni-solar + planetary (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The nutation components in longitude and obliquity are in radians +** and with respect to the equinox and ecliptic of date. The +** obliquity at J2000.0 is assumed to be the Lieske et al. (1977) +** value of 84381.448 arcsec. +** +** Both the luni-solar and planetary nutations are included. The +** latter are due to direct planetary nutations and the +** perturbations of the lunar and terrestrial orbits. +** +** 3) The function computes the MHB2000 nutation series with the +** associated corrections for planetary nutations. It is an +** implementation of the nutation part of the IAU 2000A precession- +** nutation model, formally adopted by the IAU General Assembly in +** 2000, namely MHB2000 (Mathews et al. 2002), but with the free +** core nutation (FCN - see Note 4) omitted. +** +** 4) The full MHB2000 model also contains contributions to the +** nutations in longitude and obliquity due to the free-excitation +** of the free-core-nutation during the period 1979-2000. These FCN +** terms, which are time-dependent and unpredictable, are NOT +** included in the present function and, if required, must be +** independently computed. With the FCN corrections included, the +** present function delivers a pole which is at current epochs +** accurate to a few hundred microarcseconds. The omission of FCN +** introduces further errors of about that size. +** +** 5) The present function provides classical nutation. The MHB2000 +** algorithm, from which it is adapted, deals also with (i) the +** offsets between the GCRS and mean poles and (ii) the adjustments +** in longitude and obliquity due to the changed precession rates. +** These additional functions, namely frame bias and precession +** adjustments, are supported by the SOFA functions iauBi00 and +** iauPr00. +** +** 6) The MHB2000 algorithm also provides "total" nutations, comprising +** the arithmetic sum of the frame bias, precession adjustments, +** luni-solar nutation and planetary nutation. These total +** nutations can be used in combination with an existing IAU 1976 +** precession implementation, such as iauPmat76, to deliver GCRS- +** to-true predictions of sub-mas accuracy at current dates. +** However, there are three shortcomings in the MHB2000 model that +** must be taken into account if more accurate or definitive results +** are required (see Wallace 2002): +** +** (i) The MHB2000 total nutations are simply arithmetic sums, +** yet in reality the various components are successive Euler +** rotations. This slight lack of rigor leads to cross terms +** that exceed 1 mas after a century. The rigorous procedure +** is to form the GCRS-to-true rotation matrix by applying the +** bias, precession and nutation in that order. +** +** (ii) Although the precession adjustments are stated to be with +** respect to Lieske et al. (1977), the MHB2000 model does +** not specify which set of Euler angles are to be used and +** how the adjustments are to be applied. The most literal +** and straightforward procedure is to adopt the 4-rotation +** epsilon_0, psi_A, omega_A, xi_A option, and to add DPSIPR +** to psi_A and DEPSPR to both omega_A and eps_A. +** +** (iii) The MHB2000 model predates the determination by Chapront +** et al. (2002) of a 14.6 mas displacement between the +** J2000.0 mean equinox and the origin of the ICRS frame. It +** should, however, be noted that neglecting this displacement +** when calculating star coordinates does not lead to a +** 14.6 mas change in right ascension, only a small second- +** order distortion in the pattern of the precession-nutation +** effect. +** +** For these reasons, the SOFA functions do not generate the "total +** nutations" directly, though they can of course easily be +** generated by calling iauBi00, iauPr00 and the present function +** and adding the results. +** +** 7) The MHB2000 model contains 41 instances where the same frequency +** appears multiple times, of which 38 are duplicates and three are +** triplicates. To keep the present code close to the original MHB +** algorithm, this small inefficiency has not been corrected. +** +** Called: +** iauFal03 mean anomaly of the Moon +** iauFaf03 mean argument of the latitude of the Moon +** iauFaom03 mean longitude of the Moon's ascending node +** iauFame03 mean longitude of Mercury +** iauFave03 mean longitude of Venus +** iauFae03 mean longitude of Earth +** iauFama03 mean longitude of Mars +** iauFaju03 mean longitude of Jupiter +** iauFasa03 mean longitude of Saturn +** iauFaur03 mean longitude of Uranus +** iauFapa03 general accumulated precession in longitude +** +** References: +** +** Chapront, J., Chapront-Touze, M. & Francou, G. 2002, +** Astron.Astrophys. 387, 700 +** +** Lieske, J.H., Lederle, T., Fricke, W. & Morando, B. 1977, +** Astron.Astrophys. 58, 1-16 +** +** Mathews, P.M., Herring, T.A., Buffet, B.A. 2002, J.Geophys.Res. +** 107, B4. The MHB_2000 code itself was obtained on 9th September +** 2002 from ftp//maia.usno.navy.mil/conv2000/chapter5/IAU2000A. +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** Wallace, P.T., "Software for Implementing the IAU 2000 +** Resolutions", in IERS Workshop 5.1 (2002) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int i; + double t, el, elp, f, d, om, arg, dp, de, sarg, carg, + al, af, ad, aom, alme, alve, alea, alma, + alju, alsa, alur, alne, apa, dpsils, depsls, + dpsipl, depspl; + +/* Units of 0.1 microarcsecond to radians */ + const double U2R = DAS2R / 1e7; + +/* ------------------------- */ +/* Luni-Solar nutation model */ +/* ------------------------- */ + +/* The units for the sine and cosine coefficients are */ +/* 0.1 microarcsecond and the same per Julian century */ + + static const struct { + int nl,nlp,nf,nd,nom; /* coefficients of l,l',F,D,Om */ + double sp,spt,cp; /* longitude sin, t*sin, cos coefficients */ + double ce,cet,se; /* obliquity cos, t*cos, sin coefficients */ + } xls[] = { + + /* 1- 10 */ + { 0, 0, 0, 0, 1, + -172064161.0, -174666.0, 33386.0, 92052331.0, 9086.0, 15377.0}, + { 0, 0, 2,-2, 2, + -13170906.0, -1675.0, -13696.0, 5730336.0, -3015.0, -4587.0}, + { 0, 0, 2, 0, 2,-2276413.0,-234.0,2796.0,978459.0,-485.0, 1374.0}, + { 0, 0, 0, 0, 2,2074554.0, 207.0, -698.0,-897492.0,470.0, -291.0}, + { 0, 1, 0, 0, 0,1475877.0,-3633.0,11817.0,73871.0,-184.0,-1924.0}, + { 0, 1, 2,-2, 2,-516821.0,1226.0, -524.0,224386.0,-677.0, -174.0}, + { 1, 0, 0, 0, 0, 711159.0, 73.0, -872.0, -6750.0, 0.0, 358.0}, + { 0, 0, 2, 0, 1,-387298.0,-367.0, 380.0, 200728.0, 18.0, 318.0}, + { 1, 0, 2, 0, 2,-301461.0, -36.0, 816.0, 129025.0,-63.0, 367.0}, + { 0,-1, 2,-2, 2, 215829.0,-494.0, 111.0, -95929.0,299.0, 132.0}, + + /* 11-20 */ + { 0, 0, 2,-2, 1, 128227.0, 137.0, 181.0, -68982.0, -9.0, 39.0}, + {-1, 0, 2, 0, 2, 123457.0, 11.0, 19.0, -53311.0, 32.0, -4.0}, + {-1, 0, 0, 2, 0, 156994.0, 10.0, -168.0, -1235.0, 0.0, 82.0}, + { 1, 0, 0, 0, 1, 63110.0, 63.0, 27.0, -33228.0, 0.0, -9.0}, + {-1, 0, 0, 0, 1, -57976.0, -63.0, -189.0, 31429.0, 0.0, -75.0}, + {-1, 0, 2, 2, 2, -59641.0, -11.0, 149.0, 25543.0,-11.0, 66.0}, + { 1, 0, 2, 0, 1, -51613.0, -42.0, 129.0, 26366.0, 0.0, 78.0}, + {-2, 0, 2, 0, 1, 45893.0, 50.0, 31.0, -24236.0,-10.0, 20.0}, + { 0, 0, 0, 2, 0, 63384.0, 11.0, -150.0, -1220.0, 0.0, 29.0}, + { 0, 0, 2, 2, 2, -38571.0, -1.0, 158.0, 16452.0,-11.0, 68.0}, + + /* 21-30 */ + { 0,-2, 2,-2, 2, 32481.0, 0.0, 0.0, -13870.0, 0.0, 0.0}, + {-2, 0, 0, 2, 0, -47722.0, 0.0, -18.0, 477.0, 0.0, -25.0}, + { 2, 0, 2, 0, 2, -31046.0, -1.0, 131.0, 13238.0,-11.0, 59.0}, + { 1, 0, 2,-2, 2, 28593.0, 0.0, -1.0, -12338.0, 10.0, -3.0}, + {-1, 0, 2, 0, 1, 20441.0, 21.0, 10.0, -10758.0, 0.0, -3.0}, + { 2, 0, 0, 0, 0, 29243.0, 0.0, -74.0, -609.0, 0.0, 13.0}, + { 0, 0, 2, 0, 0, 25887.0, 0.0, -66.0, -550.0, 0.0, 11.0}, + { 0, 1, 0, 0, 1, -14053.0, -25.0, 79.0, 8551.0, -2.0, -45.0}, + {-1, 0, 0, 2, 1, 15164.0, 10.0, 11.0, -8001.0, 0.0, -1.0}, + { 0, 2, 2,-2, 2, -15794.0, 72.0, -16.0, 6850.0,-42.0, -5.0}, + + /* 31-40 */ + { 0, 0,-2, 2, 0, 21783.0, 0.0, 13.0, -167.0, 0.0, 13.0}, + { 1, 0, 0,-2, 1, -12873.0, -10.0, -37.0, 6953.0, 0.0, -14.0}, + { 0,-1, 0, 0, 1, -12654.0, 11.0, 63.0, 6415.0, 0.0, 26.0}, + {-1, 0, 2, 2, 1, -10204.0, 0.0, 25.0, 5222.0, 0.0, 15.0}, + { 0, 2, 0, 0, 0, 16707.0, -85.0, -10.0, 168.0, -1.0, 10.0}, + { 1, 0, 2, 2, 2, -7691.0, 0.0, 44.0, 3268.0, 0.0, 19.0}, + {-2, 0, 2, 0, 0, -11024.0, 0.0, -14.0, 104.0, 0.0, 2.0}, + { 0, 1, 2, 0, 2, 7566.0, -21.0, -11.0, -3250.0, 0.0, -5.0}, + { 0, 0, 2, 2, 1, -6637.0, -11.0, 25.0, 3353.0, 0.0, 14.0}, + { 0,-1, 2, 0, 2, -7141.0, 21.0, 8.0, 3070.0, 0.0, 4.0}, + + /* 41-50 */ + { 0, 0, 0, 2, 1, -6302.0, -11.0, 2.0, 3272.0, 0.0, 4.0}, + { 1, 0, 2,-2, 1, 5800.0, 10.0, 2.0, -3045.0, 0.0, -1.0}, + { 2, 0, 2,-2, 2, 6443.0, 0.0, -7.0, -2768.0, 0.0, -4.0}, + {-2, 0, 0, 2, 1, -5774.0, -11.0, -15.0, 3041.0, 0.0, -5.0}, + { 2, 0, 2, 0, 1, -5350.0, 0.0, 21.0, 2695.0, 0.0, 12.0}, + { 0,-1, 2,-2, 1, -4752.0, -11.0, -3.0, 2719.0, 0.0, -3.0}, + { 0, 0, 0,-2, 1, -4940.0, -11.0, -21.0, 2720.0, 0.0, -9.0}, + {-1,-1, 0, 2, 0, 7350.0, 0.0, -8.0, -51.0, 0.0, 4.0}, + { 2, 0, 0,-2, 1, 4065.0, 0.0, 6.0, -2206.0, 0.0, 1.0}, + { 1, 0, 0, 2, 0, 6579.0, 0.0, -24.0, -199.0, 0.0, 2.0}, + + /* 51-60 */ + { 0, 1, 2,-2, 1, 3579.0, 0.0, 5.0, -1900.0, 0.0, 1.0}, + { 1,-1, 0, 0, 0, 4725.0, 0.0, -6.0, -41.0, 0.0, 3.0}, + {-2, 0, 2, 0, 2, -3075.0, 0.0, -2.0, 1313.0, 0.0, -1.0}, + { 3, 0, 2, 0, 2, -2904.0, 0.0, 15.0, 1233.0, 0.0, 7.0}, + { 0,-1, 0, 2, 0, 4348.0, 0.0, -10.0, -81.0, 0.0, 2.0}, + { 1,-1, 2, 0, 2, -2878.0, 0.0, 8.0, 1232.0, 0.0, 4.0}, + { 0, 0, 0, 1, 0, -4230.0, 0.0, 5.0, -20.0, 0.0, -2.0}, + {-1,-1, 2, 2, 2, -2819.0, 0.0, 7.0, 1207.0, 0.0, 3.0}, + {-1, 0, 2, 0, 0, -4056.0, 0.0, 5.0, 40.0, 0.0, -2.0}, + { 0,-1, 2, 2, 2, -2647.0, 0.0, 11.0, 1129.0, 0.0, 5.0}, + + /* 61-70 */ + {-2, 0, 0, 0, 1, -2294.0, 0.0, -10.0, 1266.0, 0.0, -4.0}, + { 1, 1, 2, 0, 2, 2481.0, 0.0, -7.0, -1062.0, 0.0, -3.0}, + { 2, 0, 0, 0, 1, 2179.0, 0.0, -2.0, -1129.0, 0.0, -2.0}, + {-1, 1, 0, 1, 0, 3276.0, 0.0, 1.0, -9.0, 0.0, 0.0}, + { 1, 1, 0, 0, 0, -3389.0, 0.0, 5.0, 35.0, 0.0, -2.0}, + { 1, 0, 2, 0, 0, 3339.0, 0.0, -13.0, -107.0, 0.0, 1.0}, + {-1, 0, 2,-2, 1, -1987.0, 0.0, -6.0, 1073.0, 0.0, -2.0}, + { 1, 0, 0, 0, 2, -1981.0, 0.0, 0.0, 854.0, 0.0, 0.0}, + {-1, 0, 0, 1, 0, 4026.0, 0.0, -353.0, -553.0, 0.0, -139.0}, + { 0, 0, 2, 1, 2, 1660.0, 0.0, -5.0, -710.0, 0.0, -2.0}, + + /* 71-80 */ + {-1, 0, 2, 4, 2, -1521.0, 0.0, 9.0, 647.0, 0.0, 4.0}, + {-1, 1, 0, 1, 1, 1314.0, 0.0, 0.0, -700.0, 0.0, 0.0}, + { 0,-2, 2,-2, 1, -1283.0, 0.0, 0.0, 672.0, 0.0, 0.0}, + { 1, 0, 2, 2, 1, -1331.0, 0.0, 8.0, 663.0, 0.0, 4.0}, + {-2, 0, 2, 2, 2, 1383.0, 0.0, -2.0, -594.0, 0.0, -2.0}, + {-1, 0, 0, 0, 2, 1405.0, 0.0, 4.0, -610.0, 0.0, 2.0}, + { 1, 1, 2,-2, 2, 1290.0, 0.0, 0.0, -556.0, 0.0, 0.0}, + {-2, 0, 2, 4, 2, -1214.0, 0.0, 5.0, 518.0, 0.0, 2.0}, + {-1, 0, 4, 0, 2, 1146.0, 0.0, -3.0, -490.0, 0.0, -1.0}, + { 2, 0, 2,-2, 1, 1019.0, 0.0, -1.0, -527.0, 0.0, -1.0}, + + /* 81-90 */ + { 2, 0, 2, 2, 2, -1100.0, 0.0, 9.0, 465.0, 0.0, 4.0}, + { 1, 0, 0, 2, 1, -970.0, 0.0, 2.0, 496.0, 0.0, 1.0}, + { 3, 0, 0, 0, 0, 1575.0, 0.0, -6.0, -50.0, 0.0, 0.0}, + { 3, 0, 2,-2, 2, 934.0, 0.0, -3.0, -399.0, 0.0, -1.0}, + { 0, 0, 4,-2, 2, 922.0, 0.0, -1.0, -395.0, 0.0, -1.0}, + { 0, 1, 2, 0, 1, 815.0, 0.0, -1.0, -422.0, 0.0, -1.0}, + { 0, 0,-2, 2, 1, 834.0, 0.0, 2.0, -440.0, 0.0, 1.0}, + { 0, 0, 2,-2, 3, 1248.0, 0.0, 0.0, -170.0, 0.0, 1.0}, + {-1, 0, 0, 4, 0, 1338.0, 0.0, -5.0, -39.0, 0.0, 0.0}, + { 2, 0,-2, 0, 1, 716.0, 0.0, -2.0, -389.0, 0.0, -1.0}, + + /* 91-100 */ + {-2, 0, 0, 4, 0, 1282.0, 0.0, -3.0, -23.0, 0.0, 1.0}, + {-1,-1, 0, 2, 1, 742.0, 0.0, 1.0, -391.0, 0.0, 0.0}, + {-1, 0, 0, 1, 1, 1020.0, 0.0, -25.0, -495.0, 0.0, -10.0}, + { 0, 1, 0, 0, 2, 715.0, 0.0, -4.0, -326.0, 0.0, 2.0}, + { 0, 0,-2, 0, 1, -666.0, 0.0, -3.0, 369.0, 0.0, -1.0}, + { 0,-1, 2, 0, 1, -667.0, 0.0, 1.0, 346.0, 0.0, 1.0}, + { 0, 0, 2,-1, 2, -704.0, 0.0, 0.0, 304.0, 0.0, 0.0}, + { 0, 0, 2, 4, 2, -694.0, 0.0, 5.0, 294.0, 0.0, 2.0}, + {-2,-1, 0, 2, 0, -1014.0, 0.0, -1.0, 4.0, 0.0, -1.0}, + { 1, 1, 0,-2, 1, -585.0, 0.0, -2.0, 316.0, 0.0, -1.0}, + + /* 101-110 */ + {-1, 1, 0, 2, 0, -949.0, 0.0, 1.0, 8.0, 0.0, -1.0}, + {-1, 1, 0, 1, 2, -595.0, 0.0, 0.0, 258.0, 0.0, 0.0}, + { 1,-1, 0, 0, 1, 528.0, 0.0, 0.0, -279.0, 0.0, 0.0}, + { 1,-1, 2, 2, 2, -590.0, 0.0, 4.0, 252.0, 0.0, 2.0}, + {-1, 1, 2, 2, 2, 570.0, 0.0, -2.0, -244.0, 0.0, -1.0}, + { 3, 0, 2, 0, 1, -502.0, 0.0, 3.0, 250.0, 0.0, 2.0}, + { 0, 1,-2, 2, 0, -875.0, 0.0, 1.0, 29.0, 0.0, 0.0}, + {-1, 0, 0,-2, 1, -492.0, 0.0, -3.0, 275.0, 0.0, -1.0}, + { 0, 1, 2, 2, 2, 535.0, 0.0, -2.0, -228.0, 0.0, -1.0}, + {-1,-1, 2, 2, 1, -467.0, 0.0, 1.0, 240.0, 0.0, 1.0}, + + /* 111-120 */ + { 0,-1, 0, 0, 2, 591.0, 0.0, 0.0, -253.0, 0.0, 0.0}, + { 1, 0, 2,-4, 1, -453.0, 0.0, -1.0, 244.0, 0.0, -1.0}, + {-1, 0,-2, 2, 0, 766.0, 0.0, 1.0, 9.0, 0.0, 0.0}, + { 0,-1, 2, 2, 1, -446.0, 0.0, 2.0, 225.0, 0.0, 1.0}, + { 2,-1, 2, 0, 2, -488.0, 0.0, 2.0, 207.0, 0.0, 1.0}, + { 0, 0, 0, 2, 2, -468.0, 0.0, 0.0, 201.0, 0.0, 0.0}, + { 1,-1, 2, 0, 1, -421.0, 0.0, 1.0, 216.0, 0.0, 1.0}, + {-1, 1, 2, 0, 2, 463.0, 0.0, 0.0, -200.0, 0.0, 0.0}, + { 0, 1, 0, 2, 0, -673.0, 0.0, 2.0, 14.0, 0.0, 0.0}, + { 0,-1,-2, 2, 0, 658.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + + /* 121-130 */ + { 0, 3, 2,-2, 2, -438.0, 0.0, 0.0, 188.0, 0.0, 0.0}, + { 0, 0, 0, 1, 1, -390.0, 0.0, 0.0, 205.0, 0.0, 0.0}, + {-1, 0, 2, 2, 0, 639.0, -11.0, -2.0, -19.0, 0.0, 0.0}, + { 2, 1, 2, 0, 2, 412.0, 0.0, -2.0, -176.0, 0.0, -1.0}, + { 1, 1, 0, 0, 1, -361.0, 0.0, 0.0, 189.0, 0.0, 0.0}, + { 1, 1, 2, 0, 1, 360.0, 0.0, -1.0, -185.0, 0.0, -1.0}, + { 2, 0, 0, 2, 0, 588.0, 0.0, -3.0, -24.0, 0.0, 0.0}, + { 1, 0,-2, 2, 0, -578.0, 0.0, 1.0, 5.0, 0.0, 0.0}, + {-1, 0, 0, 2, 2, -396.0, 0.0, 0.0, 171.0, 0.0, 0.0}, + { 0, 1, 0, 1, 0, 565.0, 0.0, -1.0, -6.0, 0.0, 0.0}, + + /* 131-140 */ + { 0, 1, 0,-2, 1, -335.0, 0.0, -1.0, 184.0, 0.0, -1.0}, + {-1, 0, 2,-2, 2, 357.0, 0.0, 1.0, -154.0, 0.0, 0.0}, + { 0, 0, 0,-1, 1, 321.0, 0.0, 1.0, -174.0, 0.0, 0.0}, + {-1, 1, 0, 0, 1, -301.0, 0.0, -1.0, 162.0, 0.0, 0.0}, + { 1, 0, 2,-1, 2, -334.0, 0.0, 0.0, 144.0, 0.0, 0.0}, + { 1,-1, 0, 2, 0, 493.0, 0.0, -2.0, -15.0, 0.0, 0.0}, + { 0, 0, 0, 4, 0, 494.0, 0.0, -2.0, -19.0, 0.0, 0.0}, + { 1, 0, 2, 1, 2, 337.0, 0.0, -1.0, -143.0, 0.0, -1.0}, + { 0, 0, 2, 1, 1, 280.0, 0.0, -1.0, -144.0, 0.0, 0.0}, + { 1, 0, 0,-2, 2, 309.0, 0.0, 1.0, -134.0, 0.0, 0.0}, + + /* 141-150 */ + {-1, 0, 2, 4, 1, -263.0, 0.0, 2.0, 131.0, 0.0, 1.0}, + { 1, 0,-2, 0, 1, 253.0, 0.0, 1.0, -138.0, 0.0, 0.0}, + { 1, 1, 2,-2, 1, 245.0, 0.0, 0.0, -128.0, 0.0, 0.0}, + { 0, 0, 2, 2, 0, 416.0, 0.0, -2.0, -17.0, 0.0, 0.0}, + {-1, 0, 2,-1, 1, -229.0, 0.0, 0.0, 128.0, 0.0, 0.0}, + {-2, 0, 2, 2, 1, 231.0, 0.0, 0.0, -120.0, 0.0, 0.0}, + { 4, 0, 2, 0, 2, -259.0, 0.0, 2.0, 109.0, 0.0, 1.0}, + { 2,-1, 0, 0, 0, 375.0, 0.0, -1.0, -8.0, 0.0, 0.0}, + { 2, 1, 2,-2, 2, 252.0, 0.0, 0.0, -108.0, 0.0, 0.0}, + { 0, 1, 2, 1, 2, -245.0, 0.0, 1.0, 104.0, 0.0, 0.0}, + + /* 151-160 */ + { 1, 0, 4,-2, 2, 243.0, 0.0, -1.0, -104.0, 0.0, 0.0}, + {-1,-1, 0, 0, 1, 208.0, 0.0, 1.0, -112.0, 0.0, 0.0}, + { 0, 1, 0, 2, 1, 199.0, 0.0, 0.0, -102.0, 0.0, 0.0}, + {-2, 0, 2, 4, 1, -208.0, 0.0, 1.0, 105.0, 0.0, 0.0}, + { 2, 0, 2, 0, 0, 335.0, 0.0, -2.0, -14.0, 0.0, 0.0}, + { 1, 0, 0, 1, 0, -325.0, 0.0, 1.0, 7.0, 0.0, 0.0}, + {-1, 0, 0, 4, 1, -187.0, 0.0, 0.0, 96.0, 0.0, 0.0}, + {-1, 0, 4, 0, 1, 197.0, 0.0, -1.0, -100.0, 0.0, 0.0}, + { 2, 0, 2, 2, 1, -192.0, 0.0, 2.0, 94.0, 0.0, 1.0}, + { 0, 0, 2,-3, 2, -188.0, 0.0, 0.0, 83.0, 0.0, 0.0}, + + /* 161-170 */ + {-1,-2, 0, 2, 0, 276.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 2, 1, 0, 0, 0, -286.0, 0.0, 1.0, 6.0, 0.0, 0.0}, + { 0, 0, 4, 0, 2, 186.0, 0.0, -1.0, -79.0, 0.0, 0.0}, + { 0, 0, 0, 0, 3, -219.0, 0.0, 0.0, 43.0, 0.0, 0.0}, + { 0, 3, 0, 0, 0, 276.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0, 0, 2,-4, 1, -153.0, 0.0, -1.0, 84.0, 0.0, 0.0}, + { 0,-1, 0, 2, 1, -156.0, 0.0, 0.0, 81.0, 0.0, 0.0}, + { 0, 0, 0, 4, 1, -154.0, 0.0, 1.0, 78.0, 0.0, 0.0}, + {-1,-1, 2, 4, 2, -174.0, 0.0, 1.0, 75.0, 0.0, 0.0}, + { 1, 0, 2, 4, 2, -163.0, 0.0, 2.0, 69.0, 0.0, 1.0}, + + /* 171-180 */ + {-2, 2, 0, 2, 0, -228.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {-2,-1, 2, 0, 1, 91.0, 0.0, -4.0, -54.0, 0.0, -2.0}, + {-2, 0, 0, 2, 2, 175.0, 0.0, 0.0, -75.0, 0.0, 0.0}, + {-1,-1, 2, 0, 2, -159.0, 0.0, 0.0, 69.0, 0.0, 0.0}, + { 0, 0, 4,-2, 1, 141.0, 0.0, 0.0, -72.0, 0.0, 0.0}, + { 3, 0, 2,-2, 1, 147.0, 0.0, 0.0, -75.0, 0.0, 0.0}, + {-2,-1, 0, 2, 1, -132.0, 0.0, 0.0, 69.0, 0.0, 0.0}, + { 1, 0, 0,-1, 1, 159.0, 0.0, -28.0, -54.0, 0.0, 11.0}, + { 0,-2, 0, 2, 0, 213.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + {-2, 0, 0, 4, 1, 123.0, 0.0, 0.0, -64.0, 0.0, 0.0}, + + /* 181-190 */ + {-3, 0, 0, 0, 1, -118.0, 0.0, -1.0, 66.0, 0.0, 0.0}, + { 1, 1, 2, 2, 2, 144.0, 0.0, -1.0, -61.0, 0.0, 0.0}, + { 0, 0, 2, 4, 1, -121.0, 0.0, 1.0, 60.0, 0.0, 0.0}, + { 3, 0, 2, 2, 2, -134.0, 0.0, 1.0, 56.0, 0.0, 1.0}, + {-1, 1, 2,-2, 1, -105.0, 0.0, 0.0, 57.0, 0.0, 0.0}, + { 2, 0, 0,-4, 1, -102.0, 0.0, 0.0, 56.0, 0.0, 0.0}, + { 0, 0, 0,-2, 2, 120.0, 0.0, 0.0, -52.0, 0.0, 0.0}, + { 2, 0, 2,-4, 1, 101.0, 0.0, 0.0, -54.0, 0.0, 0.0}, + {-1, 1, 0, 2, 1, -113.0, 0.0, 0.0, 59.0, 0.0, 0.0}, + { 0, 0, 2,-1, 1, -106.0, 0.0, 0.0, 61.0, 0.0, 0.0}, + + /* 191-200 */ + { 0,-2, 2, 2, 2, -129.0, 0.0, 1.0, 55.0, 0.0, 0.0}, + { 2, 0, 0, 2, 1, -114.0, 0.0, 0.0, 57.0, 0.0, 0.0}, + { 4, 0, 2,-2, 2, 113.0, 0.0, -1.0, -49.0, 0.0, 0.0}, + { 2, 0, 0,-2, 2, -102.0, 0.0, 0.0, 44.0, 0.0, 0.0}, + { 0, 2, 0, 0, 1, -94.0, 0.0, 0.0, 51.0, 0.0, 0.0}, + { 1, 0, 0,-4, 1, -100.0, 0.0, -1.0, 56.0, 0.0, 0.0}, + { 0, 2, 2,-2, 1, 87.0, 0.0, 0.0, -47.0, 0.0, 0.0}, + {-3, 0, 0, 4, 0, 161.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-1, 1, 2, 0, 1, 96.0, 0.0, 0.0, -50.0, 0.0, 0.0}, + {-1,-1, 0, 4, 0, 151.0, 0.0, -1.0, -5.0, 0.0, 0.0}, + + /* 201-210 */ + {-1,-2, 2, 2, 2, -104.0, 0.0, 0.0, 44.0, 0.0, 0.0}, + {-2,-1, 2, 4, 2, -110.0, 0.0, 0.0, 48.0, 0.0, 0.0}, + { 1,-1, 2, 2, 1, -100.0, 0.0, 1.0, 50.0, 0.0, 0.0}, + {-2, 1, 0, 2, 0, 92.0, 0.0, -5.0, 12.0, 0.0, -2.0}, + {-2, 1, 2, 0, 1, 82.0, 0.0, 0.0, -45.0, 0.0, 0.0}, + { 2, 1, 0,-2, 1, 82.0, 0.0, 0.0, -45.0, 0.0, 0.0}, + {-3, 0, 2, 0, 1, -78.0, 0.0, 0.0, 41.0, 0.0, 0.0}, + {-2, 0, 2,-2, 1, -77.0, 0.0, 0.0, 43.0, 0.0, 0.0}, + {-1, 1, 0, 2, 2, 2.0, 0.0, 0.0, 54.0, 0.0, 0.0}, + { 0,-1, 2,-1, 2, 94.0, 0.0, 0.0, -40.0, 0.0, 0.0}, + + /* 211-220 */ + {-1, 0, 4,-2, 2, -93.0, 0.0, 0.0, 40.0, 0.0, 0.0}, + { 0,-2, 2, 0, 2, -83.0, 0.0, 10.0, 40.0, 0.0, -2.0}, + {-1, 0, 2, 1, 2, 83.0, 0.0, 0.0, -36.0, 0.0, 0.0}, + { 2, 0, 0, 0, 2, -91.0, 0.0, 0.0, 39.0, 0.0, 0.0}, + { 0, 0, 2, 0, 3, 128.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-2, 0, 4, 0, 2, -79.0, 0.0, 0.0, 34.0, 0.0, 0.0}, + {-1, 0,-2, 0, 1, -83.0, 0.0, 0.0, 47.0, 0.0, 0.0}, + {-1, 1, 2, 2, 1, 84.0, 0.0, 0.0, -44.0, 0.0, 0.0}, + { 3, 0, 0, 0, 1, 83.0, 0.0, 0.0, -43.0, 0.0, 0.0}, + {-1, 0, 2, 3, 2, 91.0, 0.0, 0.0, -39.0, 0.0, 0.0}, + + /* 221-230 */ + { 2,-1, 2, 0, 1, -77.0, 0.0, 0.0, 39.0, 0.0, 0.0}, + { 0, 1, 2, 2, 1, 84.0, 0.0, 0.0, -43.0, 0.0, 0.0}, + { 0,-1, 2, 4, 2, -92.0, 0.0, 1.0, 39.0, 0.0, 0.0}, + { 2,-1, 2, 2, 2, -92.0, 0.0, 1.0, 39.0, 0.0, 0.0}, + { 0, 2,-2, 2, 0, -94.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 2,-1, 1, 68.0, 0.0, 0.0, -36.0, 0.0, 0.0}, + { 0,-2, 0, 0, 1, -61.0, 0.0, 0.0, 32.0, 0.0, 0.0}, + { 1, 0, 2,-4, 2, 71.0, 0.0, 0.0, -31.0, 0.0, 0.0}, + { 1,-1, 0,-2, 1, 62.0, 0.0, 0.0, -34.0, 0.0, 0.0}, + {-1,-1, 2, 0, 1, -63.0, 0.0, 0.0, 33.0, 0.0, 0.0}, + + /* 231-240 */ + { 1,-1, 2,-2, 2, -73.0, 0.0, 0.0, 32.0, 0.0, 0.0}, + {-2,-1, 0, 4, 0, 115.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-1, 0, 0, 3, 0, -103.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-2,-1, 2, 2, 2, 63.0, 0.0, 0.0, -28.0, 0.0, 0.0}, + { 0, 2, 2, 0, 2, 74.0, 0.0, 0.0, -32.0, 0.0, 0.0}, + { 1, 1, 0, 2, 0, -103.0, 0.0, -3.0, 3.0, 0.0, -1.0}, + { 2, 0, 2,-1, 2, -69.0, 0.0, 0.0, 30.0, 0.0, 0.0}, + { 1, 0, 2, 1, 1, 57.0, 0.0, 0.0, -29.0, 0.0, 0.0}, + { 4, 0, 0, 0, 0, 94.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + { 2, 1, 2, 0, 1, 64.0, 0.0, 0.0, -33.0, 0.0, 0.0}, + + /* 241-250 */ + { 3,-1, 2, 0, 2, -63.0, 0.0, 0.0, 26.0, 0.0, 0.0}, + {-2, 2, 0, 2, 1, -38.0, 0.0, 0.0, 20.0, 0.0, 0.0}, + { 1, 0, 2,-3, 1, -43.0, 0.0, 0.0, 24.0, 0.0, 0.0}, + { 1, 1, 2,-4, 1, -45.0, 0.0, 0.0, 23.0, 0.0, 0.0}, + {-1,-1, 2,-2, 1, 47.0, 0.0, 0.0, -24.0, 0.0, 0.0}, + { 0,-1, 0,-1, 1, -48.0, 0.0, 0.0, 25.0, 0.0, 0.0}, + { 0,-1, 0,-2, 1, 45.0, 0.0, 0.0, -26.0, 0.0, 0.0}, + {-2, 0, 0, 0, 2, 56.0, 0.0, 0.0, -25.0, 0.0, 0.0}, + {-2, 0,-2, 2, 0, 88.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1, 0,-2, 4, 0, -75.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 251-260 */ + { 1,-2, 0, 0, 0, 85.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 0, 1, 1, 49.0, 0.0, 0.0, -26.0, 0.0, 0.0}, + {-1, 2, 0, 2, 0, -74.0, 0.0, -3.0, -1.0, 0.0, -1.0}, + { 1,-1, 2,-2, 1, -39.0, 0.0, 0.0, 21.0, 0.0, 0.0}, + { 1, 2, 2,-2, 2, 45.0, 0.0, 0.0, -20.0, 0.0, 0.0}, + { 2,-1, 2,-2, 2, 51.0, 0.0, 0.0, -22.0, 0.0, 0.0}, + { 1, 0, 2,-1, 1, -40.0, 0.0, 0.0, 21.0, 0.0, 0.0}, + { 2, 1, 2,-2, 1, 41.0, 0.0, 0.0, -21.0, 0.0, 0.0}, + {-2, 0, 0,-2, 1, -42.0, 0.0, 0.0, 24.0, 0.0, 0.0}, + { 1,-2, 2, 0, 2, -51.0, 0.0, 0.0, 22.0, 0.0, 0.0}, + + /* 261-270 */ + { 0, 1, 2, 1, 1, -42.0, 0.0, 0.0, 22.0, 0.0, 0.0}, + { 1, 0, 4,-2, 1, 39.0, 0.0, 0.0, -21.0, 0.0, 0.0}, + {-2, 0, 4, 2, 2, 46.0, 0.0, 0.0, -18.0, 0.0, 0.0}, + { 1, 1, 2, 1, 2, -53.0, 0.0, 0.0, 22.0, 0.0, 0.0}, + { 1, 0, 0, 4, 0, 82.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + { 1, 0, 2, 2, 0, 81.0, 0.0, -1.0, -4.0, 0.0, 0.0}, + { 2, 0, 2, 1, 2, 47.0, 0.0, 0.0, -19.0, 0.0, 0.0}, + { 3, 1, 2, 0, 2, 53.0, 0.0, 0.0, -23.0, 0.0, 0.0}, + { 4, 0, 2, 0, 1, -45.0, 0.0, 0.0, 22.0, 0.0, 0.0}, + {-2,-1, 2, 0, 0, -44.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + + /* 271-280 */ + { 0, 1,-2, 2, 1, -33.0, 0.0, 0.0, 16.0, 0.0, 0.0}, + { 1, 0,-2, 1, 0, -61.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 0,-1,-2, 2, 1, 28.0, 0.0, 0.0, -15.0, 0.0, 0.0}, + { 2,-1, 0,-2, 1, -38.0, 0.0, 0.0, 19.0, 0.0, 0.0}, + {-1, 0, 2,-1, 2, -33.0, 0.0, 0.0, 21.0, 0.0, 0.0}, + { 1, 0, 2,-3, 2, -60.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 2,-2, 3, 48.0, 0.0, 0.0, -10.0, 0.0, 0.0}, + { 0, 0, 2,-3, 1, 27.0, 0.0, 0.0, -14.0, 0.0, 0.0}, + {-1, 0,-2, 2, 1, 38.0, 0.0, 0.0, -20.0, 0.0, 0.0}, + { 0, 0, 2,-4, 2, 31.0, 0.0, 0.0, -13.0, 0.0, 0.0}, + + /* 281-290 */ + {-2, 1, 0, 0, 1, -29.0, 0.0, 0.0, 15.0, 0.0, 0.0}, + {-1, 0, 0,-1, 1, 28.0, 0.0, 0.0, -15.0, 0.0, 0.0}, + { 2, 0, 2,-4, 2, -32.0, 0.0, 0.0, 15.0, 0.0, 0.0}, + { 0, 0, 4,-4, 4, 45.0, 0.0, 0.0, -8.0, 0.0, 0.0}, + { 0, 0, 4,-4, 2, -44.0, 0.0, 0.0, 19.0, 0.0, 0.0}, + {-1,-2, 0, 2, 1, 28.0, 0.0, 0.0, -15.0, 0.0, 0.0}, + {-2, 0, 0, 3, 0, -51.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0,-2, 2, 1, -36.0, 0.0, 0.0, 20.0, 0.0, 0.0}, + {-3, 0, 2, 2, 2, 44.0, 0.0, 0.0, -19.0, 0.0, 0.0}, + {-3, 0, 2, 2, 1, 26.0, 0.0, 0.0, -14.0, 0.0, 0.0}, + + /* 291-300 */ + {-2, 0, 2, 2, 0, -60.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 2,-1, 0, 0, 1, 35.0, 0.0, 0.0, -18.0, 0.0, 0.0}, + {-2, 1, 2, 2, 2, -27.0, 0.0, 0.0, 11.0, 0.0, 0.0}, + { 1, 1, 0, 1, 0, 47.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 0, 1, 4,-2, 2, 36.0, 0.0, 0.0, -15.0, 0.0, 0.0}, + {-1, 1, 0,-2, 1, -36.0, 0.0, 0.0, 20.0, 0.0, 0.0}, + { 0, 0, 0,-4, 1, -35.0, 0.0, 0.0, 19.0, 0.0, 0.0}, + { 1,-1, 0, 2, 1, -37.0, 0.0, 0.0, 19.0, 0.0, 0.0}, + { 1, 1, 0, 2, 1, 32.0, 0.0, 0.0, -16.0, 0.0, 0.0}, + {-1, 2, 2, 2, 2, 35.0, 0.0, 0.0, -14.0, 0.0, 0.0}, + + /* 301-310 */ + { 3, 1, 2,-2, 2, 32.0, 0.0, 0.0, -13.0, 0.0, 0.0}, + { 0,-1, 0, 4, 0, 65.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 2,-1, 0, 2, 0, 47.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 0, 0, 4, 0, 1, 32.0, 0.0, 0.0, -16.0, 0.0, 0.0}, + { 2, 0, 4,-2, 2, 37.0, 0.0, 0.0, -16.0, 0.0, 0.0}, + {-1,-1, 2, 4, 1, -30.0, 0.0, 0.0, 15.0, 0.0, 0.0}, + { 1, 0, 0, 4, 1, -32.0, 0.0, 0.0, 16.0, 0.0, 0.0}, + { 1,-2, 2, 2, 2, -31.0, 0.0, 0.0, 13.0, 0.0, 0.0}, + { 0, 0, 2, 3, 2, 37.0, 0.0, 0.0, -16.0, 0.0, 0.0}, + {-1, 1, 2, 4, 2, 31.0, 0.0, 0.0, -13.0, 0.0, 0.0}, + + /* 311-320 */ + { 3, 0, 0, 2, 0, 49.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-1, 0, 4, 2, 2, 32.0, 0.0, 0.0, -13.0, 0.0, 0.0}, + { 1, 1, 2, 2, 1, 23.0, 0.0, 0.0, -12.0, 0.0, 0.0}, + {-2, 0, 2, 6, 2, -43.0, 0.0, 0.0, 18.0, 0.0, 0.0}, + { 2, 1, 2, 2, 2, 26.0, 0.0, 0.0, -11.0, 0.0, 0.0}, + {-1, 0, 2, 6, 2, -32.0, 0.0, 0.0, 14.0, 0.0, 0.0}, + { 1, 0, 2, 4, 1, -29.0, 0.0, 0.0, 14.0, 0.0, 0.0}, + { 2, 0, 2, 4, 2, -27.0, 0.0, 0.0, 12.0, 0.0, 0.0}, + { 1, 1,-2, 1, 0, 30.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-3, 1, 2, 1, 2, -11.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + + /* 321-330 */ + { 2, 0,-2, 0, 2, -21.0, 0.0, 0.0, 10.0, 0.0, 0.0}, + {-1, 0, 0, 1, 2, -34.0, 0.0, 0.0, 15.0, 0.0, 0.0}, + {-4, 0, 2, 2, 1, -10.0, 0.0, 0.0, 6.0, 0.0, 0.0}, + {-1,-1, 0, 1, 0, -36.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 0,-2, 2, 2, -9.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + { 1, 0, 0,-1, 2, -12.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + { 0,-1, 2,-2, 3, -21.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + {-2, 1, 2, 0, 0, -29.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 0, 0, 2,-2, 4, -15.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-2,-2, 0, 2, 0, -20.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 331-340 */ + {-2, 0,-2, 4, 0, 28.0, 0.0, 0.0, 0.0, 0.0, -2.0}, + { 0,-2,-2, 2, 0, 17.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 2, 0,-2, 1, -22.0, 0.0, 0.0, 12.0, 0.0, 0.0}, + { 3, 0, 0,-4, 1, -14.0, 0.0, 0.0, 7.0, 0.0, 0.0}, + {-1, 1, 2,-2, 2, 24.0, 0.0, 0.0, -11.0, 0.0, 0.0}, + { 1,-1, 2,-4, 1, 11.0, 0.0, 0.0, -6.0, 0.0, 0.0}, + { 1, 1, 0,-2, 2, 14.0, 0.0, 0.0, -6.0, 0.0, 0.0}, + {-3, 0, 2, 0, 0, 24.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-3, 0, 2, 0, 2, 18.0, 0.0, 0.0, -8.0, 0.0, 0.0}, + {-2, 0, 0, 1, 0, -38.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 341-350 */ + { 0, 0,-2, 1, 0, -31.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-3, 0, 0, 2, 1, -16.0, 0.0, 0.0, 8.0, 0.0, 0.0}, + {-1,-1,-2, 2, 0, 29.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 2,-4, 1, -18.0, 0.0, 0.0, 10.0, 0.0, 0.0}, + { 2, 1, 0,-4, 1, -10.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + { 0, 2, 0,-2, 1, -17.0, 0.0, 0.0, 10.0, 0.0, 0.0}, + { 1, 0, 0,-3, 1, 9.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + {-2, 0, 2,-2, 2, 16.0, 0.0, 0.0, -6.0, 0.0, 0.0}, + {-2,-1, 0, 0, 1, 22.0, 0.0, 0.0, -12.0, 0.0, 0.0}, + {-4, 0, 0, 2, 0, 20.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 351-360 */ + { 1, 1, 0,-4, 1, -13.0, 0.0, 0.0, 6.0, 0.0, 0.0}, + {-1, 0, 2,-4, 1, -17.0, 0.0, 0.0, 9.0, 0.0, 0.0}, + { 0, 0, 4,-4, 1, -14.0, 0.0, 0.0, 8.0, 0.0, 0.0}, + { 0, 3, 2,-2, 2, 0.0, 0.0, 0.0, -7.0, 0.0, 0.0}, + {-3,-1, 0, 4, 0, 14.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-3, 0, 0, 4, 1, 19.0, 0.0, 0.0, -10.0, 0.0, 0.0}, + { 1,-1,-2, 2, 0, -34.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 0, 2, 2, -20.0, 0.0, 0.0, 8.0, 0.0, 0.0}, + { 1,-2, 0, 0, 1, 9.0, 0.0, 0.0, -5.0, 0.0, 0.0}, + { 1,-1, 0, 0, 2, -18.0, 0.0, 0.0, 7.0, 0.0, 0.0}, + + /* 361-370 */ + { 0, 0, 0, 1, 2, 13.0, 0.0, 0.0, -6.0, 0.0, 0.0}, + {-1,-1, 2, 0, 0, 17.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1,-2, 2,-2, 2, -12.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + { 0,-1, 2,-1, 1, 15.0, 0.0, 0.0, -8.0, 0.0, 0.0}, + {-1, 0, 2, 0, 3, -11.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 1, 1, 0, 0, 2, 13.0, 0.0, 0.0, -5.0, 0.0, 0.0}, + {-1, 1, 2, 0, 0, -18.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 2, 0, 0, 0, -35.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 2, 2, 0, 2, 9.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + {-1, 0, 4,-2, 1, -19.0, 0.0, 0.0, 10.0, 0.0, 0.0}, + + /* 371-380 */ + { 3, 0, 2,-4, 2, -26.0, 0.0, 0.0, 11.0, 0.0, 0.0}, + { 1, 2, 2,-2, 1, 8.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + { 1, 0, 4,-4, 2, -10.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + {-2,-1, 0, 4, 1, 10.0, 0.0, 0.0, -6.0, 0.0, 0.0}, + { 0,-1, 0, 2, 2, -21.0, 0.0, 0.0, 9.0, 0.0, 0.0}, + {-2, 1, 0, 4, 0, -15.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2,-1, 2, 2, 1, 9.0, 0.0, 0.0, -5.0, 0.0, 0.0}, + { 2, 0,-2, 2, 0, -29.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0, 0, 1, 1, -19.0, 0.0, 0.0, 10.0, 0.0, 0.0}, + { 0, 1, 0, 2, 2, 12.0, 0.0, 0.0, -5.0, 0.0, 0.0}, + + /* 381-390 */ + { 1,-1, 2,-1, 2, 22.0, 0.0, 0.0, -9.0, 0.0, 0.0}, + {-2, 0, 4, 0, 1, -10.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + { 2, 1, 0, 0, 1, -20.0, 0.0, 0.0, 11.0, 0.0, 0.0}, + { 0, 1, 2, 0, 0, -20.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0,-1, 4,-2, 2, -17.0, 0.0, 0.0, 7.0, 0.0, 0.0}, + { 0, 0, 4,-2, 4, 15.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 0, 2, 2, 0, 1, 8.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + {-3, 0, 0, 6, 0, 14.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 0, 4, 1, -12.0, 0.0, 0.0, 6.0, 0.0, 0.0}, + { 1,-2, 0, 2, 0, 25.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 391-400 */ + {-1, 0, 0, 4, 2, -13.0, 0.0, 0.0, 6.0, 0.0, 0.0}, + {-1,-2, 2, 2, 1, -14.0, 0.0, 0.0, 8.0, 0.0, 0.0}, + {-1, 0, 0,-2, 2, 13.0, 0.0, 0.0, -5.0, 0.0, 0.0}, + { 1, 0,-2,-2, 1, -17.0, 0.0, 0.0, 9.0, 0.0, 0.0}, + { 0, 0,-2,-2, 1, -12.0, 0.0, 0.0, 6.0, 0.0, 0.0}, + {-2, 0,-2, 0, 1, -10.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + { 0, 0, 0, 3, 1, 10.0, 0.0, 0.0, -6.0, 0.0, 0.0}, + { 0, 0, 0, 3, 0, -15.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 1, 0, 4, 0, -22.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 2, 2, 0, 28.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + + /* 401-410 */ + {-2, 0, 2, 3, 2, 15.0, 0.0, 0.0, -7.0, 0.0, 0.0}, + { 1, 0, 0, 2, 2, 23.0, 0.0, 0.0, -10.0, 0.0, 0.0}, + { 0,-1, 2, 1, 2, 12.0, 0.0, 0.0, -5.0, 0.0, 0.0}, + { 3,-1, 0, 0, 0, 29.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 2, 0, 0, 1, 0, -25.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 1,-1, 2, 0, 0, 22.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 0, 2, 1, 0, -18.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0, 2, 0, 3, 15.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 3, 1, 0, 0, 0, -23.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 3,-1, 2,-2, 2, 12.0, 0.0, 0.0, -5.0, 0.0, 0.0}, + + /* 411-420 */ + { 2, 0, 2,-1, 1, -8.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + { 1, 1, 2, 0, 0, -19.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 0, 4,-1, 2, -10.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + { 1, 2, 2, 0, 2, 21.0, 0.0, 0.0, -9.0, 0.0, 0.0}, + {-2, 0, 0, 6, 0, 23.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 0,-1, 0, 4, 1, -16.0, 0.0, 0.0, 8.0, 0.0, 0.0}, + {-2,-1, 2, 4, 1, -19.0, 0.0, 0.0, 9.0, 0.0, 0.0}, + { 0,-2, 2, 2, 1, -22.0, 0.0, 0.0, 10.0, 0.0, 0.0}, + { 0,-1, 2, 2, 0, 27.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-1, 0, 2, 3, 1, 16.0, 0.0, 0.0, -8.0, 0.0, 0.0}, + + /* 421-430 */ + {-2, 1, 2, 4, 2, 19.0, 0.0, 0.0, -8.0, 0.0, 0.0}, + { 2, 0, 0, 2, 2, 9.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + { 2,-2, 2, 0, 2, -9.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + {-1, 1, 2, 3, 2, -9.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + { 3, 0, 2,-1, 2, -8.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + { 4, 0, 2,-2, 1, 18.0, 0.0, 0.0, -9.0, 0.0, 0.0}, + {-1, 0, 0, 6, 0, 16.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-1,-2, 2, 4, 2, -10.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + {-3, 0, 2, 6, 2, -23.0, 0.0, 0.0, 9.0, 0.0, 0.0}, + {-1, 0, 2, 4, 0, 16.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + + /* 431-440 */ + { 3, 0, 0, 2, 1, -12.0, 0.0, 0.0, 6.0, 0.0, 0.0}, + { 3,-1, 2, 0, 1, -8.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + { 3, 0, 2, 0, 0, 30.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 1, 0, 4, 0, 2, 24.0, 0.0, 0.0, -10.0, 0.0, 0.0}, + { 5, 0, 2,-2, 2, 10.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + { 0,-1, 2, 4, 1, -16.0, 0.0, 0.0, 7.0, 0.0, 0.0}, + { 2,-1, 2, 2, 1, -16.0, 0.0, 0.0, 7.0, 0.0, 0.0}, + { 0, 1, 2, 4, 2, 17.0, 0.0, 0.0, -7.0, 0.0, 0.0}, + { 1,-1, 2, 4, 2, -24.0, 0.0, 0.0, 10.0, 0.0, 0.0}, + { 3,-1, 2, 2, 2, -12.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + + /* 441-450 */ + { 3, 0, 2, 2, 1, -24.0, 0.0, 0.0, 11.0, 0.0, 0.0}, + { 5, 0, 2, 0, 2, -23.0, 0.0, 0.0, 9.0, 0.0, 0.0}, + { 0, 0, 2, 6, 2, -13.0, 0.0, 0.0, 5.0, 0.0, 0.0}, + { 4, 0, 2, 2, 2, -15.0, 0.0, 0.0, 7.0, 0.0, 0.0}, + { 0,-1, 1,-1, 1, 0.0, 0.0,-1988.0, 0.0, 0.0,-1679.0}, + {-1, 0, 1, 0, 3, 0.0, 0.0, -63.0, 0.0, 0.0, -27.0}, + { 0,-2, 2,-2, 3, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0,-1, 0, 1, 0.0, 0.0, 5.0, 0.0, 0.0, 4.0}, + { 2,-2, 0,-2, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + {-1, 0, 1, 0, 2, 0.0, 0.0, 364.0, 0.0, 0.0, 176.0}, + + /* 451-460 */ + {-1, 0, 1, 0, 1, 0.0, 0.0,-1044.0, 0.0, 0.0, -891.0}, + {-1,-1, 2,-1, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {-2, 2, 0, 2, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-1, 0, 1, 0, 0, 0.0, 0.0, 330.0, 0.0, 0.0, 0.0}, + {-4, 1, 2, 2, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-3, 0, 2, 1, 1, 3.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-2,-1, 2, 0, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 1, 0,-2, 1, 1, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 2,-1,-2, 0, 1, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-4, 0, 2, 2, 0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 461-470 */ + {-3, 1, 0, 3, 0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 0,-1, 2, 0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0}, + { 0,-2, 0, 0, 2, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 0,-2, 0, 0, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-3, 0, 0, 3, 0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2,-1, 0, 2, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-1, 0,-2, 3, 0, -7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-4, 0, 0, 4, 0, -12.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2, 1,-2, 0, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 2,-1, 0,-2, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + + /* 471-480 */ + { 0, 0, 1,-1, 0, -5.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 2, 0, 1, 0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2, 1, 2, 0, 2, -7.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 1, 1, 0,-1, 1, 7.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + { 1, 0, 1,-2, 1, 0.0, 0.0, -12.0, 0.0, 0.0, -10.0}, + { 0, 2, 0, 0, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 1,-1, 2,-3, 1, 3.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-1, 1, 2,-1, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-2, 0, 4,-2, 2, -7.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-2, 0, 4,-2, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + + /* 481-490 */ + {-2,-2, 0, 2, 1, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {-2, 0,-2, 4, 0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 2, 2,-4, 1, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 1, 1, 2,-4, 2, 7.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + {-1, 2, 2,-2, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 2, 0, 0,-3, 1, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-1, 2, 0, 0, 1, -5.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 0, 0, 0,-2, 0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 2,-2, 2, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1, 1, 0, 0, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + + /* 491-500 */ + { 0, 0, 0,-1, 2, -8.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-2, 1, 0, 1, 0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1,-2, 0,-2, 1, 6.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 1, 0,-2, 0, 2, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-3, 1, 0, 2, 0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 1,-2, 2, 0, -7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 0, 0, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {-3, 0, 0, 2, 0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-3,-1, 0, 2, 0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2, 0, 2,-6, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + + /* 501-510 */ + { 0, 1, 2,-4, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 2, 0, 0,-4, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-2, 1, 2,-2, 1, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0,-1, 2,-4, 1, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 0, 1, 0,-2, 2, 9.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + {-1, 0, 0,-2, 0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2, 0,-2,-2, 1, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-4, 0, 2, 0, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1,-1, 0,-1, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0, 0,-2, 0, 2, 9.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + + /* 511-520 */ + {-3, 0, 0, 1, 0, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 0,-2, 1, 0, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2, 0,-2, 2, 1, 3.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 0, 0,-4, 2, 0, 8.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2,-1,-2, 2, 0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0, 2,-6, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1, 0, 2,-4, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 1, 0, 0,-4, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 2, 1, 2,-4, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 2, 1, 2,-4, 1, 6.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + + /* 521-530 */ + { 0, 1, 4,-4, 4, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 4,-4, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {-1,-1,-2, 4, 0, -7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-3, 0, 2, 0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 0,-2, 4, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-2,-1, 0, 3, 0, -3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 0,-2, 3, 0, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2, 0, 0, 3, 1, -5.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 0,-1, 0, 1, 0, -13.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-3, 0, 2, 2, 0, -7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 531-540 */ + { 1, 1,-2, 2, 0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 1, 0, 2, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 1,-2, 2,-2, 1, 10.0, 0.0, 13.0, 6.0, 0.0, -5.0}, + { 0, 0, 1, 0, 2, 0.0, 0.0, 30.0, 0.0, 0.0, 14.0}, + { 0, 0, 1, 0, 1, 0.0, 0.0, -162.0, 0.0, 0.0, -138.0}, + { 0, 0, 1, 0, 0, 0.0, 0.0, 75.0, 0.0, 0.0, 0.0}, + {-1, 2, 0, 2, 1, -7.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + { 0, 0, 2, 0, 2, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-2, 0, 2, 0, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 2, 0, 0,-1, 1, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + + /* 541-550 */ + { 3, 0, 0,-2, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 1, 0, 2,-2, 3, -3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 2, 0, 0, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 2, 0, 2,-3, 2, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1, 1, 4,-2, 2, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-2,-2, 0, 4, 0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0,-3, 0, 2, 0, 9.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 0,-2, 4, 0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 0, 3, 0, -7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2, 0, 0, 4, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + + /* 551-560 */ + {-1, 0, 0, 3, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 2,-2, 0, 0, 0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1,-1, 0, 1, 0, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 0, 0, 2, 0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0,-2, 2, 0, 1, -6.0, 0.0, -3.0, 3.0, 0.0, 1.0}, + {-1, 0, 1, 2, 1, 0.0, 0.0, -3.0, 0.0, 0.0, -2.0}, + {-1, 1, 0, 3, 0, 11.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-1, 2, 1, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 0,-1, 2, 0, 0, 11.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2, 1, 2, 2, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + + /* 561-570 */ + { 2,-2, 2,-2, 2, -1.0, 0.0, 3.0, 3.0, 0.0, -1.0}, + { 1, 1, 0, 1, 1, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 1, 0, 1, 0, 1, 0.0, 0.0, -13.0, 0.0, 0.0, -11.0}, + { 1, 0, 1, 0, 0, 3.0, 0.0, 6.0, 0.0, 0.0, 0.0}, + { 0, 2, 0, 2, 0, -7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2,-1, 2,-2, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 0,-1, 4,-2, 1, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 0, 0, 4,-2, 3, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 4,-2, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 4, 0, 2,-4, 2, -7.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + + /* 571-580 */ + { 2, 2, 2,-2, 2, 8.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 2, 0, 4,-4, 2, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1,-2, 0, 4, 0, 11.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1,-3, 2, 2, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {-3, 0, 2, 4, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-3, 0, 2,-2, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1,-1, 0,-2, 1, 8.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + {-3, 0, 0, 0, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-3, 0,-2, 2, 0, 11.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 0,-4, 1, -6.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + + /* 581-590 */ + {-2, 1, 0,-2, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-4, 0, 0, 0, 1, -8.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + {-1, 0, 0,-4, 1, -7.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-3, 0, 0,-2, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0, 0, 0, 3, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-1, 1, 0, 4, 1, 6.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 1,-2, 2, 0, 1, -6.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 0, 1, 0, 3, 0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-1, 0, 2, 2, 3, 6.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 0, 0, 2, 2, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + + /* 591-600 */ + {-2, 0, 2, 2, 2, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1, 1, 2, 2, 0, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 3, 0, 0, 0, 2, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 2, 1, 0, 1, 0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2,-1, 2,-1, 2, 6.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 0, 0, 2, 0, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0, 0, 3, 0, 3, 0.0, 0.0, -26.0, 0.0, 0.0, -11.0}, + { 0, 0, 3, 0, 2, 0.0, 0.0, -10.0, 0.0, 0.0, -5.0}, + {-1, 2, 2, 2, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + {-1, 0, 4, 0, 0, -13.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 601-610 */ + { 1, 2, 2, 0, 1, 3.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 3, 1, 2,-2, 1, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 1, 1, 4,-2, 2, 7.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + {-2,-1, 0, 6, 0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0,-2, 0, 4, 0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-2, 0, 0, 6, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-2,-2, 2, 4, 2, -6.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0,-3, 2, 2, 2, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0, 0, 0, 4, 2, -7.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-1,-1, 2, 3, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + + /* 611-620 */ + {-2, 0, 2, 4, 0, 13.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2,-1, 0, 2, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 1, 0, 0, 3, 0, -3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 0, 4, 1, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 0, 1, 0, 4, 0, -11.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1,-1, 2, 1, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 0, 0, 2, 2, 3, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0, 2, 2, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-1, 0, 2, 2, 2, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-2, 0, 4, 2, 1, 6.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + + /* 621-630 */ + { 2, 1, 0, 2, 1, 3.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 2, 1, 0, 2, 0, -12.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2,-1, 2, 0, 0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0, 2, 1, 0, -3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 1, 2, 2, 0, -4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2, 0, 2, 0, 3, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 3, 0, 2, 0, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 1, 0, 2, 0, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 1, 0, 3, 0, 3, 0.0, 0.0, -5.0, 0.0, 0.0, -2.0}, + { 1, 1, 2, 1, 1, -7.0, 0.0, 0.0, 4.0, 0.0, 0.0}, + + /* 631-640 */ + { 0, 2, 2, 2, 2, 6.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 2, 1, 2, 0, 0, -3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2, 0, 4,-2, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 4, 1, 2,-2, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + {-1,-1, 0, 6, 0, 3.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {-3,-1, 2, 6, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + {-1, 0, 0, 6, 1, -5.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-3, 0, 2, 6, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 1,-1, 0, 4, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 1,-1, 0, 4, 0, 12.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 641-650 */ + {-2, 0, 2, 5, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 1,-2, 2, 2, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 3,-1, 0, 2, 0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1,-1, 2, 2, 0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 0, 2, 3, 1, 5.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + {-1, 1, 2, 4, 1, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 0, 1, 2, 3, 2, -6.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-1, 0, 4, 2, 1, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 2, 0, 2, 1, 1, 6.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 5, 0, 0, 0, 0, 6.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 651-660 */ + { 2, 1, 2, 1, 2, -6.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 1, 0, 4, 0, 1, 3.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 3, 1, 2, 0, 1, 7.0, 0.0, 0.0, -4.0, 0.0, 0.0}, + { 3, 0, 4,-2, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + {-2,-1, 2, 6, 2, -5.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0, 0, 0, 6, 0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0,-2, 2, 4, 2, -6.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + {-2, 0, 2, 6, 1, -6.0, 0.0, 0.0, 3.0, 0.0, 0.0}, + { 2, 0, 0, 4, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 2, 0, 0, 4, 0, 10.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + + /* 661-670 */ + { 2,-2, 2, 2, 2, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 0, 0, 2, 4, 0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 1, 0, 2, 3, 2, 7.0, 0.0, 0.0, -3.0, 0.0, 0.0}, + { 4, 0, 0, 2, 0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 2, 0, 2, 2, 0, 11.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + { 0, 0, 4, 2, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 4,-1, 2, 0, 2, -6.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 3, 0, 2, 1, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 2, 1, 2, 2, 1, 3.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 4, 1, 2, 0, 2, 5.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + + /* 671-678 */ + {-1,-1, 2, 6, 2, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + {-1, 0, 2, 6, 1, -4.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 1,-1, 2, 4, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0}, + { 1, 1, 2, 4, 2, 4.0, 0.0, 0.0, -2.0, 0.0, 0.0}, + { 3, 1, 2, 2, 2, 3.0, 0.0, 0.0, -1.0, 0.0, 0.0}, + { 5, 0, 2, 0, 1, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 2,-1, 2, 4, 2, -3.0, 0.0, 0.0, 1.0, 0.0, 0.0}, + { 2, 0, 2, 4, 1, -3.0, 0.0, 0.0, 2.0, 0.0, 0.0} + }; + +/* Number of terms in the luni-solar nutation model */ + const int NLS = (int) (sizeof xls / sizeof xls[0]); + +/* ------------------------ */ +/* Planetary nutation model */ +/* ------------------------ */ + +/* The units for the sine and cosine coefficients are */ +/* 0.1 microarcsecond */ + + static const struct { + int nl, /* coefficients of l, F, D and Omega */ + nf, + nd, + nom, + nme, /* coefficients of planetary longitudes */ + nve, + nea, + nma, + nju, + nsa, + nur, + nne, + npa; /* coefficient of general precession */ + int sp,cp; /* longitude sin, cos coefficients */ + int se,ce; /* obliquity sin, cos coefficients */ + } xpl[] = { + + /* 1-10 */ + { 0, 0, 0, 0, 0, 0, 8,-16, 4, 5, 0, 0, 0, 1440, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, -8, 16,-4,-5, 0, 0, 2, 56,-117, -42, -40}, + { 0, 0, 0, 0, 0, 0, 8,-16, 4, 5, 0, 0, 2, 125, -43, 0, -54}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 2, 2, 0, 5, 0, 0}, + { 0, 0, 0, 0, 0, 0, -4, 8,-1,-5, 0, 0, 2, 3, -7, -3, 0}, + { 0, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, 1, 3, 0, 0, -2}, + { 0, 1,-1, 1, 0, 0, 3, -8, 3, 0, 0, 0, 0, -114, 0, 0, 61}, + {-1, 0, 0, 0, 0, 10, -3, 0, 0, 0, 0, 0, 0, -219, 89, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0,-2, 6,-3, 0, 2, -3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0, -462,1604, 0, 0}, + + /* 11-20 */ + { 0, 1,-1, 1, 0, 0, -5, 8,-3, 0, 0, 0, 0, 99, 0, 0, -53}, + { 0, 0, 0, 0, 0, 0, -4, 8,-3, 0, 0, 0, 1, -3, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 4, -8, 1, 5, 0, 0, 2, 0, 6, 2, 0}, + { 0, 0, 0, 0, 0, -5, 6, 4, 0, 0, 0, 0, 2, 3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2,-5, 0, 0, 2, -12, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2,-5, 0, 0, 1, 14,-218, 117, 8}, + { 0, 1,-1, 1, 0, 0, -1, 0, 2,-5, 0, 0, 0, 31,-481, -257, -17}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2,-5, 0, 0, 0, -491, 128, 0, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0,-2, 5, 0, 0, 0,-3084,5123, 2735,1647}, + { 0, 0, 0, 0, 0, 0, 0, 0,-2, 5, 0, 0, 1,-1444,2409,-1286,-771}, + + /* 21-30 */ + { 0, 0, 0, 0, 0, 0, 0, 0,-2, 5, 0, 0, 2, 11, -24, -11, -9}, + { 2,-1,-1, 0, 0, 0, 3, -7, 0, 0, 0, 0, 0, 26, -9, 0, 0}, + { 1, 0,-2, 0, 0, 19,-21, 3, 0, 0, 0, 0, 0, 103, -60, 0, 0}, + { 0, 1,-1, 1, 0, 2, -4, 0,-3, 0, 0, 0, 0, 0, -13, -7, 0}, + { 1, 0,-1, 1, 0, 0, -1, 0, 2, 0, 0, 0, 0, -26, -29, -16, 14}, + { 0, 1,-1, 1, 0, 0, -1, 0,-4,10, 0, 0, 0, 9, -27, -14, -5}, + {-2, 0, 2, 1, 0, 0, 2, 0, 0,-5, 0, 0, 0, 12, 0, 0, -6}, + { 0, 0, 0, 0, 0, 3, -7, 4, 0, 0, 0, 0, 0, -7, 0, 0, 0}, + { 0,-1, 1, 0, 0, 0, 1, 0, 1,-1, 0, 0, 0, 0, 24, 0, 0}, + {-2, 0, 2, 1, 0, 0, 2, 0,-2, 0, 0, 0, 0, 284, 0, 0,-151}, + + /* 31-40 */ + {-1, 0, 0, 0, 0, 18,-16, 0, 0, 0, 0, 0, 0, 226, 101, 0, 0}, + {-2, 1, 1, 2, 0, 0, 1, 0,-2, 0, 0, 0, 0, 0, -8, -2, 0}, + {-1, 1,-1, 1, 0, 18,-17, 0, 0, 0, 0, 0, 0, 0, -6, -3, 0}, + {-1, 0, 1, 1, 0, 0, 2, -2, 0, 0, 0, 0, 0, 5, 0, 0, -3}, + { 0, 0, 0, 0, 0, -8, 13, 0, 0, 0, 0, 0, 2, -41, 175, 76, 17}, + { 0, 2,-2, 2, 0, -8, 11, 0, 0, 0, 0, 0, 0, 0, 15, 6, 0}, + { 0, 0, 0, 0, 0, -8, 13, 0, 0, 0, 0, 0, 1, 425, 212, -133, 269}, + { 0, 1,-1, 1, 0, -8, 12, 0, 0, 0, 0, 0, 0, 1200, 598, 319,-641}, + { 0, 0, 0, 0, 0, 8,-13, 0, 0, 0, 0, 0, 0, 235, 334, 0, 0}, + { 0, 1,-1, 1, 0, 8,-14, 0, 0, 0, 0, 0, 0, 11, -12, -7, -6}, + + /* 41-50 */ + { 0, 0, 0, 0, 0, 8,-13, 0, 0, 0, 0, 0, 1, 5, -6, 3, 3}, + {-2, 0, 2, 1, 0, 0, 2, 0,-4, 5, 0, 0, 0, -5, 0, 0, 3}, + {-2, 0, 2, 2, 0, 3, -3, 0, 0, 0, 0, 0, 0, 6, 0, 0, -3}, + {-2, 0, 2, 0, 0, 0, 2, 0,-3, 1, 0, 0, 0, 15, 0, 0, 0}, + { 0, 0, 0, 1, 0, 3, -5, 0, 2, 0, 0, 0, 0, 13, 0, 0, -7}, + {-2, 0, 2, 0, 0, 0, 2, 0,-4, 3, 0, 0, 0, -6, -9, 0, 0}, + { 0,-1, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 266, -78, 0, 0}, + { 0, 0, 0, 1, 0, 0, -1, 2, 0, 0, 0, 0, 0, -460,-435, -232, 246}, + { 0, 1,-1, 2, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0, 15, 7, 0}, + {-1, 1, 0, 1, 0, 3, -5, 0, 0, 0, 0, 0, 0, -3, 0, 0, 2}, + + /* 51-60 */ + {-1, 0, 1, 0, 0, 3, -4, 0, 0, 0, 0, 0, 0, 0, 131, 0, 0}, + {-2, 0, 2, 0, 0, 0, 2, 0,-2,-2, 0, 0, 0, 4, 0, 0, 0}, + {-2, 2, 0, 2, 0, 0, -5, 9, 0, 0, 0, 0, 0, 0, 3, 0, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0, 0,-1, 0, 0, 0, 4, 2, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0, 0, 0, 2, 0, -17, -19, -10, 9}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, -9, -11, 6, -5}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, -6, 0, 0, 3}, + {-1, 0, 1, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, -16, 8, 0, 0}, + { 0,-1, 1, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0}, + + /* 61-70 */ + { 0, 1,-1, 2, 0, 0, -1, 0, 0, 2, 0, 0, 0, 11, 24, 11, -5}, + { 0, 0, 0, 1, 0, 0, -9, 17, 0, 0, 0, 0, 0, -3, -4, -2, 1}, + { 0, 0, 0, 2, 0, -3, 5, 0, 0, 0, 0, 0, 0, 3, 0, 0, -1}, + { 0, 1,-1, 1, 0, 0, -1, 0,-1, 2, 0, 0, 0, 0, -8, -4, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 1,-2, 0, 0, 0, 0, 3, 0, 0}, + { 1, 0,-2, 0, 0, 17,-16, 0,-2, 0, 0, 0, 0, 0, 5, 0, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0, 1,-3, 0, 0, 0, 0, 3, 2, 0}, + {-2, 0, 2, 1, 0, 0, 5, -6, 0, 0, 0, 0, 0, -6, 4, 2, 3}, + { 0,-2, 2, 0, 0, 0, 9,-13, 0, 0, 0, 0, 0, -3, -5, 0, 0}, + { 0, 1,-1, 2, 0, 0, -1, 0, 0, 1, 0, 0, 0, -5, 0, 0, 2}, + + /* 71-80 */ + { 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 24, 13, -2}, + { 0,-1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -42, 20, 0, 0}, + { 0,-2, 2, 0, 0, 5, -6, 0, 0, 0, 0, 0, 0, -10, 233, 0, 0}, + { 0,-1, 1, 1, 0, 5, -7, 0, 0, 0, 0, 0, 0, -3, 0, 0, 1}, + {-2, 0, 2, 0, 0, 6, -8, 0, 0, 0, 0, 0, 0, 78, -18, 0, 0}, + { 2, 1,-3, 1, 0, -6, 7, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0}, + { 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -3, -1, 0}, + { 0,-1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, -4, -2, 1}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0, 0, 2, 0, 0, 0, -8, -4, -1}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, -5, 3, 0}, + + /* 81-90 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, -7, 0, 0, 3}, + { 0, 0, 0, 0, 0, 0, -8, 15, 0, 0, 0, 0, 2, -14, 8, 3, 6}, + { 0, 0, 0, 0, 0, 0, -8, 15, 0, 0, 0, 0, 1, 0, 8, -4, 0}, + { 0, 1,-1, 1, 0, 0, -9, 15, 0, 0, 0, 0, 0, 0, 19, 10, 0}, + { 0, 0, 0, 0, 0, 0, 8,-15, 0, 0, 0, 0, 0, 45, -22, 0, 0}, + { 1,-1,-1, 0, 0, 0, 8,-15, 0, 0, 0, 0, 0, -3, 0, 0, 0}, + { 2, 0,-2, 0, 0, 2, -5, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0}, + {-2, 0, 2, 0, 0, 0, 2, 0,-5, 5, 0, 0, 0, 0, 3, 0, 0}, + { 2, 0,-2, 1, 0, 0, -6, 8, 0, 0, 0, 0, 0, 3, 5, 3, -2}, + { 2, 0,-2, 1, 0, 0, -2, 0, 3, 0, 0, 0, 0, 89, -16, -9, -48}, + + /* 91-100 */ + {-2, 1, 1, 0, 0, 0, 1, 0,-3, 0, 0, 0, 0, 0, 3, 0, 0}, + {-2, 1, 1, 1, 0, 0, 1, 0,-3, 0, 0, 0, 0, -3, 7, 4, 2}, + {-2, 0, 2, 0, 0, 0, 2, 0,-3, 0, 0, 0, 0, -349, -62, 0, 0}, + {-2, 0, 2, 0, 0, 0, 6, -8, 0, 0, 0, 0, 0, -15, 22, 0, 0}, + {-2, 0, 2, 0, 0, 0, 2, 0,-1,-5, 0, 0, 0, -3, 0, 0, 0}, + {-1, 0, 1, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, -53, 0, 0, 0}, + {-1, 1, 1, 1, 0,-20, 20, 0, 0, 0, 0, 0, 0, 5, 0, 0, -3}, + { 1, 0,-2, 0, 0, 20,-21, 0, 0, 0, 0, 0, 0, 0, -8, 0, 0}, + { 0, 0, 0, 1, 0, 0, 8,-15, 0, 0, 0, 0, 0, 15, -7, -4, -8}, + { 0, 2,-2, 1, 0, 0,-10, 15, 0, 0, 0, 0, 0, -3, 0, 0, 1}, + + /* 101-110 */ + { 0,-1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, -21, -78, 0, 0}, + { 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 20, -70, -37, -11}, + { 0, 1,-1, 2, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 6, 3, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0,-2, 4, 0, 0, 0, 5, 3, 2, -2}, + { 2, 0,-2, 1, 0, -6, 8, 0, 0, 0, 0, 0, 0, -17, -4, -2, 9}, + { 0,-2, 2, 1, 0, 5, -6, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 1, 32, 15, -8, 17}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0,-1, 0, 0, 0, 174, 84, 45, -93}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 11, 56, 0, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, -66, -12, -6, 35}, + + /* 111-120 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 47, 8, 4, -25}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 8, 4, 0}, + { 0, 2,-2, 1, 0, 0, -9, 13, 0, 0, 0, 0, 0, 10, -22, -12, -5}, + { 0, 0, 0, 1, 0, 0, 7,-13, 0, 0, 0, 0, 0, -3, 0, 0, 2}, + {-2, 0, 2, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, -24, 12, 0, 0}, + { 0, 0, 0, 0, 0, 0, 9,-17, 0, 0, 0, 0, 0, 5, -6, 0, 0}, + { 0, 0, 0, 0, 0, 0, -9, 17, 0, 0, 0, 0, 2, 3, 0, 0, -2}, + { 1, 0,-1, 1, 0, 0, -3, 4, 0, 0, 0, 0, 0, 4, 3, 1, -2}, + { 1, 0,-1, 1, 0, -3, 4, 0, 0, 0, 0, 0, 0, 0, 29, 15, 0}, + { 0, 0, 0, 2, 0, 0, -1, 2, 0, 0, 0, 0, 0, -5, -4, -2, 2}, + + /* 121-130 */ + { 0,-1, 1, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 8, -3, -1, -5}, + { 0,-2, 2, 0, 1, 0, -2, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0}, + { 0, 0, 0, 0, 0, 3, -5, 0, 2, 0, 0, 0, 0, 10, 0, 0, 0}, + {-2, 0, 2, 1, 0, 0, 2, 0,-3, 1, 0, 0, 0, 3, 0, 0, -2}, + {-2, 0, 2, 1, 0, 3, -3, 0, 0, 0, 0, 0, 0, -5, 0, 0, 3}, + { 0, 0, 0, 1, 0, 8,-13, 0, 0, 0, 0, 0, 0, 46, 66, 35, -25}, + { 0,-1, 1, 0, 0, 8,-12, 0, 0, 0, 0, 0, 0, -14, 7, 0, 0}, + { 0, 2,-2, 1, 0, -8, 11, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0}, + {-1, 0, 1, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, -5, 0, 0, 0}, + {-1, 0, 0, 1, 0, 18,-16, 0, 0, 0, 0, 0, 0, -68, -34, -18, 36}, + + /* 131-140 */ + { 0, 1,-1, 1, 0, 0, -1, 0,-1, 1, 0, 0, 0, 0, 14, 7, 0}, + { 0, 0, 0, 1, 0, 3, -7, 4, 0, 0, 0, 0, 0, 10, -6, -3, -5}, + {-2, 1, 1, 1, 0, 0, -3, 7, 0, 0, 0, 0, 0, -5, -4, -2, 3}, + { 0, 1,-1, 2, 0, 0, -1, 0,-2, 5, 0, 0, 0, -3, 5, 2, 1}, + { 0, 0, 0, 1, 0, 0, 0, 0,-2, 5, 0, 0, 0, 76, 17, 9, -41}, + { 0, 0, 0, 1, 0, 0, -4, 8,-3, 0, 0, 0, 0, 84, 298, 159, -45}, + { 1, 0, 0, 1, 0,-10, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, -1}, + { 0, 2,-2, 1, 0, 0, -2, 0, 0, 0, 0, 0, 0, -3, 0, 0, 2}, + {-1, 0, 0, 1, 0, 10, -3, 0, 0, 0, 0, 0, 0, -3, 0, 0, 1}, + { 0, 0, 0, 1, 0, 0, 4, -8, 3, 0, 0, 0, 0, -82, 292, 156, 44}, + + /* 141-150 */ + { 0, 0, 0, 1, 0, 0, 0, 0, 2,-5, 0, 0, 0, -73, 17, 9, 39}, + { 0,-1, 1, 0, 0, 0, 1, 0, 2,-5, 0, 0, 0, -9, -16, 0, 0}, + { 2,-1,-1, 1, 0, 0, 3, -7, 0, 0, 0, 0, 0, 3, 0, -1, -2}, + {-2, 0, 2, 0, 0, 0, 2, 0, 0,-5, 0, 0, 0, -3, 0, 0, 0}, + { 0, 0, 0, 1, 0, -3, 7, -4, 0, 0, 0, 0, 0, -9, -5, -3, 5}, + {-2, 0, 2, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, -439, 0, 0, 0}, + { 1, 0, 0, 1, 0,-18, 16, 0, 0, 0, 0, 0, 0, 57, -28, -15, -30}, + {-2, 1, 1, 1, 0, 0, 1, 0,-2, 0, 0, 0, 0, 0, -6, -3, 0}, + { 0, 1,-1, 2, 0, -8, 12, 0, 0, 0, 0, 0, 0, -4, 0, 0, 2}, + { 0, 0, 0, 1, 0, -8, 13, 0, 0, 0, 0, 0, 0, -40, 57, 30, 21}, + + /* 151-160 */ + { 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 1, 23, 7, 3, -13}, + { 0, 1,-1, 1, 0, 0, 0, -2, 0, 0, 0, 0, 0, 273, 80, 43,-146}, + { 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0, -449, 430, 0, 0}, + { 0, 1,-1, 1, 0, 0, -2, 2, 0, 0, 0, 0, 0, -8, -47, -25, 4}, + { 0, 0, 0, 0, 0, 0, -1, 2, 0, 0, 0, 0, 1, 6, 47, 25, -3}, + {-1, 0, 1, 1, 0, 3, -4, 0, 0, 0, 0, 0, 0, 0, 23, 13, 0}, + {-1, 0, 1, 1, 0, 0, 3, -4, 0, 0, 0, 0, 0, -3, 0, 0, 2}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0,-2, 0, 0, 0, 3, -4, -2, -2}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0, 2, 0, 0, 0, -48,-110, -59, 26}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 51, 114, 61, -27}, + + /* 161-170 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, -133, 0, 0, 57}, + { 0, 1,-1, 0, 0, 3, -6, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0}, + { 0, 0, 0, 1, 0, -3, 5, 0, 0, 0, 0, 0, 0, -21, -6, -3, 11}, + { 0, 1,-1, 2, 0, -3, 4, 0, 0, 0, 0, 0, 0, 0, -3, -1, 0}, + { 0, 0, 0, 1, 0, 0, -2, 4, 0, 0, 0, 0, 0, -11, -21, -11, 6}, + { 0, 2,-2, 1, 0, -5, 6, 0, 0, 0, 0, 0, 0, -18,-436, -233, 9}, + { 0,-1, 1, 0, 0, 5, -7, 0, 0, 0, 0, 0, 0, 35, -7, 0, 0}, + { 0, 0, 0, 1, 0, 5, -8, 0, 0, 0, 0, 0, 0, 0, 5, 3, 0}, + {-2, 0, 2, 1, 0, 6, -8, 0, 0, 0, 0, 0, 0, 11, -3, -1, -6}, + { 0, 0, 0, 1, 0, 0, -8, 15, 0, 0, 0, 0, 0, -5, -3, -1, 3}, + + /* 171-180 */ + {-2, 0, 2, 1, 0, 0, 2, 0,-3, 0, 0, 0, 0, -53, -9, -5, 28}, + {-2, 0, 2, 1, 0, 0, 6, -8, 0, 0, 0, 0, 0, 0, 3, 2, 1}, + { 1, 0,-1, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, 4, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 0, 0, 3,-5, 0, 0, 0, 0, -4, 0, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0,-1, 0, 0, 0, 0, -50, 194, 103, 27}, + { 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 1, -13, 52, 28, 7}, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -91, 248, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 6, 49, 26, -3}, + { 0, 1,-1, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, -6, -47, -25, 3}, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5, 3, 0}, + + /* 181-190 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 52, 23, 10, -23}, + { 0, 1,-1, 2, 0, 0, -1, 0, 0,-1, 0, 0, 0, -3, 0, 0, 1}, + { 0, 0, 0, 1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 5, 3, 0}, + { 0,-1, 1, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, -4, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, -7, 13, 0, 0, 0, 0, 2, -4, 8, 3, 2}, + { 0, 0, 0, 0, 0, 0, 7,-13, 0, 0, 0, 0, 0, 10, 0, 0, 0}, + { 2, 0,-2, 1, 0, 0, -5, 6, 0, 0, 0, 0, 0, 3, 0, 0, -2}, + { 0, 2,-2, 1, 0, 0, -8, 11, 0, 0, 0, 0, 0, 0, 8, 4, 0}, + { 0, 2,-2, 1,-1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 8, 4, 1}, + {-2, 0, 2, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, -4, 0, 0, 0}, + + /* 191-200 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, -4, 0, 0, 0}, + { 0, 1,-1, 1, 0, 0, -1, 0, 0, 3, 0, 0, 0, -8, 4, 2, 4}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 8, -4, -2, -4}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 0, 15, 7, 0}, + {-2, 0, 2, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, -138, 0, 0, 0}, + { 0, 0, 0, 2, 0, 0, -4, 8,-3, 0, 0, 0, 0, 0, -7, -3, 0}, + { 0, 0, 0, 2, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, -7, -3, 0}, + { 2, 0,-2, 1, 0, 0, -2, 0, 2, 0, 0, 0, 0, 54, 0, 0, -29}, + { 0, 1,-1, 2, 0, 0, -1, 0, 2, 0, 0, 0, 0, 0, 10, 4, 0}, + { 0, 1,-1, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, -7, 0, 0, 3}, + + /* 201-210 */ + { 0, 0, 0, 1, 0, 0, 1, -2, 0, 0, 0, 0, 0, -37, 35, 19, 20}, + { 0,-1, 1, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 4, 0, 0}, + { 0,-1, 1, 0, 0, 0, 1, 0, 0,-2, 0, 0, 0, -4, 9, 0, 0}, + { 0, 2,-2, 1, 0, 0, -2, 0, 0, 2, 0, 0, 0, 8, 0, 0, -4}, + { 0, 1,-1, 1, 0, 3, -6, 0, 0, 0, 0, 0, 0, -9, -14, -8, 5}, + { 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0, 1, -3, -9, -5, 3}, + { 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0, 0, -145, 47, 0, 0}, + { 0, 1,-1, 1, 0, -3, 4, 0, 0, 0, 0, 0, 0, -10, 40, 21, 5}, + { 0, 0, 0, 0, 0, -3, 5, 0, 0, 0, 0, 0, 1, 11, -49, -26, -7}, + { 0, 0, 0, 0, 0, -3, 5, 0, 0, 0, 0, 0, 2,-2150, 0, 0, 932}, + + /* 211-220 */ + { 0, 2,-2, 2, 0, -3, 3, 0, 0, 0, 0, 0, 0, -12, 0, 0, 5}, + { 0, 0, 0, 0, 0, -3, 5, 0, 0, 0, 0, 0, 2, 85, 0, 0, -37}, + { 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 1, 4, 0, 0, -2}, + { 0, 1,-1, 1, 0, 0, 1, -4, 0, 0, 0, 0, 0, 3, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 0, -86, 153, 0, 0}, + { 0, 0, 0, 0, 0, 0, -2, 4, 0, 0, 0, 0, 1, -6, 9, 5, 3}, + { 0, 1,-1, 1, 0, 0, -3, 4, 0, 0, 0, 0, 0, 9, -13, -7, -5}, + { 0, 0, 0, 0, 0, 0, -2, 4, 0, 0, 0, 0, 1, -8, 12, 6, 4}, + { 0, 0, 0, 0, 0, 0, -2, 4, 0, 0, 0, 0, 2, -51, 0, 0, 22}, + { 0, 0, 0, 0, 0, -5, 8, 0, 0, 0, 0, 0, 2, -11,-268, -116, 5}, + + /* 221-230 */ + { 0, 2,-2, 2, 0, -5, 6, 0, 0, 0, 0, 0, 0, 0, 12, 5, 0}, + { 0, 0, 0, 0, 0, -5, 8, 0, 0, 0, 0, 0, 2, 0, 7, 3, 0}, + { 0, 0, 0, 0, 0, -5, 8, 0, 0, 0, 0, 0, 1, 31, 6, 3, -17}, + { 0, 1,-1, 1, 0, -5, 7, 0, 0, 0, 0, 0, 0, 140, 27, 14, -75}, + { 0, 0, 0, 0, 0, -5, 8, 0, 0, 0, 0, 0, 1, 57, 11, 6, -30}, + { 0, 0, 0, 0, 0, 5, -8, 0, 0, 0, 0, 0, 0, -14, -39, 0, 0}, + { 0, 1,-1, 2, 0, 0, -1, 0,-1, 0, 0, 0, 0, 0, -6, -2, 0}, + { 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 4, 15, 8, -2}, + { 0,-1, 1, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 0, 4, 0, 0}, + { 0, 2,-2, 1, 0, 0, -2, 0, 1, 0, 0, 0, 0, -3, 0, 0, 1}, + + /* 231-240 */ + { 0, 0, 0, 0, 0, 0, -6, 11, 0, 0, 0, 0, 2, 0, 11, 5, 0}, + { 0, 0, 0, 0, 0, 0, 6,-11, 0, 0, 0, 0, 0, 9, 6, 0, 0}, + { 0, 0, 0, 0,-1, 0, 4, 0, 0, 0, 0, 0, 2, -4, 10, 4, 2}, + { 0, 0, 0, 0, 1, 0, -4, 0, 0, 0, 0, 0, 0, 5, 3, 0, 0}, + { 2, 0,-2, 1, 0, -3, 3, 0, 0, 0, 0, 0, 0, 16, 0, 0, -9}, + {-2, 0, 2, 0, 0, 0, 2, 0, 0,-2, 0, 0, 0, -3, 0, 0, 0}, + { 0, 2,-2, 1, 0, 0, -7, 9, 0, 0, 0, 0, 0, 0, 3, 2, -1}, + { 0, 0, 0, 0, 0, 0, 0, 0, 4,-5, 0, 0, 2, 7, 0, 0, -3}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, -25, 22, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 42, 223, 119, -22}, + + /* 241-250 */ + { 0, 1,-1, 1, 0, 0, -1, 0, 2, 0, 0, 0, 0, -27,-143, -77, 14}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 9, 49, 26, -5}, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2,-1166, 0, 0, 505}, + { 0, 2,-2, 2, 0, 0, -2, 0, 2, 0, 0, 0, 0, -5, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 2, -6, 0, 0, 3}, + { 0, 0, 0, 1, 0, 3, -5, 0, 0, 0, 0, 0, 0, -8, 0, 1, 4}, + { 0,-1, 1, 0, 0, 3, -4, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0}, + { 0, 2,-2, 1, 0, -3, 3, 0, 0, 0, 0, 0, 0, 117, 0, 0, -63}, + { 0, 0, 0, 1, 0, 0, 2, -4, 0, 0, 0, 0, 0, -4, 8, 4, 2}, + { 0, 2,-2, 1, 0, 0, -4, 4, 0, 0, 0, 0, 0, 3, 0, 0, -2}, + + /* 251-260 */ + { 0, 1,-1, 2, 0, -5, 7, 0, 0, 0, 0, 0, 0, -5, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, 0, 0, 31, 0, 0}, + { 0, 0, 0, 0, 0, 0, -3, 6, 0, 0, 0, 0, 1, -5, 0, 1, 3}, + { 0, 1,-1, 1, 0, 0, -4, 6, 0, 0, 0, 0, 0, 4, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, -3, 6, 0, 0, 0, 0, 1, -4, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, -3, 6, 0, 0, 0, 0, 2, -24, -13, -6, 10}, + { 0,-1, 1, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0}, + { 0, 0, 0, 1, 0, 2, -3, 0, 0, 0, 0, 0, 0, 0, -32, -17, 0}, + { 0, 0, 0, 0, 0, 0, -5, 9, 0, 0, 0, 0, 2, 8, 12, 5, -3}, + { 0, 0, 0, 0, 0, 0, -5, 9, 0, 0, 0, 0, 1, 3, 0, 0, -1}, + + /* 261-270 */ + { 0, 0, 0, 0, 0, 0, 5, -9, 0, 0, 0, 0, 0, 7, 13, 0, 0}, + { 0,-1, 1, 0, 0, 0, 1, 0,-2, 0, 0, 0, 0, -3, 16, 0, 0}, + { 0, 2,-2, 1, 0, 0, -2, 0, 2, 0, 0, 0, 0, 50, 0, 0, -27}, + {-2, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -5, -3, 0}, + { 0,-2, 2, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0}, + { 0, 0, 0, 0, 0, -6, 10, 0, 0, 0, 0, 0, 1, 0, 5, 3, 1}, + { 0, 0, 0, 0, 0, -6, 10, 0, 0, 0, 0, 0, 2, 24, 5, 2, -11}, + { 0, 0, 0, 0, 0, -2, 3, 0, 0, 0, 0, 0, 2, 5, -11, -5, -2}, + { 0, 0, 0, 0, 0, -2, 3, 0, 0, 0, 0, 0, 1, 30, -3, -2, -16}, + { 0, 1,-1, 1, 0, -2, 2, 0, 0, 0, 0, 0, 0, 18, 0, 0, -9}, + + /* 271-280 */ + { 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0, 0, 8, 614, 0, 0}, + { 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0, 1, 3, -3, -1, -2}, + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 6, 17, 9, -3}, + { 0, 1,-1, 1, 0, 0, -1, 0, 3, 0, 0, 0, 0, -3, -9, -5, 2}, + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 6, 3, -1}, + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, -127, 21, 9, 55}, + { 0, 0, 0, 0, 0, 0, 4, -8, 0, 0, 0, 0, 0, 3, 5, 0, 0}, + { 0, 0, 0, 0, 0, 0, -4, 8, 0, 0, 0, 0, 2, -6, -10, -4, 3}, + { 0,-2, 2, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 5, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, -4, 7, 0, 0, 0, 0, 2, 16, 9, 4, -7}, + + /* 281-290 */ + { 0, 0, 0, 0, 0, 0, -4, 7, 0, 0, 0, 0, 1, 3, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 4, -7, 0, 0, 0, 0, 0, 0, 22, 0, 0}, + { 0, 0, 0, 1, 0, -2, 3, 0, 0, 0, 0, 0, 0, 0, 19, 10, 0}, + { 0, 2,-2, 1, 0, 0, -2, 0, 3, 0, 0, 0, 0, 7, 0, 0, -4}, + { 0, 0, 0, 0, 0, 0, -5, 10, 0, 0, 0, 0, 2, 0, -5, -2, 0}, + { 0, 0, 0, 1, 0, -1, 2, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0}, + { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2, -9, 3, 1, 4}, + { 0, 0, 0, 0, 0, 0, -3, 5, 0, 0, 0, 0, 2, 17, 0, 0, -7}, + { 0, 0, 0, 0, 0, 0, -3, 5, 0, 0, 0, 0, 1, 0, -3, -2, -1}, + { 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0, -20, 34, 0, 0}, + + /* 291-300 */ + { 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0, 1, -10, 0, 1, 5}, + { 0, 1,-1, 1, 0, 1, -3, 0, 0, 0, 0, 0, 0, -4, 0, 0, 2}, + { 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0, 0, 22, -87, 0, 0}, + { 0, 0, 0, 0, 0, -1, 2, 0, 0, 0, 0, 0, 1, -4, 0, 0, 2}, + { 0, 0, 0, 0, 0, -1, 2, 0, 0, 0, 0, 0, 2, -3, -6, -2, 1}, + { 0, 0, 0, 0, 0, -7, 11, 0, 0, 0, 0, 0, 2, -16, -3, -1, 7}, + { 0, 0, 0, 0, 0, -7, 11, 0, 0, 0, 0, 0, 1, 0, -3, -2, 0}, + { 0,-2, 2, 0, 0, 4, -4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0, -68, 39, 0, 0}, + { 0, 2,-2, 1, 0, -4, 4, 0, 0, 0, 0, 0, 0, 27, 0, 0, -14}, + + /* 301-310 */ + { 0,-1, 1, 0, 0, 4, -5, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, -25, 0, 0, 0}, + { 0, 0, 0, 0, 0, -4, 7, 0, 0, 0, 0, 0, 1, -12, -3, -2, 6}, + { 0, 1,-1, 1, 0, -4, 6, 0, 0, 0, 0, 0, 0, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, -4, 7, 0, 0, 0, 0, 0, 2, 3, 66, 29, -1}, + { 0, 0, 0, 0, 0, -4, 6, 0, 0, 0, 0, 0, 2, 490, 0, 0,-213}, + { 0, 0, 0, 0, 0, -4, 6, 0, 0, 0, 0, 0, 1, -22, 93, 49, 12}, + { 0, 1,-1, 1, 0, -4, 5, 0, 0, 0, 0, 0, 0, -7, 28, 15, 4}, + { 0, 0, 0, 0, 0, -4, 6, 0, 0, 0, 0, 0, 1, -3, 13, 7, 2}, + { 0, 0, 0, 0, 0, 4, -6, 0, 0, 0, 0, 0, 0, -46, 14, 0, 0}, + + /* 311-320 */ + {-2, 0, 2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 1, 0, 0}, + { 0,-1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0}, + { 0, 0, 0, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, -28, 0, 0, 15}, + { 0, 0, 0, 0, 0, 0, -1, 0, 5, 0, 0, 0, 2, 5, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 1, -3, 0, 0, 0, 0, 0, 0, 3, 0, 0}, + { 0, 0, 0, 0, 0, 0, -1, 3, 0, 0, 0, 0, 2, -11, 0, 0, 5}, + { 0, 0, 0, 0, 0, 0, -7, 12, 0, 0, 0, 0, 2, 0, 3, 1, 0}, + { 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 2, -3, 0, 0, 1}, + { 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 1, 25, 106, 57, -13}, + + /* 321-330 */ + { 0, 1,-1, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 5, 21, 11, -3}, + { 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 1485, 0, 0, 0}, + { 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 1, -7, -32, -17, 4}, + { 0, 1,-1, 1, 0, 1, -2, 0, 0, 0, 0, 0, 0, 0, 5, 3, 0}, + { 0, 0, 0, 0, 0, 0, -2, 5, 0, 0, 0, 0, 2, -6, -3, -2, 3}, + { 0, 0, 0, 0, 0, 0, -1, 0, 4, 0, 0, 0, 2, 30, -6, -2, -13}, + { 0, 0, 0, 0, 0, 0, 1, 0,-4, 0, 0, 0, 0, -4, 4, 0, 0}, + { 0, 0, 0, 1, 0, -1, 1, 0, 0, 0, 0, 0, 0, -19, 0, 0, 10}, + { 0, 0, 0, 0, 0, 0, -6, 10, 0, 0, 0, 0, 2, 0, 4, 2, -1}, + { 0, 0, 0, 0, 0, 0, -6, 10, 0, 0, 0, 0, 0, 0, 3, 0, 0}, + + /* 331-340 */ + { 0, 2,-2, 1, 0, 0, -3, 0, 3, 0, 0, 0, 0, 4, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, -3, 7, 0, 0, 0, 0, 2, 0, -3, -1, 0}, + {-2, 0, 2, 0, 0, 4, -4, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, -5, 8, 0, 0, 0, 0, 2, 5, 3, 1, -2}, + { 0, 0, 0, 0, 0, 0, 5, -8, 0, 0, 0, 0, 0, 0, 11, 0, 0}, + { 0, 0, 0, 0, 0, 0, -1, 0, 3, 0, 0, 0, 2, 118, 0, 0, -52}, + { 0, 0, 0, 0, 0, 0, -1, 0, 3, 0, 0, 0, 1, 0, -5, -3, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0,-3, 0, 0, 0, 0, -28, 36, 0, 0}, + { 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 0, 0, 5, -5, 0, 0}, + { 0, 0, 0, 0, 0, -2, 4, 0, 0, 0, 0, 0, 1, 14, -59, -31, -8}, + + /* 341-350 */ + { 0, 1,-1, 1, 0, -2, 3, 0, 0, 0, 0, 0, 0, 0, 9, 5, 1}, + { 0, 0, 0, 0, 0, -2, 4, 0, 0, 0, 0, 0, 2, -458, 0, 0, 198}, + { 0, 0, 0, 0, 0, -6, 9, 0, 0, 0, 0, 0, 2, 0, -45, -20, 0}, + { 0, 0, 0, 0, 0, -6, 9, 0, 0, 0, 0, 0, 1, 9, 0, 0, -5}, + { 0, 0, 0, 0, 0, 6, -9, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0}, + { 0, 0, 0, 1, 0, 0, 1, 0,-2, 0, 0, 0, 0, 0, -4, -2, -1}, + { 0, 2,-2, 1, 0, -2, 2, 0, 0, 0, 0, 0, 0, 11, 0, 0, -6}, + { 0, 0, 0, 0, 0, 0, -4, 6, 0, 0, 0, 0, 2, 6, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 4, -6, 0, 0, 0, 0, 0, -16, 23, 0, 0}, + { 0, 0, 0, 1, 0, 3, -4, 0, 0, 0, 0, 0, 0, 0, -4, -2, 0}, + + /* 351-360 */ + { 0, 0, 0, 0, 0, 0, -1, 0, 2, 0, 0, 0, 2, -5, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 1, 0,-2, 0, 0, 0, 0, -166, 269, 0, 0}, + { 0, 0, 0, 1, 0, 0, 1, 0,-1, 0, 0, 0, 0, 15, 0, 0, -8}, + { 0, 0, 0, 0, 0, -5, 9, 0, 0, 0, 0, 0, 2, 10, 0, 0, -4}, + { 0, 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, -78, 45, 0, 0}, + { 0, 0, 0, 0, 0, -3, 4, 0, 0, 0, 0, 0, 2, 0, -5, -2, 0}, + { 0, 0, 0, 0, 0, -3, 4, 0, 0, 0, 0, 0, 1, 7, 0, 0, -4}, + { 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, 0, -5, 328, 0, 0}, + { 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, 1, 3, 0, 0, -2}, + { 0, 0, 0, 1, 0, 0, 2, -2, 0, 0, 0, 0, 0, 5, 0, 0, -2}, + + /* 361-370 */ + { 0, 0, 0, 1, 0, 0, -1, 0, 2, 0, 0, 0, 0, 0, 3, 1, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 0,-3, 0, 0, 0, -3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 1,-5, 0, 0, 0, -3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, -4, -2, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0,-1223, -26, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 1, 0, 7, 3, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0,-3, 5, 0, 0, 0, 3, 0, 0, 0}, + { 0, 0, 0, 1, 0, -3, 4, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 0,-2, 0, 0, 0, -6, 20, 0, 0}, + { 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, -368, 0, 0, 0}, + + /* 371-380 */ + { 0, 0, 0, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, -75, 0, 0, 0}, + { 0, 0, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, 11, 0, 0, -6}, + { 0, 0, 0, 1, 0, 0, -2, 2, 0, 0, 0, 0, 0, 3, 0, 0, -2}, + { 0, 0, 0, 0, 0, -8, 14, 0, 0, 0, 0, 0, 2, -3, 0, 0, 1}, + { 0, 0, 0, 0, 0, 0, 1, 0, 2,-5, 0, 0, 0, -13, -30, 0, 0}, + { 0, 0, 0, 0, 0, 0, 5, -8, 3, 0, 0, 0, 0, 21, 3, 0, 0}, + { 0, 0, 0, 0, 0, 0, 5, -8, 3, 0, 0, 0, 2, -3, 0, 0, 1}, + { 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, -4, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 8, -27, 0, 0}, + { 0, 0, 0, 0, 0, 0, 3, -8, 3, 0, 0, 0, 0, -19, -11, 0, 0}, + + /* 381-390 */ + { 0, 0, 0, 0, 0, 0, -3, 8,-3, 0, 0, 0, 2, -4, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 1, 0,-2, 5, 0, 0, 2, 0, 5, 2, 0}, + { 0, 0, 0, 0, 0, -8, 12, 0, 0, 0, 0, 0, 2, -6, 0, 0, 2}, + { 0, 0, 0, 0, 0, -8, 12, 0, 0, 0, 0, 0, 0, -8, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 1,-2, 0, 0, 0, -1, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 2, -14, 0, 0, 6}, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 6, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, -74, 0, 0, 32}, + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 2, 0, -3, -1, 0}, + { 0, 2,-2, 1, 0, -5, 5, 0, 0, 0, 0, 0, 0, 4, 0, 0, -2}, + + /* 391-400 */ + { 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 8, 11, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 3, 2, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 2, -262, 0, 0, 114}, + { 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0}, + { 0, 0, 0, 0, 0, -3, 6, 0, 0, 0, 0, 0, 1, -7, 0, 0, 4}, + { 0, 0, 0, 0, 0, -3, 6, 0, 0, 0, 0, 0, 2, 0, -27, -12, 0}, + { 0, 0, 0, 0, 0, 0, -1, 4, 0, 0, 0, 0, 2, -19, -8, -4, 8}, + { 0, 0, 0, 0, 0, -5, 7, 0, 0, 0, 0, 0, 2, 202, 0, 0, -87}, + { 0, 0, 0, 0, 0, -5, 7, 0, 0, 0, 0, 0, 1, -8, 35, 19, 5}, + { 0, 1,-1, 1, 0, -5, 6, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0}, + + /* 401-410 */ + { 0, 0, 0, 0, 0, 5, -7, 0, 0, 0, 0, 0, 0, 16, -5, 0, 0}, + { 0, 2,-2, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, 5, 0, 0, -3}, + { 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, -3, 0, 0}, + { 0, 0, 0, 0,-1, 0, 3, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, -35, -48, -21, 15}, + { 0, 0, 0, 0, 0, 0, -2, 6, 0, 0, 0, 0, 2, -3, -5, -2, 1}, + { 0, 0, 0, 1, 0, 2, -2, 0, 0, 0, 0, 0, 0, 6, 0, 0, -3}, + { 0, 0, 0, 0, 0, 0, -6, 9, 0, 0, 0, 0, 2, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, 0, 6, -9, 0, 0, 0, 0, 0, 0, -5, 0, 0}, + { 0, 0, 0, 0, 0, -2, 2, 0, 0, 0, 0, 0, 1, 12, 55, 29, -6}, + + /* 411-420 */ + { 0, 1,-1, 1, 0, -2, 1, 0, 0, 0, 0, 0, 0, 0, 5, 3, 0}, + { 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, -598, 0, 0, 0}, + { 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 1, -3, -13, -7, 1}, + { 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 2, -5, -7, -3, 2}, + { 0, 0, 0, 0, 0, 0, -5, 7, 0, 0, 0, 0, 2, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, 0, 5, -7, 0, 0, 0, 0, 0, 5, -7, 0, 0}, + { 0, 0, 0, 1, 0, -2, 2, 0, 0, 0, 0, 0, 0, 4, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 4, -5, 0, 0, 0, 0, 0, 16, -6, 0, 0}, + { 0, 0, 0, 0, 0, 1, -3, 0, 0, 0, 0, 0, 0, 8, -3, 0, 0}, + { 0, 0, 0, 0, 0, -1, 3, 0, 0, 0, 0, 0, 1, 8, -31, -16, -4}, + + /* 421-430 */ + { 0, 1,-1, 1, 0, -1, 2, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0}, + { 0, 0, 0, 0, 0, -1, 3, 0, 0, 0, 0, 0, 2, 113, 0, 0, -49}, + { 0, 0, 0, 0, 0, -7, 10, 0, 0, 0, 0, 0, 2, 0, -24, -10, 0}, + { 0, 0, 0, 0, 0, -7, 10, 0, 0, 0, 0, 0, 1, 4, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 27, 0, 0, 0}, + { 0, 0, 0, 0, 0, -4, 8, 0, 0, 0, 0, 0, 2, -3, 0, 0, 1}, + { 0, 0, 0, 0, 0, -4, 5, 0, 0, 0, 0, 0, 2, 0, -4, -2, 0}, + { 0, 0, 0, 0, 0, -4, 5, 0, 0, 0, 0, 0, 1, 5, 0, 0, -2}, + { 0, 0, 0, 0, 0, 4, -5, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0}, + { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 2, -13, 0, 0, 6}, + + /* 431-440 */ + { 0, 0, 0, 0, 0, 0, -2, 0, 5, 0, 0, 0, 2, 5, 0, 0, -2}, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 2, -18, -10, -4, 8}, + { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -4, -28, 0, 0}, + { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, -5, 6, 3, 2}, + { 0, 0, 0, 0, 0, -9, 13, 0, 0, 0, 0, 0, 2, -3, 0, 0, 1}, + { 0, 0, 0, 0, 0, 0, -1, 5, 0, 0, 0, 0, 2, -5, -9, -4, 2}, + { 0, 0, 0, 0, 0, 0, -2, 0, 4, 0, 0, 0, 2, 17, 0, 0, -7}, + { 0, 0, 0, 0, 0, 0, 2, 0,-4, 0, 0, 0, 0, 11, 4, 0, 0}, + { 0, 0, 0, 0, 0, 0, -2, 7, 0, 0, 0, 0, 2, 0, -6, -2, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0,-3, 0, 0, 0, 0, 83, 15, 0, 0}, + + /* 441-450 */ + { 0, 0, 0, 0, 0, -2, 5, 0, 0, 0, 0, 0, 1, -4, 0, 0, 2}, + { 0, 0, 0, 0, 0, -2, 5, 0, 0, 0, 0, 0, 2, 0,-114, -49, 0}, + { 0, 0, 0, 0, 0, -6, 8, 0, 0, 0, 0, 0, 2, 117, 0, 0, -51}, + { 0, 0, 0, 0, 0, -6, 8, 0, 0, 0, 0, 0, 1, -5, 19, 10, 2}, + { 0, 0, 0, 0, 0, 6, -8, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0}, + { 0, 0, 0, 1, 0, 0, 2, 0,-2, 0, 0, 0, 0, -3, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, -3, 9, 0, 0, 0, 0, 2, 0, -3, -1, 0}, + { 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, 3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 2, 0, -6, -2, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 393, 3, 0, 0}, + + /* 451-460 */ + { 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 1, -4, 21, 11, 2}, + { 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 2, -6, 0, -1, 3}, + { 0, 0, 0, 0, 0, -5, 10, 0, 0, 0, 0, 0, 2, -3, 8, 4, 1}, + { 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, 8, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 2, 18, -29, -13, -8}, + { 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 1, 8, 34, 18, -4}, + { 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0}, + { 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 1, 3, 12, 6, -1}, + { 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 2, 54, -15, -7, -24}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0,-3, 0, 0, 0, 0, 3, 0, 0}, + + /* 461-470 */ + { 0, 0, 0, 0, 0, 0, -5, 13, 0, 0, 0, 0, 2, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, 0, 2, 0,-1, 0, 0, 0, 0, 0, 35, 0, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0,-1, 0, 0, 0, 2, -154, -30, -13, 67}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0,-2, 0, 0, 0, 15, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0,-2, 0, 0, 1, 0, 4, 2, 0}, + { 0, 0, 0, 0, 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, 9, 0, 0}, + { 0, 0, 0, 0, 0, 0, 3, -2, 0, 0, 0, 0, 2, 80, -71, -31, -35}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0,-1, 0, 0, 2, 0, -20, -9, 0}, + { 0, 0, 0, 0, 0, 0, -6, 15, 0, 0, 0, 0, 2, 11, 5, 2, -5}, + { 0, 0, 0, 0, 0, -8, 15, 0, 0, 0, 0, 0, 2, 61, -96, -42, -27}, + + /* 471-480 */ + { 0, 0, 0, 0, 0, -3, 9, -4, 0, 0, 0, 0, 2, 14, 9, 4, -6}, + { 0, 0, 0, 0, 0, 0, 2, 0, 2,-5, 0, 0, 2, -11, -6, -3, 5}, + { 0, 0, 0, 0, 0, 0, -2, 8,-1,-5, 0, 0, 2, 0, -3, -1, 0}, + { 0, 0, 0, 0, 0, 0, 6, -8, 3, 0, 0, 0, 2, 123,-415, -180, -53}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, -35}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 7, -32, -17, -4}, + { 0, 1,-1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -9, -5, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1, 0, -4, 2, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, -89, 0, 0, 38}, + + /* 481-490 */ + { 0, 0, 0, 0, 0, 0, -6, 16,-4,-5, 0, 0, 2, 0, -86, -19, -6}, + { 0, 0, 0, 0, 0, 0, -2, 8,-3, 0, 0, 0, 2, 0, 0, -19, 6}, + { 0, 0, 0, 0, 0, 0, -2, 8,-3, 0, 0, 0, 2, -123,-416, -180, 53}, + { 0, 0, 0, 0, 0, 0, 6, -8, 1, 5, 0, 0, 2, 0, -3, -1, 0}, + { 0, 0, 0, 0, 0, 0, 2, 0,-2, 5, 0, 0, 2, 12, -6, -3, -5}, + { 0, 0, 0, 0, 0, 3, -5, 4, 0, 0, 0, 0, 2, -13, 9, 4, 6}, + { 0, 0, 0, 0, 0, -8, 11, 0, 0, 0, 0, 0, 2, 0, -15, -7, 0}, + { 0, 0, 0, 0, 0, -8, 11, 0, 0, 0, 0, 0, 1, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, -8, 11, 0, 0, 0, 0, 0, 2, -62, -97, -42, 27}, + { 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 2, -11, 5, 2, 5}, + + /* 491-500 */ + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 2, 0, -19, -8, 0}, + { 0, 0, 0, 0, 0, 3, -3, 0, 2, 0, 0, 0, 2, -3, 0, 0, 1}, + { 0, 2,-2, 1, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, 4, 2, 0}, + { 0, 1,-1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0}, + { 0, 2,-2, 1, 0, 0, -4, 8,-3, 0, 0, 0, 0, 0, 4, 2, 0}, + { 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 2, -85, -70, -31, 37}, + { 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 2, 163, -12, -5, -72}, + { 0, 0, 0, 0, 0, -3, 7, 0, 0, 0, 0, 0, 2, -63, -16, -7, 28}, + { 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 2, -21, -32, -14, 9}, + { 0, 0, 0, 0, 0, -5, 6, 0, 0, 0, 0, 0, 2, 0, -3, -1, 0}, + + /* 501-510 */ + { 0, 0, 0, 0, 0, -5, 6, 0, 0, 0, 0, 0, 1, 3, 0, 0, -2}, + { 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0}, + { 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, 2, 3, 10, 4, -1}, + { 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, 0, -1, 6, 0, 0, 0, 0, 2, 0, -7, -3, 0}, + { 0, 0, 0, 0, 0, 0, 7, -9, 0, 0, 0, 0, 2, 0, -4, -2, 0}, + { 0, 0, 0, 0, 0, 2, -1, 0, 0, 0, 0, 0, 0, 6, 19, 0, 0}, + { 0, 0, 0, 0, 0, 2, -1, 0, 0, 0, 0, 0, 2, 5,-173, -75, -2}, + { 0, 0, 0, 0, 0, 0, 6, -7, 0, 0, 0, 0, 2, 0, -7, -3, 0}, + { 0, 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 2, 7, -12, -5, -3}, + + /* 511-520 */ + { 0, 0, 0, 0, 0, -1, 4, 0, 0, 0, 0, 0, 1, -3, 0, 0, 2}, + { 0, 0, 0, 0, 0, -1, 4, 0, 0, 0, 0, 0, 2, 3, -4, -2, -1}, + { 0, 0, 0, 0, 0, -7, 9, 0, 0, 0, 0, 0, 2, 74, 0, 0, -32}, + { 0, 0, 0, 0, 0, -7, 9, 0, 0, 0, 0, 0, 1, -3, 12, 6, 2}, + { 0, 0, 0, 0, 0, 0, 4, -3, 0, 0, 0, 0, 2, 26, -14, -6, -11}, + { 0, 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 2, 19, 0, 0, -8}, + { 0, 0, 0, 0, 0, -4, 4, 0, 0, 0, 0, 0, 1, 6, 24, 13, -3}, + { 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0}, + { 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, 1, 0, -10, -5, 0}, + { 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, 2, 11, -3, -1, -5}, + + /* 521-530 */ + { 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 2, 3, 0, 1, -1}, + { 0, 0, 0, 0, 0, 0, -3, 0, 5, 0, 0, 0, 2, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0}, + { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 5, -23, -12, -3}, + { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, -339, 0, 0, 147}, + { 0, 0, 0, 0, 0, -9, 12, 0, 0, 0, 0, 0, 2, 0, -10, -5, 0}, + { 0, 0, 0, 0, 0, 0, 3, 0,-4, 0, 0, 0, 0, 5, 0, 0, 0}, + { 0, 2,-2, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, 0, 7, -8, 0, 0, 0, 0, 2, 0, -4, -2, 0}, + { 0, 0, 0, 0, 0, 0, 3, 0,-3, 0, 0, 0, 0, 18, -3, 0, 0}, + + /* 531-540 */ + { 0, 0, 0, 0, 0, 0, 3, 0,-3, 0, 0, 0, 2, 9, -11, -5, -4}, + { 0, 0, 0, 0, 0, -2, 6, 0, 0, 0, 0, 0, 2, -8, 0, 0, 4}, + { 0, 0, 0, 0, 0, -6, 7, 0, 0, 0, 0, 0, 1, 3, 0, 0, -1}, + { 0, 0, 0, 0, 0, 6, -7, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0}, + { 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 0, 0, 2, 6, -9, -4, -2}, + { 0, 0, 0, 0, 0, 0, 3, 0,-2, 0, 0, 0, 0, -4, -12, 0, 0}, + { 0, 0, 0, 0, 0, 0, 3, 0,-2, 0, 0, 0, 2, 67, -91, -39, -29}, + { 0, 0, 0, 0, 0, 0, 5, -4, 0, 0, 0, 0, 2, 30, -18, -8, -13}, + { 0, 0, 0, 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0, 0, 0, 0, 0, 3, -2, 0, 0, 0, 0, 0, 2, 0,-114, -50, 0}, + + /* 541-550 */ + { 0, 0, 0, 0, 0, 0, 3, 0,-1, 0, 0, 0, 2, 0, 0, 0, 23}, + { 0, 0, 0, 0, 0, 0, 3, 0,-1, 0, 0, 0, 2, 517, 16, 7,-224}, + { 0, 0, 0, 0, 0, 0, 3, 0, 0,-2, 0, 0, 2, 0, -7, -3, 0}, + { 0, 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 2, 143, -3, -1, -62}, + { 0, 0, 0, 0, 0, 0, 3, 0, 0,-1, 0, 0, 2, 29, 0, 0, -13}, + { 0, 2,-2, 1, 0, 0, 1, 0,-1, 0, 0, 0, 0, -4, 0, 0, 2}, + { 0, 0, 0, 0, 0, -8, 16, 0, 0, 0, 0, 0, 2, -6, 0, 0, 3}, + { 0, 0, 0, 0, 0, 0, 3, 0, 2,-5, 0, 0, 2, 5, 12, 5, -2}, + { 0, 0, 0, 0, 0, 0, 7, -8, 3, 0, 0, 0, 2, -25, 0, 0, 11}, + { 0, 0, 0, 0, 0, 0, -5, 16,-4,-5, 0, 0, 2, -3, 0, 0, 1}, + + /* 551-560 */ + { 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 2, 0, 4, 2, 0}, + { 0, 0, 0, 0, 0, 0, -1, 8,-3, 0, 0, 0, 2, -22, 12, 5, 10}, + { 0, 0, 0, 0, 0, -8, 10, 0, 0, 0, 0, 0, 2, 50, 0, 0, -22}, + { 0, 0, 0, 0, 0, -8, 10, 0, 0, 0, 0, 0, 1, 0, 7, 4, 0}, + { 0, 0, 0, 0, 0, -8, 10, 0, 0, 0, 0, 0, 2, 0, 3, 1, 0}, + { 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, -4, 4, 2, 2}, + { 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 2, -5, -11, -5, 2}, + { 0, 0, 0, 0, 0, -3, 8, 0, 0, 0, 0, 0, 2, 0, 4, 2, 0}, + { 0, 0, 0, 0, 0, -5, 5, 0, 0, 0, 0, 0, 1, 4, 17, 9, -2}, + { 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0}, + + /* 561-570 */ + { 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 0, 1, 0, -4, -2, 0}, + { 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 0, 2, -8, 0, 0, 4}, + { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 4, -15, -8, -2}, + { 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 370, -8, 0,-160}, + { 0, 0, 0, 0, 0, 0, 7, -7, 0, 0, 0, 0, 2, 0, 0, -3, 0}, + { 0, 0, 0, 0, 0, 0, 7, -7, 0, 0, 0, 0, 2, 0, 3, 1, 0}, + { 0, 0, 0, 0, 0, 0, 6, -5, 0, 0, 0, 0, 2, -6, 3, 1, 3}, + { 0, 0, 0, 0, 0, 7, -8, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0}, + { 0, 0, 0, 0, 0, 0, 5, -3, 0, 0, 0, 0, 2, -10, 0, 0, 4}, + + /* 571-580 */ + { 0, 0, 0, 0, 0, 4, -3, 0, 0, 0, 0, 0, 2, 0, 9, 4, 0}, + { 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 2, 4, 17, 7, -2}, + { 0, 0, 0, 0, 0, -9, 11, 0, 0, 0, 0, 0, 2, 34, 0, 0, -15}, + { 0, 0, 0, 0, 0, -9, 11, 0, 0, 0, 0, 0, 1, 0, 5, 3, 0}, + { 0, 0, 0, 0, 0, 0, 4, 0,-4, 0, 0, 0, 2, -5, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 4, 0,-3, 0, 0, 0, 2, -37, -7, -3, 16}, + { 0, 0, 0, 0, 0, -6, 6, 0, 0, 0, 0, 0, 1, 3, 13, 7, -2}, + { 0, 0, 0, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0}, + { 0, 0, 0, 0, 0, 6, -6, 0, 0, 0, 0, 0, 1, 0, -3, -2, 0}, + { 0, 0, 0, 0, 0, 0, 4, 0,-2, 0, 0, 0, 2, -184, -3, -1, 80}, + + /* 581-590 */ + { 0, 0, 0, 0, 0, 0, 6, -4, 0, 0, 0, 0, 2, -3, 0, 0, 1}, + { 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0}, + { 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 0, 1, 0, -10, -6, -1}, + { 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 0, 2, 31, -6, 0, -13}, + { 0, 0, 0, 0, 0, 0, 4, 0,-1, 0, 0, 0, 2, -3, -32, -14, 1}, + { 0, 0, 0, 0, 0, 0, 4, 0, 0,-2, 0, 0, 2, -7, 0, 0, 3}, + { 0, 0, 0, 0, 0, 0, 5, -2, 0, 0, 0, 0, 2, 0, -8, -4, 0}, + { 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 3, -4, 0, 0}, + { 0, 0, 0, 0, 0, 8, -9, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0}, + { 0, 0, 0, 0, 0, 5, -4, 0, 0, 0, 0, 0, 2, 0, 3, 1, 0}, + + /* 591-600 */ + { 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 2, 19, -23, -10, 2}, + { 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, -10}, + { 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 1, 0, 3, 2, 0}, + { 0, 0, 0, 0, 0, -7, 7, 0, 0, 0, 0, 0, 1, 0, 9, 5, -1}, + { 0, 0, 0, 0, 0, 7, -7, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0}, + { 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 0, 1, 0, -7, -4, 0}, + { 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 0, 2, 8, -4, 0, -4}, + { 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0}, + { 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0}, + { 0, 0, 0, 0, 0, 0, 5, 0,-4, 0, 0, 0, 2, -3, 0, 0, 1}, + + /* 601-610 */ + { 0, 0, 0, 0, 0, 0, 5, 0,-3, 0, 0, 0, 2, -9, 0, 1, 4}, + { 0, 0, 0, 0, 0, 0, 5, 0,-2, 0, 0, 0, 2, 3, 12, 5, -1}, + { 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 17, -3, -1, 0}, + { 0, 0, 0, 0, 0, -8, 8, 0, 0, 0, 0, 0, 1, 0, 7, 4, 0}, + { 0, 0, 0, 0, 0, 8, -8, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0}, + { 0, 0, 0, 0, 0, 5, -3, 0, 0, 0, 0, 0, 1, 0, -5, -3, 0}, + { 0, 0, 0, 0, 0, 5, -3, 0, 0, 0, 0, 0, 2, 14, -3, 0, -1}, + { 0, 0, 0, 0, 0, -9, 9, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0}, + { 0, 0, 0, 0, 0, -9, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, -5}, + { 0, 0, 0, 0, 0, -9, 9, 0, 0, 0, 0, 0, 1, 0, 5, 3, 0}, + + /* 611-620 */ + { 0, 0, 0, 0, 0, 9, -9, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0}, + { 0, 0, 0, 0, 0, 6, -4, 0, 0, 0, 0, 0, 1, 0, -3, -2, 0}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 2, 2, 9, 4, 3}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1, 0, 4, 2, 0}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 2, 6, 0, 0, -3}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1, 0, 3, 1, 0}, + { 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 2, 5, 0, 0, -2}, + + /* 621-630 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0, -1}, + { 1, 0,-2, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, -3, 0, 0, 0}, + { 1, 0,-2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0}, + { 1, 0,-2, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 7, 0, 0, 0}, + { 1, 0,-2, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0}, + {-1, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0}, + {-1, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 6, 0, 0, 0}, + {-1, 0, 2, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, -4, 0, 0}, + { 1, 0,-2, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, -4, 0, 0}, + {-2, 0, 2, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0, 5, 0, 0, 0}, + + /* 631-640 */ + {-1, 0, 0, 0, 0, 0, 2, 0,-3, 0, 0, 0, 0, -3, 0, 0, 0}, + {-1, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 4, 0, 0, 0}, + {-1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0}, + {-1, 0, 2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0}, + { 1,-1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0}, + {-1, 0, 2, 0, 0, 0, 2, 0,-3, 0, 0, 0, 0, 13, 0, 0, 0}, + {-2, 0, 0, 0, 0, 0, 2, 0,-3, 0, 0, 0, 0, 21, 11, 0, 0}, + { 1, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, -5, 0, 0}, + {-1, 1,-1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -5, -2, 0}, + { 1, 1,-1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 5, 3, 0}, + + /* 641-650 */ + {-1, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, -5, 0, 0}, + {-1, 0, 2, 1, 0, 0, 2, 0,-2, 0, 0, 0, 0, -3, 0, 0, 2}, + { 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 20, 10, 0, 0}, + {-1, 0, 2, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, -34, 0, 0, 0}, + {-1, 0, 2, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, -19, 0, 0, 0}, + { 1, 0,-2, 1, 0, 0, -2, 0, 2, 0, 0, 0, 0, 3, 0, 0, -2}, + { 1, 2,-2, 2, 0, -3, 3, 0, 0, 0, 0, 0, 0, -3, 0, 0, 1}, + { 1, 2,-2, 2, 0, 0, -2, 0, 2, 0, 0, 0, 0, -6, 0, 0, 3}, + { 1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0}, + { 1, 0, 0, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 3, 0, 0, 0}, + + /* 651-660 */ + { 0, 0,-2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0}, + { 0, 0,-2, 0, 0, 0, 1, 0,-1, 0, 0, 0, 0, 4, 0, 0, 0}, + { 0, 2, 0, 2, 0, -2, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, -1}, + { 0, 2, 0, 2, 0, 0, -1, 0, 1, 0, 0, 0, 0, 6, 0, 0, -3}, + { 0, 2, 0, 2, 0, -1, 1, 0, 0, 0, 0, 0, 0, -8, 0, 0, 3}, + { 0, 2, 0, 2, 0, -2, 3, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0}, + { 0, 0, 2, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, -3, 0, 0, 0}, + { 0, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -3, -2, 0}, + { 1, 2, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 126, -63, -27, -55}, + {-1, 2, 0, 2, 0, 10, -3, 0, 0, 0, 0, 0, 0, -5, 0, 1, 2}, + + /* 661-670 */ + { 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, -3, 28, 15, 2}, + { 1, 2, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 5, 0, 1, -2}, + { 0, 2, 0, 2, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, 9, 4, 1}, + { 0, 2, 0, 2, 0, 0, -4, 8,-3, 0, 0, 0, 0, 0, 9, 4, -1}, + {-1, 2, 0, 2, 0, 0, -4, 8,-3, 0, 0, 0, 0, -126, -63, -27, 55}, + { 2, 2,-2, 2, 0, 0, -2, 0, 3, 0, 0, 0, 0, 3, 0, 0, -1}, + { 1, 2, 0, 1, 0, 0, -2, 0, 3, 0, 0, 0, 0, 21, -11, -6, -11}, + { 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -4, 0, 0}, + {-1, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, -21, -11, -6, 11}, + {-2, 2, 2, 2, 0, 0, 2, 0,-2, 0, 0, 0, 0, -3, 0, 0, 1}, + + /* 671-680 */ + { 0, 2, 0, 2, 0, 2, -3, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0}, + { 0, 2, 0, 2, 0, 1, -1, 0, 0, 0, 0, 0, 0, 8, 0, 0, -4}, + { 0, 2, 0, 2, 0, 0, 1, 0,-1, 0, 0, 0, 0, -6, 0, 0, 3}, + { 0, 2, 0, 2, 0, 2, -2, 0, 0, 0, 0, 0, 0, -3, 0, 0, 1}, + {-1, 2, 2, 2, 0, 0, -1, 0, 1, 0, 0, 0, 0, 3, 0, 0, -1}, + { 1, 2, 0, 2, 0, -1, 1, 0, 0, 0, 0, 0, 0, -3, 0, 0, 1}, + {-1, 2, 2, 2, 0, 0, 2, 0,-3, 0, 0, 0, 0, -5, 0, 0, 2}, + { 2, 2, 0, 2, 0, 0, 2, 0,-3, 0, 0, 0, 0, 24, -12, -5, -11}, + { 1, 2, 0, 2, 0, 0, -4, 8,-3, 0, 0, 0, 0, 0, 3, 1, 0}, + { 1, 2, 0, 2, 0, 0, 4, -8, 3, 0, 0, 0, 0, 0, 3, 1, 0}, + + /* 681-687 */ + { 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 2, 0}, + { 0, 2, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, -24, -12, -5, 10}, + { 2, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 4, 0, -1, -2}, + {-1, 2, 2, 2, 0, 0, 2, 0,-2, 0, 0, 0, 0, 13, 0, 0, -6}, + {-1, 2, 2, 2, 0, 3, -3, 0, 0, 0, 0, 0, 0, 7, 0, 0, -3}, + { 1, 2, 0, 2, 0, 1, -1, 0, 0, 0, 0, 0, 0, 3, 0, 0, -1}, + { 0, 2, 2, 2, 0, 0, 2, 0,-2, 0, 0, 0, 0, 3, 0, 0, -1} + }; + +/* Number of terms in the planetary nutation model */ + const int NPL = (int) (sizeof xpl / sizeof xpl[0]); + +/* ------------------------------------------------------------------ */ + +/* Interval between fundamental date J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* ------------------- */ +/* LUNI-SOLAR NUTATION */ +/* ------------------- */ + +/* Fundamental (Delaunay) arguments */ + +/* Mean anomaly of the Moon (IERS 2003). */ + el = iauFal03(t); + +/* Mean anomaly of the Sun (MHB2000). */ + elp = fmod(1287104.79305 + + t * (129596581.0481 + + t * (-0.5532 + + t * (0.000136 + + t * (-0.00001149)))), TURNAS) * DAS2R; + +/* Mean longitude of the Moon minus that of the ascending node */ +/* (IERS 2003. */ + f = iauFaf03(t); + +/* Mean elongation of the Moon from the Sun (MHB2000). */ + d = fmod(1072260.70369 + + t * (1602961601.2090 + + t * (-6.3706 + + t * (0.006593 + + t * (-0.00003169)))), TURNAS) * DAS2R; + +/* Mean longitude of the ascending node of the Moon (IERS 2003). */ + om = iauFaom03(t); + +/* Initialize the nutation values. */ + dp = 0.0; + de = 0.0; + +/* Summation of luni-solar nutation series (in reverse order). */ + for (i = NLS-1; i >= 0; i--) { + + /* Argument and functions. */ + arg = fmod((double)xls[i].nl * el + + (double)xls[i].nlp * elp + + (double)xls[i].nf * f + + (double)xls[i].nd * d + + (double)xls[i].nom * om, D2PI); + sarg = sin(arg); + carg = cos(arg); + + /* Term. */ + dp += (xls[i].sp + xls[i].spt * t) * sarg + xls[i].cp * carg; + de += (xls[i].ce + xls[i].cet * t) * carg + xls[i].se * sarg; + } + +/* Convert from 0.1 microarcsec units to radians. */ + dpsils = dp * U2R; + depsls = de * U2R; + +/* ------------------ */ +/* PLANETARY NUTATION */ +/* ------------------ */ + +/* n.b. The MHB2000 code computes the luni-solar and planetary nutation */ +/* in different functions, using slightly different Delaunay */ +/* arguments in the two cases. This behaviour is faithfully */ +/* reproduced here. Use of the IERS 2003 expressions for both */ +/* cases leads to negligible changes, well below */ +/* 0.1 microarcsecond. */ + +/* Mean anomaly of the Moon (MHB2000). */ + al = fmod(2.35555598 + 8328.6914269554 * t, D2PI); + +/* Mean longitude of the Moon minus that of the ascending node */ +/*(MHB2000). */ + af = fmod(1.627905234 + 8433.466158131 * t, D2PI); + +/* Mean elongation of the Moon from the Sun (MHB2000). */ + ad = fmod(5.198466741 + 7771.3771468121 * t, D2PI); + +/* Mean longitude of the ascending node of the Moon (MHB2000). */ + aom = fmod(2.18243920 - 33.757045 * t, D2PI); + +/* General accumulated precession in longitude (IERS 2003). */ + apa = iauFapa03(t); + +/* Planetary longitudes, Mercury through Uranus (IERS 2003). */ + alme = iauFame03(t); + alve = iauFave03(t); + alea = iauFae03(t); + alma = iauFama03(t); + alju = iauFaju03(t); + alsa = iauFasa03(t); + alur = iauFaur03(t); + +/* Neptune longitude (MHB2000). */ + alne = fmod(5.321159000 + 3.8127774000 * t, D2PI); + +/* Initialize the nutation values. */ + dp = 0.0; + de = 0.0; + +/* Summation of planetary nutation series (in reverse order). */ + for (i = NPL-1; i >= 0; i--) { + + /* Argument and functions. */ + arg = fmod((double)xpl[i].nl * al + + (double)xpl[i].nf * af + + (double)xpl[i].nd * ad + + (double)xpl[i].nom * aom + + (double)xpl[i].nme * alme + + (double)xpl[i].nve * alve + + (double)xpl[i].nea * alea + + (double)xpl[i].nma * alma + + (double)xpl[i].nju * alju + + (double)xpl[i].nsa * alsa + + (double)xpl[i].nur * alur + + (double)xpl[i].nne * alne + + (double)xpl[i].npa * apa, D2PI); + sarg = sin(arg); + carg = cos(arg); + + /* Term. */ + dp += (double)xpl[i].sp * sarg + (double)xpl[i].cp * carg; + de += (double)xpl[i].se * sarg + (double)xpl[i].ce * carg; + + } + +/* Convert from 0.1 microarcsec units to radians. */ + dpsipl = dp * U2R; + depspl = de * U2R; + +/* ------- */ +/* RESULTS */ +/* ------- */ + +/* Add luni-solar and planetary components. */ + *dpsi = dpsils + dpsipl; + *deps = depsls + depspl; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/nut00b.c b/src/cpp/3rdparty/sofa/src/nut00b.c new file mode 100644 index 000000000..bbede7095 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/nut00b.c @@ -0,0 +1,423 @@ +#include "sofa.h" +#include "sofam.h" + +void iauNut00b(double date1, double date2, double *dpsi, double *deps) +/* +** - - - - - - - - - - +** i a u N u t 0 0 b +** - - - - - - - - - - +** +** Nutation, IAU 2000B model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsi,deps double nutation, luni-solar + planetary (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The nutation components in longitude and obliquity are in radians +** and with respect to the equinox and ecliptic of date. The +** obliquity at J2000.0 is assumed to be the Lieske et al. (1977) +** value of 84381.448 arcsec. (The errors that result from using +** this function with the IAU 2006 value of 84381.406 arcsec can be +** neglected.) +** +** The nutation model consists only of luni-solar terms, but +** includes also a fixed offset which compensates for certain long- +** period planetary terms (Note 7). +** +** 3) This function is an implementation of the IAU 2000B abridged +** nutation model formally adopted by the IAU General Assembly in +** 2000. The function computes the MHB_2000_SHORT luni-solar +** nutation series (Luzum 2001), but without the associated +** corrections for the precession rate adjustments and the offset +** between the GCRS and J2000.0 mean poles. +** +** 4) The full IAU 2000A (MHB2000) nutation model contains nearly 1400 +** terms. The IAU 2000B model (McCarthy & Luzum 2003) contains only +** 77 terms, plus additional simplifications, yet still delivers +** results of 1 mas accuracy at present epochs. This combination of +** accuracy and size makes the IAU 2000B abridged nutation model +** suitable for most practical applications. +** +** The function delivers a pole accurate to 1 mas from 1900 to 2100 +** (usually better than 1 mas, very occasionally just outside +** 1 mas). The full IAU 2000A model, which is implemented in the +** function iauNut00a (q.v.), delivers considerably greater accuracy +** at current dates; however, to realize this improved accuracy, +** corrections for the essentially unpredictable free-core-nutation +** (FCN) must also be included. +** +** 5) The present function provides classical nutation. The +** MHB_2000_SHORT algorithm, from which it is adapted, deals also +** with (i) the offsets between the GCRS and mean poles and (ii) the +** adjustments in longitude and obliquity due to the changed +** precession rates. These additional functions, namely frame bias +** and precession adjustments, are supported by the SOFA functions +** iauBi00 and iauPr00. +** +** 6) The MHB_2000_SHORT algorithm also provides "total" nutations, +** comprising the arithmetic sum of the frame bias, precession +** adjustments, and nutation (luni-solar + planetary). These total +** nutations can be used in combination with an existing IAU 1976 +** precession implementation, such as iauPmat76, to deliver GCRS- +** to-true predictions of mas accuracy at current epochs. However, +** for symmetry with the iauNut00a function (q.v. for the reasons), +** the SOFA functions do not generate the "total nutations" +** directly. Should they be required, they could of course easily +** be generated by calling iauBi00, iauPr00 and the present function +** and adding the results. +** +** 7) The IAU 2000B model includes "planetary bias" terms that are +** fixed in size but compensate for long-period nutations. The +** amplitudes quoted in McCarthy & Luzum (2003), namely +** Dpsi = -1.5835 mas and Depsilon = +1.6339 mas, are optimized for +** the "total nutations" method described in Note 6. The Luzum +** (2001) values used in this SOFA implementation, namely -0.135 mas +** and +0.388 mas, are optimized for the "rigorous" method, where +** frame bias, precession and nutation are applied separately and in +** that order. During the interval 1995-2050, the SOFA +** implementation delivers a maximum error of 1.001 mas (not +** including FCN). +** +** References: +** +** Lieske, J.H., Lederle, T., Fricke, W., Morando, B., "Expressions +** for the precession quantities based upon the IAU /1976/ system of +** astronomical constants", Astron.Astrophys. 58, 1-2, 1-16. (1977) +** +** Luzum, B., private communication, 2001 (Fortran code +** MHB_2000_SHORT) +** +** McCarthy, D.D. & Luzum, B.J., "An abridged model of the +** precession-nutation of the celestial pole", Cel.Mech.Dyn.Astron. +** 85, 37-49 (2003) +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J., Astron.Astrophys. 282, 663-683 (1994) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, el, elp, f, d, om, arg, dp, de, sarg, carg, + dpsils, depsls, dpsipl, depspl; + int i; + +/* Units of 0.1 microarcsecond to radians */ + static const double U2R = DAS2R / 1e7; + +/* ---------------------------------------- */ +/* Fixed offsets in lieu of planetary terms */ +/* ---------------------------------------- */ + + static const double DPPLAN = -0.135 * DMAS2R; + static const double DEPLAN = 0.388 * DMAS2R; + +/* --------------------------------------------------- */ +/* Luni-solar nutation: argument and term coefficients */ +/* --------------------------------------------------- */ + +/* The units for the sine and cosine coefficients are */ +/* 0.1 microarcsec and the same per Julian century */ + + static const struct { + int nl,nlp,nf,nd,nom; /* coefficients of l,l',F,D,Om */ + double ps,pst,pc; /* longitude sin, t*sin, cos coefficients */ + double ec,ect,es; /* obliquity cos, t*cos, sin coefficients */ + + } x[] = { + + /* 1-10 */ + { 0, 0, 0, 0,1, + -172064161.0, -174666.0, 33386.0, 92052331.0, 9086.0, 15377.0}, + { 0, 0, 2,-2,2, + -13170906.0, -1675.0, -13696.0, 5730336.0, -3015.0, -4587.0}, + { 0, 0, 2, 0,2,-2276413.0,-234.0, 2796.0, 978459.0,-485.0,1374.0}, + { 0, 0, 0, 0,2,2074554.0, 207.0, -698.0,-897492.0, 470.0,-291.0}, + { 0, 1, 0, 0,0,1475877.0,-3633.0,11817.0, 73871.0,-184.0,-1924.0}, + { 0, 1, 2,-2,2,-516821.0, 1226.0, -524.0, 224386.0,-677.0,-174.0}, + { 1, 0, 0, 0,0, 711159.0, 73.0, -872.0, -6750.0, 0.0, 358.0}, + { 0, 0, 2, 0,1,-387298.0, -367.0, 380.0, 200728.0, 18.0, 318.0}, + { 1, 0, 2, 0,2,-301461.0, -36.0, 816.0, 129025.0, -63.0, 367.0}, + { 0,-1, 2,-2,2, 215829.0, -494.0, 111.0, -95929.0, 299.0, 132.0}, + + /* 11-20 */ + { 0, 0, 2,-2,1, 128227.0, 137.0, 181.0, -68982.0, -9.0, 39.0}, + {-1, 0, 2, 0,2, 123457.0, 11.0, 19.0, -53311.0, 32.0, -4.0}, + {-1, 0, 0, 2,0, 156994.0, 10.0, -168.0, -1235.0, 0.0, 82.0}, + { 1, 0, 0, 0,1, 63110.0, 63.0, 27.0, -33228.0, 0.0, -9.0}, + {-1, 0, 0, 0,1, -57976.0, -63.0, -189.0, 31429.0, 0.0, -75.0}, + {-1, 0, 2, 2,2, -59641.0, -11.0, 149.0, 25543.0, -11.0, 66.0}, + { 1, 0, 2, 0,1, -51613.0, -42.0, 129.0, 26366.0, 0.0, 78.0}, + {-2, 0, 2, 0,1, 45893.0, 50.0, 31.0, -24236.0, -10.0, 20.0}, + { 0, 0, 0, 2,0, 63384.0, 11.0, -150.0, -1220.0, 0.0, 29.0}, + { 0, 0, 2, 2,2, -38571.0, -1.0, 158.0, 16452.0, -11.0, 68.0}, + + /* 21-30 */ + { 0,-2, 2,-2,2, 32481.0, 0.0, 0.0, -13870.0, 0.0, 0.0}, + {-2, 0, 0, 2,0, -47722.0, 0.0, -18.0, 477.0, 0.0, -25.0}, + { 2, 0, 2, 0,2, -31046.0, -1.0, 131.0, 13238.0, -11.0, 59.0}, + { 1, 0, 2,-2,2, 28593.0, 0.0, -1.0, -12338.0, 10.0, -3.0}, + {-1, 0, 2, 0,1, 20441.0, 21.0, 10.0, -10758.0, 0.0, -3.0}, + { 2, 0, 0, 0,0, 29243.0, 0.0, -74.0, -609.0, 0.0, 13.0}, + { 0, 0, 2, 0,0, 25887.0, 0.0, -66.0, -550.0, 0.0, 11.0}, + { 0, 1, 0, 0,1, -14053.0, -25.0, 79.0, 8551.0, -2.0, -45.0}, + {-1, 0, 0, 2,1, 15164.0, 10.0, 11.0, -8001.0, 0.0, -1.0}, + { 0, 2, 2,-2,2, -15794.0, 72.0, -16.0, 6850.0, -42.0, -5.0}, + + /* 31-40 */ + { 0, 0,-2, 2,0, 21783.0, 0.0, 13.0, -167.0, 0.0, 13.0}, + { 1, 0, 0,-2,1, -12873.0, -10.0, -37.0, 6953.0, 0.0, -14.0}, + { 0,-1, 0, 0,1, -12654.0, 11.0, 63.0, 6415.0, 0.0, 26.0}, + {-1, 0, 2, 2,1, -10204.0, 0.0, 25.0, 5222.0, 0.0, 15.0}, + { 0, 2, 0, 0,0, 16707.0, -85.0, -10.0, 168.0, -1.0, 10.0}, + { 1, 0, 2, 2,2, -7691.0, 0.0, 44.0, 3268.0, 0.0, 19.0}, + {-2, 0, 2, 0,0, -11024.0, 0.0, -14.0, 104.0, 0.0, 2.0}, + { 0, 1, 2, 0,2, 7566.0, -21.0, -11.0, -3250.0, 0.0, -5.0}, + { 0, 0, 2, 2,1, -6637.0, -11.0, 25.0, 3353.0, 0.0, 14.0}, + { 0,-1, 2, 0,2, -7141.0, 21.0, 8.0, 3070.0, 0.0, 4.0}, + + /* 41-50 */ + { 0, 0, 0, 2,1, -6302.0, -11.0, 2.0, 3272.0, 0.0, 4.0}, + { 1, 0, 2,-2,1, 5800.0, 10.0, 2.0, -3045.0, 0.0, -1.0}, + { 2, 0, 2,-2,2, 6443.0, 0.0, -7.0, -2768.0, 0.0, -4.0}, + {-2, 0, 0, 2,1, -5774.0, -11.0, -15.0, 3041.0, 0.0, -5.0}, + { 2, 0, 2, 0,1, -5350.0, 0.0, 21.0, 2695.0, 0.0, 12.0}, + { 0,-1, 2,-2,1, -4752.0, -11.0, -3.0, 2719.0, 0.0, -3.0}, + { 0, 0, 0,-2,1, -4940.0, -11.0, -21.0, 2720.0, 0.0, -9.0}, + {-1,-1, 0, 2,0, 7350.0, 0.0, -8.0, -51.0, 0.0, 4.0}, + { 2, 0, 0,-2,1, 4065.0, 0.0, 6.0, -2206.0, 0.0, 1.0}, + { 1, 0, 0, 2,0, 6579.0, 0.0, -24.0, -199.0, 0.0, 2.0}, + + /* 51-60 */ + { 0, 1, 2,-2,1, 3579.0, 0.0, 5.0, -1900.0, 0.0, 1.0}, + { 1,-1, 0, 0,0, 4725.0, 0.0, -6.0, -41.0, 0.0, 3.0}, + {-2, 0, 2, 0,2, -3075.0, 0.0, -2.0, 1313.0, 0.0, -1.0}, + { 3, 0, 2, 0,2, -2904.0, 0.0, 15.0, 1233.0, 0.0, 7.0}, + { 0,-1, 0, 2,0, 4348.0, 0.0, -10.0, -81.0, 0.0, 2.0}, + { 1,-1, 2, 0,2, -2878.0, 0.0, 8.0, 1232.0, 0.0, 4.0}, + { 0, 0, 0, 1,0, -4230.0, 0.0, 5.0, -20.0, 0.0, -2.0}, + {-1,-1, 2, 2,2, -2819.0, 0.0, 7.0, 1207.0, 0.0, 3.0}, + {-1, 0, 2, 0,0, -4056.0, 0.0, 5.0, 40.0, 0.0, -2.0}, + { 0,-1, 2, 2,2, -2647.0, 0.0, 11.0, 1129.0, 0.0, 5.0}, + + /* 61-70 */ + {-2, 0, 0, 0,1, -2294.0, 0.0, -10.0, 1266.0, 0.0, -4.0}, + { 1, 1, 2, 0,2, 2481.0, 0.0, -7.0, -1062.0, 0.0, -3.0}, + { 2, 0, 0, 0,1, 2179.0, 0.0, -2.0, -1129.0, 0.0, -2.0}, + {-1, 1, 0, 1,0, 3276.0, 0.0, 1.0, -9.0, 0.0, 0.0}, + { 1, 1, 0, 0,0, -3389.0, 0.0, 5.0, 35.0, 0.0, -2.0}, + { 1, 0, 2, 0,0, 3339.0, 0.0, -13.0, -107.0, 0.0, 1.0}, + {-1, 0, 2,-2,1, -1987.0, 0.0, -6.0, 1073.0, 0.0, -2.0}, + { 1, 0, 0, 0,2, -1981.0, 0.0, 0.0, 854.0, 0.0, 0.0}, + {-1, 0, 0, 1,0, 4026.0, 0.0, -353.0, -553.0, 0.0,-139.0}, + { 0, 0, 2, 1,2, 1660.0, 0.0, -5.0, -710.0, 0.0, -2.0}, + + /* 71-77 */ + {-1, 0, 2, 4,2, -1521.0, 0.0, 9.0, 647.0, 0.0, 4.0}, + {-1, 1, 0, 1,1, 1314.0, 0.0, 0.0, -700.0, 0.0, 0.0}, + { 0,-2, 2,-2,1, -1283.0, 0.0, 0.0, 672.0, 0.0, 0.0}, + { 1, 0, 2, 2,1, -1331.0, 0.0, 8.0, 663.0, 0.0, 4.0}, + {-2, 0, 2, 2,2, 1383.0, 0.0, -2.0, -594.0, 0.0, -2.0}, + {-1, 0, 0, 0,2, 1405.0, 0.0, 4.0, -610.0, 0.0, 2.0}, + { 1, 1, 2,-2,2, 1290.0, 0.0, 0.0, -556.0, 0.0, 0.0} + }; + +/* Number of terms in the series */ + const int NLS = (int) (sizeof x / sizeof x[0]); + +/* ------------------------------------------------------------------ */ + +/* Interval between fundamental epoch J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* --------------------*/ +/* LUNI-SOLAR NUTATION */ +/* --------------------*/ + +/* Fundamental (Delaunay) arguments from Simon et al. (1994) */ + +/* Mean anomaly of the Moon. */ + el = fmod(485868.249036 + (1717915923.2178) * t, TURNAS) * DAS2R; + +/* Mean anomaly of the Sun. */ + elp = fmod(1287104.79305 + (129596581.0481) * t, TURNAS) * DAS2R; + +/* Mean argument of the latitude of the Moon. */ + f = fmod(335779.526232 + (1739527262.8478) * t, TURNAS) * DAS2R; + +/* Mean elongation of the Moon from the Sun. */ + d = fmod(1072260.70369 + (1602961601.2090) * t, TURNAS) * DAS2R; + +/* Mean longitude of the ascending node of the Moon. */ + om = fmod(450160.398036 + (-6962890.5431) * t, TURNAS) * DAS2R; + +/* Initialize the nutation values. */ + dp = 0.0; + de = 0.0; + +/* Summation of luni-solar nutation series (smallest terms first). */ + for (i = NLS-1; i >= 0; i--) { + + /* Argument and functions. */ + arg = fmod( (double)x[i].nl * el + + (double)x[i].nlp * elp + + (double)x[i].nf * f + + (double)x[i].nd * d + + (double)x[i].nom * om, D2PI ); + sarg = sin(arg); + carg = cos(arg); + + /* Term. */ + dp += (x[i].ps + x[i].pst * t) * sarg + x[i].pc * carg; + de += (x[i].ec + x[i].ect * t) * carg + x[i].es * sarg; + } + +/* Convert from 0.1 microarcsec units to radians. */ + dpsils = dp * U2R; + depsls = de * U2R; + +/* ------------------------------*/ +/* IN LIEU OF PLANETARY NUTATION */ +/* ------------------------------*/ + +/* Fixed offset to correct for missing terms in truncated series. */ + dpsipl = DPPLAN; + depspl = DEPLAN; + +/* --------*/ +/* RESULTS */ +/* --------*/ + +/* Add luni-solar and planetary components. */ + *dpsi = dpsils + dpsipl; + *deps = depsls + depspl; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/nut06a.c b/src/cpp/3rdparty/sofa/src/nut06a.c new file mode 100644 index 000000000..2afe62dd7 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/nut06a.c @@ -0,0 +1,201 @@ +#include "sofa.h" +#include "sofam.h" + +void iauNut06a(double date1, double date2, double *dpsi, double *deps) +/* +** - - - - - - - - - - +** i a u N u t 0 6 a +** - - - - - - - - - - +** +** IAU 2000A nutation with adjustments to match the IAU 2006 +** precession. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsi,deps double nutation, luni-solar + planetary (Note 2) +** +** Status: canonical model. +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The nutation components in longitude and obliquity are in radians +** and with respect to the mean equinox and ecliptic of date, +** IAU 2006 precession model (Hilton et al. 2006, Capitaine et al. +** 2005). +** +** 3) The function first computes the IAU 2000A nutation, then applies +** adjustments for (i) the consequences of the change in obliquity +** from the IAU 1980 ecliptic to the IAU 2006 ecliptic and (ii) the +** secular variation in the Earth's dynamical form factor J2. +** +** 4) The present function provides classical nutation, complementing +** the IAU 2000 frame bias and IAU 2006 precession. It delivers a +** pole which is at current epochs accurate to a few tens of +** microarcseconds, apart from the free core nutation. +** +** Called: +** iauNut00a nutation, IAU 2000A +** +** References: +** +** Chapront, J., Chapront-Touze, M. & Francou, G. 2002, +** Astron.Astrophys. 387, 700 +** +** Lieske, J.H., Lederle, T., Fricke, W. & Morando, B. 1977, +** Astron.Astrophys. 58, 1-16 +** +** Mathews, P.M., Herring, T.A., Buffet, B.A. 2002, J.Geophys.Res. +** 107, B4. The MHB_2000 code itself was obtained on 9th September +** 2002 from ftp//maia.usno.navy.mil/conv2000/chapter5/IAU2000A. +** +** Simon, J.-L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G., Laskar, J. 1994, Astron.Astrophys. 282, 663-683 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M. 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** Wallace, P.T., "Software for Implementing the IAU 2000 +** Resolutions", in IERS Workshop 5.1 (2002) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, fj2, dp, de; + + +/* Interval between fundamental date J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Factor correcting for secular variation of J2. */ + fj2 = -2.7774e-6 * t; + +/* Obtain IAU 2000A nutation. */ + iauNut00a(date1, date2, &dp, &de); + +/* Apply P03 adjustments (Wallace & Capitaine, 2006, Eqs.5). */ + *dpsi = dp + dp * (0.4697e-6 + fj2); + *deps = de + de * fj2; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/nut80.c b/src/cpp/3rdparty/sofa/src/nut80.c new file mode 100644 index 000000000..61a79e5c9 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/nut80.c @@ -0,0 +1,376 @@ +#include "sofa.h" +#include "sofam.h" + +void iauNut80(double date1, double date2, double *dpsi, double *deps) +/* +** - - - - - - - - - +** i a u N u t 8 0 +** - - - - - - - - - +** +** Nutation, IAU 1980 model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsi double nutation in longitude (radians) +** deps double nutation in obliquity (radians) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The nutation components are with respect to the ecliptic of +** date. +** +** Called: +** iauAnpm normalize angle into range +/- pi +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 3.222 (p111). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, el, elp, f, d, om, dp, de, arg, s, c; + int j; + +/* Units of 0.1 milliarcsecond to radians */ + const double U2R = DAS2R / 1e4; + +/* ------------------------------------------------ */ +/* Table of multiples of arguments and coefficients */ +/* ------------------------------------------------ */ + +/* The units for the sine and cosine coefficients are 0.1 mas and */ +/* the same per Julian century */ + + static const struct { + int nl,nlp,nf,nd,nom; /* coefficients of l,l',F,D,Om */ + double sp,spt; /* longitude sine, 1 and t coefficients */ + double ce,cet; /* obliquity cosine, 1 and t coefficients */ + } x[] = { + + /* 1-10 */ + { 0, 0, 0, 0, 1, -171996.0, -174.2, 92025.0, 8.9 }, + { 0, 0, 0, 0, 2, 2062.0, 0.2, -895.0, 0.5 }, + { -2, 0, 2, 0, 1, 46.0, 0.0, -24.0, 0.0 }, + { 2, 0, -2, 0, 0, 11.0, 0.0, 0.0, 0.0 }, + { -2, 0, 2, 0, 2, -3.0, 0.0, 1.0, 0.0 }, + { 1, -1, 0, -1, 0, -3.0, 0.0, 0.0, 0.0 }, + { 0, -2, 2, -2, 1, -2.0, 0.0, 1.0, 0.0 }, + { 2, 0, -2, 0, 1, 1.0, 0.0, 0.0, 0.0 }, + { 0, 0, 2, -2, 2, -13187.0, -1.6, 5736.0, -3.1 }, + { 0, 1, 0, 0, 0, 1426.0, -3.4, 54.0, -0.1 }, + + /* 11-20 */ + { 0, 1, 2, -2, 2, -517.0, 1.2, 224.0, -0.6 }, + { 0, -1, 2, -2, 2, 217.0, -0.5, -95.0, 0.3 }, + { 0, 0, 2, -2, 1, 129.0, 0.1, -70.0, 0.0 }, + { 2, 0, 0, -2, 0, 48.0, 0.0, 1.0, 0.0 }, + { 0, 0, 2, -2, 0, -22.0, 0.0, 0.0, 0.0 }, + { 0, 2, 0, 0, 0, 17.0, -0.1, 0.0, 0.0 }, + { 0, 1, 0, 0, 1, -15.0, 0.0, 9.0, 0.0 }, + { 0, 2, 2, -2, 2, -16.0, 0.1, 7.0, 0.0 }, + { 0, -1, 0, 0, 1, -12.0, 0.0, 6.0, 0.0 }, + { -2, 0, 0, 2, 1, -6.0, 0.0, 3.0, 0.0 }, + + /* 21-30 */ + { 0, -1, 2, -2, 1, -5.0, 0.0, 3.0, 0.0 }, + { 2, 0, 0, -2, 1, 4.0, 0.0, -2.0, 0.0 }, + { 0, 1, 2, -2, 1, 4.0, 0.0, -2.0, 0.0 }, + { 1, 0, 0, -1, 0, -4.0, 0.0, 0.0, 0.0 }, + { 2, 1, 0, -2, 0, 1.0, 0.0, 0.0, 0.0 }, + { 0, 0, -2, 2, 1, 1.0, 0.0, 0.0, 0.0 }, + { 0, 1, -2, 2, 0, -1.0, 0.0, 0.0, 0.0 }, + { 0, 1, 0, 0, 2, 1.0, 0.0, 0.0, 0.0 }, + { -1, 0, 0, 1, 1, 1.0, 0.0, 0.0, 0.0 }, + { 0, 1, 2, -2, 0, -1.0, 0.0, 0.0, 0.0 }, + + /* 31-40 */ + { 0, 0, 2, 0, 2, -2274.0, -0.2, 977.0, -0.5 }, + { 1, 0, 0, 0, 0, 712.0, 0.1, -7.0, 0.0 }, + { 0, 0, 2, 0, 1, -386.0, -0.4, 200.0, 0.0 }, + { 1, 0, 2, 0, 2, -301.0, 0.0, 129.0, -0.1 }, + { 1, 0, 0, -2, 0, -158.0, 0.0, -1.0, 0.0 }, + { -1, 0, 2, 0, 2, 123.0, 0.0, -53.0, 0.0 }, + { 0, 0, 0, 2, 0, 63.0, 0.0, -2.0, 0.0 }, + { 1, 0, 0, 0, 1, 63.0, 0.1, -33.0, 0.0 }, + { -1, 0, 0, 0, 1, -58.0, -0.1, 32.0, 0.0 }, + { -1, 0, 2, 2, 2, -59.0, 0.0, 26.0, 0.0 }, + + /* 41-50 */ + { 1, 0, 2, 0, 1, -51.0, 0.0, 27.0, 0.0 }, + { 0, 0, 2, 2, 2, -38.0, 0.0, 16.0, 0.0 }, + { 2, 0, 0, 0, 0, 29.0, 0.0, -1.0, 0.0 }, + { 1, 0, 2, -2, 2, 29.0, 0.0, -12.0, 0.0 }, + { 2, 0, 2, 0, 2, -31.0, 0.0, 13.0, 0.0 }, + { 0, 0, 2, 0, 0, 26.0, 0.0, -1.0, 0.0 }, + { -1, 0, 2, 0, 1, 21.0, 0.0, -10.0, 0.0 }, + { -1, 0, 0, 2, 1, 16.0, 0.0, -8.0, 0.0 }, + { 1, 0, 0, -2, 1, -13.0, 0.0, 7.0, 0.0 }, + { -1, 0, 2, 2, 1, -10.0, 0.0, 5.0, 0.0 }, + + /* 51-60 */ + { 1, 1, 0, -2, 0, -7.0, 0.0, 0.0, 0.0 }, + { 0, 1, 2, 0, 2, 7.0, 0.0, -3.0, 0.0 }, + { 0, -1, 2, 0, 2, -7.0, 0.0, 3.0, 0.0 }, + { 1, 0, 2, 2, 2, -8.0, 0.0, 3.0, 0.0 }, + { 1, 0, 0, 2, 0, 6.0, 0.0, 0.0, 0.0 }, + { 2, 0, 2, -2, 2, 6.0, 0.0, -3.0, 0.0 }, + { 0, 0, 0, 2, 1, -6.0, 0.0, 3.0, 0.0 }, + { 0, 0, 2, 2, 1, -7.0, 0.0, 3.0, 0.0 }, + { 1, 0, 2, -2, 1, 6.0, 0.0, -3.0, 0.0 }, + { 0, 0, 0, -2, 1, -5.0, 0.0, 3.0, 0.0 }, + + /* 61-70 */ + { 1, -1, 0, 0, 0, 5.0, 0.0, 0.0, 0.0 }, + { 2, 0, 2, 0, 1, -5.0, 0.0, 3.0, 0.0 }, + { 0, 1, 0, -2, 0, -4.0, 0.0, 0.0, 0.0 }, + { 1, 0, -2, 0, 0, 4.0, 0.0, 0.0, 0.0 }, + { 0, 0, 0, 1, 0, -4.0, 0.0, 0.0, 0.0 }, + { 1, 1, 0, 0, 0, -3.0, 0.0, 0.0, 0.0 }, + { 1, 0, 2, 0, 0, 3.0, 0.0, 0.0, 0.0 }, + { 1, -1, 2, 0, 2, -3.0, 0.0, 1.0, 0.0 }, + { -1, -1, 2, 2, 2, -3.0, 0.0, 1.0, 0.0 }, + { -2, 0, 0, 0, 1, -2.0, 0.0, 1.0, 0.0 }, + + /* 71-80 */ + { 3, 0, 2, 0, 2, -3.0, 0.0, 1.0, 0.0 }, + { 0, -1, 2, 2, 2, -3.0, 0.0, 1.0, 0.0 }, + { 1, 1, 2, 0, 2, 2.0, 0.0, -1.0, 0.0 }, + { -1, 0, 2, -2, 1, -2.0, 0.0, 1.0, 0.0 }, + { 2, 0, 0, 0, 1, 2.0, 0.0, -1.0, 0.0 }, + { 1, 0, 0, 0, 2, -2.0, 0.0, 1.0, 0.0 }, + { 3, 0, 0, 0, 0, 2.0, 0.0, 0.0, 0.0 }, + { 0, 0, 2, 1, 2, 2.0, 0.0, -1.0, 0.0 }, + { -1, 0, 0, 0, 2, 1.0, 0.0, -1.0, 0.0 }, + { 1, 0, 0, -4, 0, -1.0, 0.0, 0.0, 0.0 }, + + /* 81-90 */ + { -2, 0, 2, 2, 2, 1.0, 0.0, -1.0, 0.0 }, + { -1, 0, 2, 4, 2, -2.0, 0.0, 1.0, 0.0 }, + { 2, 0, 0, -4, 0, -1.0, 0.0, 0.0, 0.0 }, + { 1, 1, 2, -2, 2, 1.0, 0.0, -1.0, 0.0 }, + { 1, 0, 2, 2, 1, -1.0, 0.0, 1.0, 0.0 }, + { -2, 0, 2, 4, 2, -1.0, 0.0, 1.0, 0.0 }, + { -1, 0, 4, 0, 2, 1.0, 0.0, 0.0, 0.0 }, + { 1, -1, 0, -2, 0, 1.0, 0.0, 0.0, 0.0 }, + { 2, 0, 2, -2, 1, 1.0, 0.0, -1.0, 0.0 }, + { 2, 0, 2, 2, 2, -1.0, 0.0, 0.0, 0.0 }, + + /* 91-100 */ + { 1, 0, 0, 2, 1, -1.0, 0.0, 0.0, 0.0 }, + { 0, 0, 4, -2, 2, 1.0, 0.0, 0.0, 0.0 }, + { 3, 0, 2, -2, 2, 1.0, 0.0, 0.0, 0.0 }, + { 1, 0, 2, -2, 0, -1.0, 0.0, 0.0, 0.0 }, + { 0, 1, 2, 0, 1, 1.0, 0.0, 0.0, 0.0 }, + { -1, -1, 0, 2, 1, 1.0, 0.0, 0.0, 0.0 }, + { 0, 0, -2, 0, 1, -1.0, 0.0, 0.0, 0.0 }, + { 0, 0, 2, -1, 2, -1.0, 0.0, 0.0, 0.0 }, + { 0, 1, 0, 2, 0, -1.0, 0.0, 0.0, 0.0 }, + { 1, 0, -2, -2, 0, -1.0, 0.0, 0.0, 0.0 }, + + /* 101-106 */ + { 0, -1, 2, 0, 1, -1.0, 0.0, 0.0, 0.0 }, + { 1, 1, 0, -2, 1, -1.0, 0.0, 0.0, 0.0 }, + { 1, 0, -2, 2, 0, -1.0, 0.0, 0.0, 0.0 }, + { 2, 0, 0, 2, 0, 1.0, 0.0, 0.0, 0.0 }, + { 0, 0, 2, 4, 2, -1.0, 0.0, 0.0, 0.0 }, + { 0, 1, 0, 1, 0, 1.0, 0.0, 0.0, 0.0 } + }; + +/* Number of terms in the series */ + const int NT = (int) (sizeof x / sizeof x[0]); + +/* ------------------------------------------------------------------ */ + +/* Interval between fundamental epoch J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* --------------------- */ +/* Fundamental arguments */ +/* --------------------- */ + +/* Mean longitude of Moon minus mean longitude of Moon's perigee. */ + el = iauAnpm( + (485866.733 + (715922.633 + (31.310 + 0.064 * t) * t) * t) + * DAS2R + fmod(1325.0 * t, 1.0) * D2PI); + +/* Mean longitude of Sun minus mean longitude of Sun's perigee. */ + elp = iauAnpm( + (1287099.804 + (1292581.224 + (-0.577 - 0.012 * t) * t) * t) + * DAS2R + fmod(99.0 * t, 1.0) * D2PI); + +/* Mean longitude of Moon minus mean longitude of Moon's node. */ + f = iauAnpm( + (335778.877 + (295263.137 + (-13.257 + 0.011 * t) * t) * t) + * DAS2R + fmod(1342.0 * t, 1.0) * D2PI); + +/* Mean elongation of Moon from Sun. */ + d = iauAnpm( + (1072261.307 + (1105601.328 + (-6.891 + 0.019 * t) * t) * t) + * DAS2R + fmod(1236.0 * t, 1.0) * D2PI); + +/* Longitude of the mean ascending node of the lunar orbit on the */ +/* ecliptic, measured from the mean equinox of date. */ + om = iauAnpm( + (450160.280 + (-482890.539 + (7.455 + 0.008 * t) * t) * t) + * DAS2R + fmod(-5.0 * t, 1.0) * D2PI); + +/* --------------- */ +/* Nutation series */ +/* --------------- */ + +/* Initialize nutation components. */ + dp = 0.0; + de = 0.0; + +/* Sum the nutation terms, ending with the biggest. */ + for (j = NT-1; j >= 0; j--) { + + /* Form argument for current term. */ + arg = (double)x[j].nl * el + + (double)x[j].nlp * elp + + (double)x[j].nf * f + + (double)x[j].nd * d + + (double)x[j].nom * om; + + /* Accumulate current nutation term. */ + s = x[j].sp + x[j].spt * t; + c = x[j].ce + x[j].cet * t; + if (s != 0.0) dp += s * sin(arg); + if (c != 0.0) de += c * cos(arg); + } + +/* Convert results from 0.1 mas units to radians. */ + *dpsi = dp * U2R; + *deps = de * U2R; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/nutm80.c b/src/cpp/3rdparty/sofa/src/nutm80.c new file mode 100644 index 000000000..57bf3255c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/nutm80.c @@ -0,0 +1,167 @@ +#include "sofa.h" + +void iauNutm80(double date1, double date2, double rmatn[3][3]) +/* +** - - - - - - - - - - +** i a u N u t m 8 0 +** - - - - - - - - - - +** +** Form the matrix of nutation for a given date, IAU 1980 model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TDB date (Note 1) +** +** Returned: +** rmatn double[3][3] nutation matrix +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(true) = rmatn * V(mean), +** where the p-vector V(true) is with respect to the true +** equatorial triad of date and the p-vector V(mean) is with +** respect to the mean equatorial triad of date. +** +** Called: +** iauNut80 nutation, IAU 1980 +** iauObl80 mean obliquity, IAU 1980 +** iauNumat form nutation matrix +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsi, deps, epsa; + + +/* Nutation components and mean obliquity. */ + iauNut80(date1, date2, &dpsi, &deps); + epsa = iauObl80(date1, date2); + +/* Build the rotation matrix. */ + iauNumat(epsa, dpsi, deps, rmatn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/obl06.c b/src/cpp/3rdparty/sofa/src/obl06.c new file mode 100644 index 000000000..6da700d04 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/obl06.c @@ -0,0 +1,171 @@ +#include "sofa.h" +#include "sofam.h" + +double iauObl06(double date1, double date2) +/* +** - - - - - - - - - +** i a u O b l 0 6 +** - - - - - - - - - +** +** Mean obliquity of the ecliptic, IAU 2006 precession model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double obliquity of the ecliptic (radians, Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The result is the angle between the ecliptic and mean equator of +** date date1+date2. +** +** Reference: +** +** Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, eps0; + + +/* Interval between fundamental date J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Mean obliquity. */ + eps0 = (84381.406 + + (-46.836769 + + ( -0.0001831 + + ( 0.00200340 + + ( -0.000000576 + + ( -0.0000000434) * t) * t) * t) * t) * t) * DAS2R; + + return eps0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/obl80.c b/src/cpp/3rdparty/sofa/src/obl80.c new file mode 100644 index 000000000..4afefcf1c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/obl80.c @@ -0,0 +1,171 @@ +#include "sofa.h" +#include "sofam.h" + +double iauObl80(double date1, double date2) +/* +** - - - - - - - - - +** i a u O b l 8 0 +** - - - - - - - - - +** +** Mean obliquity of the ecliptic, IAU 1980 model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double obliquity of the ecliptic (radians, Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The result is the angle between the ecliptic and mean equator of +** date date1+date2. +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Expression 3.222-1 (p114). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, eps0; + + +/* Interval between fundamental epoch J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Mean obliquity of date. */ + eps0 = DAS2R * (84381.448 + + (-46.8150 + + (-0.00059 + + ( 0.001813) * t) * t) * t); + + return eps0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/p06e.c b/src/cpp/3rdparty/sofa/src/p06e.c new file mode 100644 index 000000000..134906751 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/p06e.c @@ -0,0 +1,379 @@ +#include "sofa.h" +#include "sofam.h" + +void iauP06e(double date1, double date2, + double *eps0, double *psia, double *oma, double *bpa, + double *bqa, double *pia, double *bpia, + double *epsa, double *chia, double *za, double *zetaa, + double *thetaa, double *pa, + double *gam, double *phi, double *psi) +/* +** - - - - - - - - +** i a u P 0 6 e +** - - - - - - - - +** +** Precession angles, IAU 2006, equinox based. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical models. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (see Note 2): +** eps0 double epsilon_0 +** psia double psi_A +** oma double omega_A +** bpa double P_A +** bqa double Q_A +** pia double pi_A +** bpia double Pi_A +** epsa double obliquity epsilon_A +** chia double chi_A +** za double z_A +** zetaa double zeta_A +** thetaa double theta_A +** pa double p_A +** gam double F-W angle gamma_J2000 +** phi double F-W angle phi_J2000 +** psi double F-W angle psi_J2000 +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) This function returns the set of equinox based angles for the +** Capitaine et al. "P03" precession theory, adopted by the IAU in +** 2006. The angles are set out in Table 1 of Hilton et al. (2006): +** +** eps0 epsilon_0 obliquity at J2000.0 +** psia psi_A luni-solar precession +** oma omega_A inclination of equator wrt J2000.0 ecliptic +** bpa P_A ecliptic pole x, J2000.0 ecliptic triad +** bqa Q_A ecliptic pole -y, J2000.0 ecliptic triad +** pia pi_A angle between moving and J2000.0 ecliptics +** bpia Pi_A longitude of ascending node of the ecliptic +** epsa epsilon_A obliquity of the ecliptic +** chia chi_A planetary precession +** za z_A equatorial precession: -3rd 323 Euler angle +** zetaa zeta_A equatorial precession: -1st 323 Euler angle +** thetaa theta_A equatorial precession: 2nd 323 Euler angle +** pa p_A general precession (n.b. see below) +** gam gamma_J2000 J2000.0 RA difference of ecliptic poles +** phi phi_J2000 J2000.0 codeclination of ecliptic pole +** psi psi_J2000 longitude difference of equator poles, J2000.0 +** +** The returned values are all radians. +** +** Note that the t^5 coefficient in the series for p_A from +** Capitaine et al. (2003) is incorrectly signed in Hilton et al. +** (2006). +** +** 3) Hilton et al. (2006) Table 1 also contains angles that depend on +** models distinct from the P03 precession theory itself, namely the +** IAU 2000A frame bias and nutation. The quoted polynomials are +** used in other SOFA functions: +** +** . iauXy06 contains the polynomial parts of the X and Y series. +** +** . iauS06 contains the polynomial part of the s+XY/2 series. +** +** . iauPfw06 implements the series for the Fukushima-Williams +** angles that are with respect to the GCRS pole (i.e. the variants +** that include frame bias). +** +** 4) The IAU resolution stipulated that the choice of parameterization +** was left to the user, and so an IAU compliant precession +** implementation can be constructed using various combinations of +** the angles returned by the present function. +** +** 5) The parameterization used by SOFA is the version of the Fukushima- +** Williams angles that refers directly to the GCRS pole. These +** angles may be calculated by calling the function iauPfw06. SOFA +** also supports the direct computation of the CIP GCRS X,Y by +** series, available by calling iauXy06. +** +** 6) The agreement between the different parameterizations is at the +** 1 microarcsecond level in the present era. +** +** 7) When constructing a precession formulation that refers to the GCRS +** pole rather than the dynamical pole, it may (depending on the +** choice of angles) be necessary to introduce the frame bias +** explicitly. +** +** 8) It is permissible to re-use the same variable in the returned +** arguments. The quantities are stored in the stated order. +** +** References: +** +** Capitaine, N., Wallace, P.T. & Chapront, J., 2003, +** Astron.Astrophys., 412, 567 +** +** Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351 +** +** Called: +** iauObl06 mean obliquity, IAU 2006 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t; + + +/* Interval between fundamental date J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Obliquity at J2000.0. */ + + *eps0 = 84381.406 * DAS2R; + +/* Luni-solar precession. */ + + *psia = ( 5038.481507 + + ( -1.0790069 + + ( -0.00114045 + + ( 0.000132851 + + ( -0.0000000951 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Inclination of mean equator with respect to the J2000.0 ecliptic. */ + + *oma = *eps0 + ( -0.025754 + + ( 0.0512623 + + ( -0.00772503 + + ( -0.000000467 + + ( 0.0000003337 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Ecliptic pole x, J2000.0 ecliptic triad. */ + + *bpa = ( 4.199094 + + ( 0.1939873 + + ( -0.00022466 + + ( -0.000000912 + + ( 0.0000000120 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Ecliptic pole -y, J2000.0 ecliptic triad. */ + + *bqa = ( -46.811015 + + ( 0.0510283 + + ( 0.00052413 + + ( -0.000000646 + + ( -0.0000000172 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Angle between moving and J2000.0 ecliptics. */ + + *pia = ( 46.998973 + + ( -0.0334926 + + ( -0.00012559 + + ( 0.000000113 + + ( -0.0000000022 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Longitude of ascending node of the moving ecliptic. */ + + *bpia = ( 629546.7936 + + ( -867.95758 + + ( 0.157992 + + ( -0.0005371 + + ( -0.00004797 + + ( 0.000000072 ) + * t) * t) * t) * t) * t) * DAS2R; + +/* Mean obliquity of the ecliptic. */ + + *epsa = iauObl06(date1, date2); + +/* Planetary precession. */ + + *chia = ( 10.556403 + + ( -2.3814292 + + ( -0.00121197 + + ( 0.000170663 + + ( -0.0000000560 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Equatorial precession: minus the third of the 323 Euler angles. */ + + *za = ( -2.650545 + + ( 2306.077181 + + ( 1.0927348 + + ( 0.01826837 + + ( -0.000028596 + + ( -0.0000002904 ) + * t) * t) * t) * t) * t) * DAS2R; + +/* Equatorial precession: minus the first of the 323 Euler angles. */ + + *zetaa = ( 2.650545 + + ( 2306.083227 + + ( 0.2988499 + + ( 0.01801828 + + ( -0.000005971 + + ( -0.0000003173 ) + * t) * t) * t) * t) * t) * DAS2R; + +/* Equatorial precession: second of the 323 Euler angles. */ + + *thetaa = ( 2004.191903 + + ( -0.4294934 + + ( -0.04182264 + + ( -0.000007089 + + ( -0.0000001274 ) + * t) * t) * t) * t) * t * DAS2R; + +/* General precession. */ + + *pa = ( 5028.796195 + + ( 1.1054348 + + ( 0.00007964 + + ( -0.000023857 + + ( -0.0000000383 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Fukushima-Williams angles for precession. */ + + *gam = ( 10.556403 + + ( 0.4932044 + + ( -0.00031238 + + ( -0.000002788 + + ( 0.0000000260 ) + * t) * t) * t) * t) * t * DAS2R; + + *phi = *eps0 + ( -46.811015 + + ( 0.0511269 + + ( 0.00053289 + + ( -0.000000440 + + ( -0.0000000176 ) + * t) * t) * t) * t) * t * DAS2R; + + *psi = ( 5038.481507 + + ( 1.5584176 + + ( -0.00018522 + + ( -0.000026452 + + ( -0.0000000148 ) + * t) * t) * t) * t) * t * DAS2R; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/p2pv.c b/src/cpp/3rdparty/sofa/src/p2pv.c new file mode 100644 index 000000000..8703def0c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/p2pv.c @@ -0,0 +1,133 @@ +#include "sofa.h" + +void iauP2pv(double p[3], double pv[2][3]) +/* +** - - - - - - - - +** i a u P 2 p v +** - - - - - - - - +** +** Extend a p-vector to a pv-vector by appending a zero velocity. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** p double[3] p-vector +** +** Returned: +** pv double[2][3] pv-vector +** +** Called: +** iauCp copy p-vector +** iauZp zero p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauCp(p, pv[0]); + iauZp(pv[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/p2s.c b/src/cpp/3rdparty/sofa/src/p2s.c new file mode 100644 index 000000000..e758dbe9b --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/p2s.c @@ -0,0 +1,141 @@ +#include "sofa.h" + +void iauP2s(double p[3], double *theta, double *phi, double *r) +/* +** - - - - - - - +** i a u P 2 s +** - - - - - - - +** +** P-vector to spherical polar coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** p double[3] p-vector +** +** Returned: +** theta double longitude angle (radians) +** phi double latitude angle (radians) +** r double radial distance +** +** Notes: +** +** 1) If P is null, zero theta, phi and r are returned. +** +** 2) At either pole, zero theta is returned. +** +** Called: +** iauC2s p-vector to spherical +** iauPm modulus of p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauC2s(p, theta, phi); + *r = iauPm(p); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pap.c b/src/cpp/3rdparty/sofa/src/pap.c new file mode 100644 index 000000000..49d4502bd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pap.c @@ -0,0 +1,191 @@ +#include "sofa.h" + +double iauPap(double a[3], double b[3]) +/* +** - - - - - - - +** i a u P a p +** - - - - - - - +** +** Position-angle from two p-vectors. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3] direction of reference point +** b double[3] direction of point whose PA is required +** +** Returned (function value): +** double position angle of b with respect to a (radians) +** +** Notes: +** +** 1) The result is the position angle, in radians, of direction b with +** respect to direction a. It is in the range -pi to +pi. The +** sense is such that if b is a small distance "north" of a the +** position angle is approximately zero, and if b is a small +** distance "east" of a the position angle is approximately +pi/2. +** +** 2) The vectors a and b need not be of unit length. +** +** 3) Zero is returned if the two directions are the same or if either +** vector is null. +** +** 4) If vector a is at a pole, the result is ill-defined. +** +** Called: +** iauPn decompose p-vector into modulus and direction +** iauPm modulus of p-vector +** iauPxp vector product of two p-vectors +** iauPmp p-vector minus p-vector +** iauPdp scalar product of two p-vectors +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double am, au[3], bm, st, ct, xa, ya, za, eta[3], xi[3], a2b[3], pa; + + +/* Modulus and direction of the a vector. */ + iauPn(a, &am, au); + +/* Modulus of the b vector. */ + bm = iauPm(b); + +/* Deal with the case of a null vector. */ + if ((am == 0.0) || (bm == 0.0)) { + st = 0.0; + ct = 1.0; + } else { + + /* The "north" axis tangential from a (arbitrary length). */ + xa = a[0]; + ya = a[1]; + za = a[2]; + eta[0] = -xa * za; + eta[1] = -ya * za; + eta[2] = xa*xa + ya*ya; + + /* The "east" axis tangential from a (same length). */ + iauPxp(eta, au, xi); + + /* The vector from a to b. */ + iauPmp(b, a, a2b); + + /* Resolve into components along the north and east axes. */ + st = iauPdp(a2b, xi); + ct = iauPdp(a2b, eta); + + /* Deal with degenerate cases. */ + if ((st == 0.0) && (ct == 0.0)) ct = 1.0; + } + +/* Position angle. */ + pa = atan2(st, ct); + + return pa; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pas.c b/src/cpp/3rdparty/sofa/src/pas.c new file mode 100644 index 000000000..079c26f3f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pas.c @@ -0,0 +1,148 @@ +#include "sofa.h" + +double iauPas(double al, double ap, double bl, double bp) +/* +** - - - - - - - +** i a u P a s +** - - - - - - - +** +** Position-angle from spherical coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** al double longitude of point A (e.g. RA) in radians +** ap double latitude of point A (e.g. Dec) in radians +** bl double longitude of point B +** bp double latitude of point B +** +** Returned (function value): +** double position angle of B with respect to A +** +** Notes: +** +** 1) The result is the bearing (position angle), in radians, of point +** B with respect to point A. It is in the range -pi to +pi. The +** sense is such that if B is a small distance "east" of point A, +** the bearing is approximately +pi/2. +** +** 2) Zero is returned if the two points are coincident. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dl, x, y, pa; + + + dl = bl - al; + y = sin(dl) * cos(bp); + x = sin(bp) * cos(ap) - cos(bp) * sin(ap) * cos(dl); + pa = ((x != 0.0) || (y != 0.0)) ? atan2(y, x) : 0.0; + + return pa; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pb06.c b/src/cpp/3rdparty/sofa/src/pb06.c new file mode 100644 index 000000000..12324d173 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pb06.c @@ -0,0 +1,202 @@ +#include "sofa.h" + +void iauPb06(double date1, double date2, + double *bzeta, double *bz, double *btheta) +/* +** - - - - - - - - +** i a u P b 0 6 +** - - - - - - - - +** +** This function forms three Euler angles which implement general +** precession from epoch J2000.0, using the IAU 2006 model. Frame +** bias (the offset between ICRS and mean J2000.0) is included. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** bzeta double 1st rotation: radians cw around z +** bz double 3rd rotation: radians cw around z +** btheta double 2nd rotation: radians ccw around y +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The traditional accumulated precession angles zeta_A, z_A, +** theta_A cannot be obtained in the usual way, namely through +** polynomial expressions, because of the frame bias. The latter +** means that two of the angles undergo rapid changes near this +** date. They are instead the results of decomposing the +** precession-bias matrix obtained by using the Fukushima-Williams +** method, which does not suffer from the problem. The +** decomposition returns values which can be used in the +** conventional formulation and which include frame bias. +** +** 3) The three angles are returned in the conventional order, which +** is not the same as the order of the corresponding Euler +** rotations. The precession-bias matrix is +** R_3(-z) x R_2(+theta) x R_3(-zeta). +** +** 4) Should zeta_A, z_A, theta_A angles be required that do not +** contain frame bias, they are available by calling the SOFA +** function iauP06e. +** +** Called: +** iauPmat06 PB matrix, IAU 2006 +** iauRz rotate around Z-axis +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r[3][3], y, x; + + +/* Precession matrix via Fukushima-Williams angles. */ + iauPmat06(date1, date2, r); + +/* Solve for z, choosing the +/- pi alternative. */ + y = r[1][2]; + x = -r[0][2]; + if ( x < 0.0 ) { + y = -y; + x = -x; + } + *bz = ( x != 0.0 || y != 0.0 ) ? - atan2(y,x) : 0.0; + +/* Derotate it out of the matrix. */ + iauRz ( *bz, r ); + +/* Solve for the remaining two angles. */ + y = r[0][2]; + x = r[2][2]; + *btheta = ( x != 0.0 || y != 0.0 ) ? - atan2(y,x) : 0.0; + + y = -r[1][0]; + x = r[1][1]; + *bzeta = ( x != 0.0 || y != 0.0 ) ? - atan2(y,x) : 0.0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pdp.c b/src/cpp/3rdparty/sofa/src/pdp.c new file mode 100644 index 000000000..b374f5c2d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pdp.c @@ -0,0 +1,136 @@ +#include "sofa.h" + +double iauPdp(double a[3], double b[3]) +/* +** - - - - - - - +** i a u P d p +** - - - - - - - +** +** p-vector inner (=scalar=dot) product. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3] first p-vector +** b double[3] second p-vector +** +** Returned (function value): +** double a . b +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double w; + + + w = a[0] * b[0] + + a[1] * b[1] + + a[2] * b[2]; + + return w; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pfw06.c b/src/cpp/3rdparty/sofa/src/pfw06.c new file mode 100644 index 000000000..b4796ad2d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pfw06.c @@ -0,0 +1,216 @@ +#include "sofa.h" +#include "sofam.h" + +void iauPfw06(double date1, double date2, + double *gamb, double *phib, double *psib, double *epsa) +/* +** - - - - - - - - - +** i a u P f w 0 6 +** - - - - - - - - - +** +** Precession angles, IAU 2006 (Fukushima-Williams 4-angle formulation). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** gamb double F-W angle gamma_bar (radians) +** phib double F-W angle phi_bar (radians) +** psib double F-W angle psi_bar (radians) +** epsa double F-W angle epsilon_A (radians) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) Naming the following points: +** +** e = J2000.0 ecliptic pole, +** p = GCRS pole, +** E = mean ecliptic pole of date, +** and P = mean pole of date, +** +** the four Fukushima-Williams angles are as follows: +** +** gamb = gamma_bar = epE +** phib = phi_bar = pE +** psib = psi_bar = pEP +** epsa = epsilon_A = EP +** +** 3) The matrix representing the combined effects of frame bias and +** precession is: +** +** PxB = R_1(-epsa).R_3(-psib).R_1(phib).R_3(gamb) +** +** 4) The matrix representing the combined effects of frame bias, +** precession and nutation is simply: +** +** NxPxB = R_1(-epsa-dE).R_3(-psib-dP).R_1(phib).R_3(gamb) +** +** where dP and dE are the nutation components with respect to the +** ecliptic of date. +** +** Reference: +** +** Hilton, J. et al., 2006, Celest.Mech.Dyn.Astron. 94, 351 +** +** Called: +** iauObl06 mean obliquity, IAU 2006 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t; + + +/* Interval between fundamental date J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* P03 bias+precession angles. */ + *gamb = ( -0.052928 + + ( 10.556378 + + ( 0.4932044 + + ( -0.00031238 + + ( -0.000002788 + + ( 0.0000000260 ) + * t) * t) * t) * t) * t) * DAS2R; + *phib = ( 84381.412819 + + ( -46.811016 + + ( 0.0511268 + + ( 0.00053289 + + ( -0.000000440 + + ( -0.0000000176 ) + * t) * t) * t) * t) * t) * DAS2R; + *psib = ( -0.041775 + + ( 5038.481484 + + ( 1.5584175 + + ( -0.00018522 + + ( -0.000026452 + + ( -0.0000000148 ) + * t) * t) * t) * t) * t) * DAS2R; + *epsa = iauObl06(date1, date2); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/plan94.c b/src/cpp/3rdparty/sofa/src/plan94.c new file mode 100644 index 000000000..a81dd7514 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/plan94.c @@ -0,0 +1,569 @@ +#include "sofa.h" +#include "sofam.h" + +int iauPlan94(double date1, double date2, int np, double pv[2][3]) +/* +** - - - - - - - - - - +** i a u P l a n 9 4 +** - - - - - - - - - - +** +** Approximate heliocentric position and velocity of a nominated major +** planet: Mercury, Venus, EMB, Mars, Jupiter, Saturn, Uranus or +** Neptune (but not the Earth itself). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** n.b. Not IAU-endorsed and without canonical status. +** +** Given: +** date1 double TDB date part A (Note 1) +** date2 double TDB date part B (Note 1) +** np int planet (1=Mercury, 2=Venus, 3=EMB, 4=Mars, +** 5=Jupiter, 6=Saturn, 7=Uranus, 8=Neptune) +** +** Returned (argument): +** pv double[2][3] planet p,v (heliocentric, J2000.0, au,au/d) +** +** Returned (function value): +** int status: -1 = illegal NP (outside 1-8) +** 0 = OK +** +1 = warning: year outside 1000-3000 +** +2 = warning: failed to converge +** +** Notes: +** +** 1) The date date1+date2 is in the TDB time scale (in practice TT can +** be used) and is a Julian Date, apportioned in any convenient way +** between the two arguments. For example, JD(TDB)=2450123.7 could +** be expressed in any of these ways, among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. The limited +** accuracy of the present algorithm is such that any of the methods +** is satisfactory. +** +** 2) If an np value outside the range 1-8 is supplied, an error status +** (function value -1) is returned and the pv vector set to zeroes. +** +** 3) For np=3 the result is for the Earth-Moon Barycenter. To obtain +** the heliocentric position and velocity of the Earth, use instead +** the SOFA function iauEpv00. +** +** 4) On successful return, the array pv contains the following: +** +** pv[0][0] x } +** pv[0][1] y } heliocentric position, au +** pv[0][2] z } +** +** pv[1][0] xdot } +** pv[1][1] ydot } heliocentric velocity, au/d +** pv[1][2] zdot } +** +** The reference frame is equatorial and is with respect to the +** mean equator and equinox of epoch J2000.0. +** +** 5) The algorithm is due to J.L. Simon, P. Bretagnon, J. Chapront, +** M. Chapront-Touze, G. Francou and J. Laskar (Bureau des +** Longitudes, Paris, France). From comparisons with JPL +** ephemeris DE102, they quote the following maximum errors +** over the interval 1800-2050: +** +** L (arcsec) B (arcsec) R (km) +** +** Mercury 4 1 300 +** Venus 5 1 800 +** EMB 6 1 1000 +** Mars 17 1 7700 +** Jupiter 71 5 76000 +** Saturn 81 13 267000 +** Uranus 86 7 712000 +** Neptune 11 1 253000 +** +** Over the interval 1000-3000, they report that the accuracy is no +** worse than 1.5 times that over 1800-2050. Outside 1000-3000 the +** accuracy declines. +** +** Comparisons of the present function with the JPL DE200 ephemeris +** give the following RMS errors over the interval 1960-2025: +** +** position (km) velocity (m/s) +** +** Mercury 334 0.437 +** Venus 1060 0.855 +** EMB 2010 0.815 +** Mars 7690 1.98 +** Jupiter 71700 7.70 +** Saturn 199000 19.4 +** Uranus 564000 16.4 +** Neptune 158000 14.4 +** +** Comparisons against DE200 over the interval 1800-2100 gave the +** following maximum absolute differences. (The results using +** DE406 were essentially the same.) +** +** L (arcsec) B (arcsec) R (km) Rdot (m/s) +** +** Mercury 7 1 500 0.7 +** Venus 7 1 1100 0.9 +** EMB 9 1 1300 1.0 +** Mars 26 1 9000 2.5 +** Jupiter 78 6 82000 8.2 +** Saturn 87 14 263000 24.6 +** Uranus 86 7 661000 27.4 +** Neptune 11 2 248000 21.4 +** +** 6) The present SOFA re-implementation of the original Simon et al. +** Fortran code differs from the original in the following respects: +** +** * C instead of Fortran. +** +** * The date is supplied in two parts. +** +** * The result is returned only in equatorial Cartesian form; +** the ecliptic longitude, latitude and radius vector are not +** returned. +** +** * The result is in the J2000.0 equatorial frame, not ecliptic. +** +** * More is done in-line: there are fewer calls to subroutines. +** +** * Different error/warning status values are used. +** +** * A different Kepler's-equation-solver is used (avoiding +** use of double precision complex). +** +** * Polynomials in t are nested to minimize rounding errors. +** +** * Explicit double constants are used to avoid mixed-mode +** expressions. +** +** None of the above changes affects the result significantly. +** +** 7) The returned status indicates the most serious condition +** encountered during execution of the function. Illegal np is +** considered the most serious, overriding failure to converge, +** which in turn takes precedence over the remote date warning. +** +** Called: +** iauAnpm normalize angle into range +/- pi +** +** Reference: Simon, J.L, Bretagnon, P., Chapront, J., +** Chapront-Touze, M., Francou, G., and Laskar, J., +** Astron.Astrophys., 282, 663 (1994). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Gaussian constant */ + static const double GK = 0.017202098950; + +/* Sin and cos of J2000.0 mean obliquity (IAU 1976) */ + static const double SINEPS = 0.3977771559319137; + static const double COSEPS = 0.9174820620691818; + +/* Maximum number of iterations allowed to solve Kepler's equation */ + static const int KMAX = 10; + + int jstat, i, k; + double t, da, dl, de, dp, di, dom, dmu, arga, argl, am, + ae, dae, ae2, at, r, v, si2, xq, xp, tl, xsw, + xcw, xm2, xf, ci2, xms, xmc, xpxq2, x, y, z; + +/* Planetary inverse masses */ + static const double amas[] = { 6023600.0, /* Mercury */ + 408523.5, /* Venus */ + 328900.5, /* EMB */ + 3098710.0, /* Mars */ + 1047.355, /* Jupiter */ + 3498.5, /* Saturn */ + 22869.0, /* Uranus */ + 19314.0 }; /* Neptune */ + +/* +** Tables giving the mean Keplerian elements, limited to t^2 terms: +** +** a semi-major axis (au) +** dlm mean longitude (degree and arcsecond) +** e eccentricity +** pi longitude of the perihelion (degree and arcsecond) +** dinc inclination (degree and arcsecond) +** omega longitude of the ascending node (degree and arcsecond) +*/ + + static const double a[][3] = { + { 0.3870983098, 0.0, 0.0 }, /* Mercury */ + { 0.7233298200, 0.0, 0.0 }, /* Venus */ + { 1.0000010178, 0.0, 0.0 }, /* EMB */ + { 1.5236793419, 3e-10, 0.0 }, /* Mars */ + { 5.2026032092, 19132e-10, -39e-10 }, /* Jupiter */ + { 9.5549091915, -0.0000213896, 444e-10 }, /* Saturn */ + { 19.2184460618, -3716e-10, 979e-10 }, /* Uranus */ + { 30.1103868694, -16635e-10, 686e-10 } /* Neptune */ + }; + + static const double dlm[][3] = { + { 252.25090552, 5381016286.88982, -1.92789 }, + { 181.97980085, 2106641364.33548, 0.59381 }, + { 100.46645683, 1295977422.83429, -2.04411 }, + { 355.43299958, 689050774.93988, 0.94264 }, + { 34.35151874, 109256603.77991, -30.60378 }, + { 50.07744430, 43996098.55732, 75.61614 }, + { 314.05500511, 15424811.93933, -1.75083 }, + { 304.34866548, 7865503.20744, 0.21103 } + }; + + static const double e[][3] = { + { 0.2056317526, 0.0002040653, -28349e-10 }, + { 0.0067719164, -0.0004776521, 98127e-10 }, + { 0.0167086342, -0.0004203654, -0.0000126734 }, + { 0.0934006477, 0.0009048438, -80641e-10 }, + { 0.0484979255, 0.0016322542, -0.0000471366 }, + { 0.0555481426, -0.0034664062, -0.0000643639 }, + { 0.0463812221, -0.0002729293, 0.0000078913 }, + { 0.0094557470, 0.0000603263, 0.0 } + }; + + static const double pi[][3] = { + { 77.45611904, 5719.11590, -4.83016 }, + { 131.56370300, 175.48640, -498.48184 }, + { 102.93734808, 11612.35290, 53.27577 }, + { 336.06023395, 15980.45908, -62.32800 }, + { 14.33120687, 7758.75163, 259.95938 }, + { 93.05723748, 20395.49439, 190.25952 }, + { 173.00529106, 3215.56238, -34.09288 }, + { 48.12027554, 1050.71912, 27.39717 } + }; + + static const double dinc[][3] = { + { 7.00498625, -214.25629, 0.28977 }, + { 3.39466189, -30.84437, -11.67836 }, + { 0.0, 469.97289, -3.35053 }, + { 1.84972648, -293.31722, -8.11830 }, + { 1.30326698, -71.55890, 11.95297 }, + { 2.48887878, 91.85195, -17.66225 }, + { 0.77319689, -60.72723, 1.25759 }, + { 1.76995259, 8.12333, 0.08135 } + }; + + static const double omega[][3] = { + { 48.33089304, -4515.21727, -31.79892 }, + { 76.67992019, -10008.48154, -51.32614 }, + { 174.87317577, -8679.27034, 15.34191 }, + { 49.55809321, -10620.90088, -230.57416 }, + { 100.46440702, 6362.03561, 326.52178 }, + { 113.66550252, -9240.19942, -66.23743 }, + { 74.00595701, 2669.15033, 145.93964 }, + { 131.78405702, -221.94322, -0.78728 } + }; + +/* Tables for trigonometric terms to be added to the mean elements of */ +/* the semi-major axes */ + + static const double kp[][9] = { + { 69613, 75645, 88306, 59899, 15746, 71087, 142173, 3086, 0 }, + { 21863, 32794, 26934, 10931, 26250, 43725, 53867, 28939, 0 }, + { 16002, 21863, 32004, 10931, 14529, 16368, 15318, 32794, 0 }, + { 6345, 7818, 15636, 7077, 8184, 14163, 1107, 4872, 0 }, + { 1760, 1454, 1167, 880, 287, 2640, 19, 2047, 1454 }, + { 574, 0, 880, 287, 19, 1760, 1167, 306, 574 }, + { 204, 0, 177, 1265, 4, 385, 200, 208, 204 }, + { 0, 102, 106, 4, 98, 1367, 487, 204, 0 } + }; + + static const double ca[][9] = { + { 4, -13, 11, -9, -9, -3, -1, 4, 0 }, + { -156, 59, -42, 6, 19, -20, -10, -12, 0 }, + { 64, -152, 62, -8, 32, -41, 19, -11, 0 }, + { 124, 621, -145, 208, 54, -57, 30, 15, 0 }, + { -23437, -2634, 6601, 6259, -1507,-1821, 2620, -2115, -1489 }, + { 62911,-119919, 79336,17814,-24241,12068, 8306, -4893, 8902 }, + { 389061,-262125,-44088, 8387,-22976,-2093, -615, -9720, 6633 }, + { -412235,-157046,-31430,37817, -9740, -13, -7449, 9644, 0 } + }; + + static const double sa[][9] = { + { -29, -1, 9, 6, -6, 5, 4, 0, 0 }, + { -48, -125, -26, -37, 18, -13, -20, -2, 0 }, + { -150, -46, 68, 54, 14, 24, -28, 22, 0 }, + { -621, 532, -694, -20, 192, -94, 71, -73, 0 }, + { -14614,-19828, -5869, 1881, -4372, -2255, 782, 930, 913 }, + { 139737, 0, 24667, 51123, -5102, 7429, -4095, -1976, -9566 }, + { -138081, 0, 37205,-49039,-41901,-33872,-27037,-12474, 18797 }, + { 0, 28492,133236, 69654, 52322,-49577,-26430, -3593, 0 } + }; + +/* Tables giving the trigonometric terms to be added to the mean */ +/* elements of the mean longitudes */ + + static const double kq[][10] = { + { 3086,15746,69613,59899,75645,88306, 12661, 2658, 0, 0 }, + { 21863,32794,10931, 73, 4387,26934, 1473, 2157, 0, 0 }, + { 10,16002,21863,10931, 1473,32004, 4387, 73, 0, 0 }, + { 10, 6345, 7818, 1107,15636, 7077, 8184, 532, 10, 0 }, + { 19, 1760, 1454, 287, 1167, 880, 574, 2640, 19, 1454 }, + { 19, 574, 287, 306, 1760, 12, 31, 38, 19, 574 }, + { 4, 204, 177, 8, 31, 200, 1265, 102, 4, 204 }, + { 4, 102, 106, 8, 98, 1367, 487, 204, 4, 102 } + }; + + static const double cl[][10] = { + { 21, -95, -157, 41, -5, 42, 23, 30, 0, 0 }, + { -160, -313, -235, 60, -74, -76, -27, 34, 0, 0 }, + { -325, -322, -79, 232, -52, 97, 55, -41, 0, 0 }, + { 2268, -979, 802, 602, -668, -33, 345, 201, -55, 0 }, + { 7610, -4997,-7689,-5841,-2617, 1115,-748,-607, 6074, 354 }, + { -18549, 30125,20012, -730, 824, 23,1289,-352, -14767, -2062 }, + { -135245,-14594, 4197,-4030,-5630,-2898,2540,-306, 2939, 1986 }, + { 89948, 2103, 8963, 2695, 3682, 1648, 866,-154, -1963, -283 } + }; + + static const double sl[][10] = { + { -342, 136, -23, 62, 66, -52, -33, 17, 0, 0 }, + { 524, -149, -35, 117, 151, 122, -71, -62, 0, 0 }, + { -105, -137, 258, 35, -116, -88,-112, -80, 0, 0 }, + { 854, -205, -936, -240, 140, -341, -97, -232, 536, 0 }, + { -56980, 8016, 1012, 1448,-3024,-3710, 318, 503, 3767, 577 }, + { 138606,-13478,-4964, 1441,-1319,-1482, 427, 1236, -9167, -1918 }, + { 71234,-41116, 5334,-4935,-1848, 66, 434, -1748, 3780, -701 }, + { -47645, 11647, 2166, 3194, 679, 0,-244, -419, -2531, 48 } + }; + +/* ------------------------------------------------------------------ */ + +/* Validate the planet number. */ + if ((np < 1) || (np > 8)) { + jstat = -1; + + /* Reset the result in case of failure. */ + for (k = 0; k < 2; k++) { + for (i = 0; i < 3; i++) { + pv[k][i] = 0.0; + } + } + + } else { + + /* Decrement the planet number to start at zero. */ + np--; + + /* Time: Julian millennia since J2000.0. */ + t = ((date1 - DJ00) + date2) / DJM; + + /* OK status unless remote date. */ + jstat = fabs(t) <= 1.0 ? 0 : 1; + + /* Compute the mean elements. */ + da = a[np][0] + + (a[np][1] + + a[np][2] * t) * t; + dl = (3600.0 * dlm[np][0] + + (dlm[np][1] + + dlm[np][2] * t) * t) * DAS2R; + de = e[np][0] + + ( e[np][1] + + e[np][2] * t) * t; + dp = iauAnpm((3600.0 * pi[np][0] + + (pi[np][1] + + pi[np][2] * t) * t) * DAS2R); + di = (3600.0 * dinc[np][0] + + (dinc[np][1] + + dinc[np][2] * t) * t) * DAS2R; + dom = iauAnpm((3600.0 * omega[np][0] + + (omega[np][1] + + omega[np][2] * t) * t) * DAS2R); + + /* Apply the trigonometric terms. */ + dmu = 0.35953620 * t; + for (k = 0; k < 8; k++) { + arga = kp[np][k] * dmu; + argl = kq[np][k] * dmu; + da += (ca[np][k] * cos(arga) + + sa[np][k] * sin(arga)) * 1e-7; + dl += (cl[np][k] * cos(argl) + + sl[np][k] * sin(argl)) * 1e-7; + } + arga = kp[np][8] * dmu; + da += t * (ca[np][8] * cos(arga) + + sa[np][8] * sin(arga)) * 1e-7; + for (k = 8; k < 10; k++) { + argl = kq[np][k] * dmu; + dl += t * (cl[np][k] * cos(argl) + + sl[np][k] * sin(argl)) * 1e-7; + } + dl = fmod(dl, D2PI); + + /* Iterative soln. of Kepler's equation to get eccentric anomaly. */ + am = dl - dp; + ae = am + de * sin(am); + k = 0; + dae = 1.0; + while (k < KMAX && fabs(dae) > 1e-12) { + dae = (am - ae + de * sin(ae)) / (1.0 - de * cos(ae)); + ae += dae; + k++; + if (k == KMAX-1) jstat = 2; + } + + /* True anomaly. */ + ae2 = ae / 2.0; + at = 2.0 * atan2(sqrt((1.0 + de) / (1.0 - de)) * sin(ae2), + cos(ae2)); + + /* Distance (au) and speed (radians per day). */ + r = da * (1.0 - de * cos(ae)); + v = GK * sqrt((1.0 + 1.0 / amas[np]) / (da * da * da)); + + si2 = sin(di / 2.0); + xq = si2 * cos(dom); + xp = si2 * sin(dom); + tl = at + dp; + xsw = sin(tl); + xcw = cos(tl); + xm2 = 2.0 * (xp * xcw - xq * xsw); + xf = da / sqrt(1 - de * de); + ci2 = cos(di / 2.0); + xms = (de * sin(dp) + xsw) * xf; + xmc = (de * cos(dp) + xcw) * xf; + xpxq2 = 2 * xp * xq; + + /* Position (J2000.0 ecliptic x,y,z in au). */ + x = r * (xcw - xm2 * xp); + y = r * (xsw + xm2 * xq); + z = r * (-xm2 * ci2); + + /* Rotate to equatorial. */ + pv[0][0] = x; + pv[0][1] = y * COSEPS - z * SINEPS; + pv[0][2] = y * SINEPS + z * COSEPS; + + /* Velocity (J2000.0 ecliptic xdot,ydot,zdot in au/d). */ + x = v * (( -1.0 + 2.0 * xp * xp) * xms + xpxq2 * xmc); + y = v * (( 1.0 - 2.0 * xq * xq) * xmc - xpxq2 * xms); + z = v * (2.0 * ci2 * (xp * xms + xq * xmc)); + + /* Rotate to equatorial. */ + pv[1][0] = x; + pv[1][1] = y * COSEPS - z * SINEPS; + pv[1][2] = y * SINEPS + z * COSEPS; + + } + +/* Return the status. */ + return jstat; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pm.c b/src/cpp/3rdparty/sofa/src/pm.c new file mode 100644 index 000000000..0ea36fd0f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pm.c @@ -0,0 +1,128 @@ +#include "sofa.h" + +double iauPm(double p[3]) +/* +** - - - - - - +** i a u P m +** - - - - - - +** +** Modulus of p-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** p double[3] p-vector +** +** Returned (function value): +** double modulus +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + return sqrt( p[0]*p[0] + p[1]*p[1] + p[2]*p[2] ); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pmat00.c b/src/cpp/3rdparty/sofa/src/pmat00.c new file mode 100644 index 000000000..75de1763c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pmat00.c @@ -0,0 +1,168 @@ +#include "sofa.h" + +void iauPmat00(double date1, double date2, double rbp[3][3]) +/* +** - - - - - - - - - - +** i a u P m a t 0 0 +** - - - - - - - - - - +** +** Precession matrix (including frame bias) from GCRS to a specified +** date, IAU 2000 model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rbp double[3][3] bias-precession matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(date) = rbp * V(GCRS), where +** the p-vector V(GCRS) is with respect to the Geocentric Celestial +** Reference System (IAU, 2000) and the p-vector V(date) is with +** respect to the mean equatorial triad of the given date. +** +** Called: +** iauBp00 frame bias and precession matrices, IAU 2000 +** +** Reference: +** +** IAU: Trans. International Astronomical Union, Vol. XXIVB; Proc. +** 24th General Assembly, Manchester, UK. Resolutions B1.3, B1.6. +** (2000) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rb[3][3], rp[3][3]; + + +/* Obtain the required matrix (discarding others). */ + iauBp00(date1, date2, rb, rp, rbp); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pmat06.c b/src/cpp/3rdparty/sofa/src/pmat06.c new file mode 100644 index 000000000..10e09bebb --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pmat06.c @@ -0,0 +1,176 @@ +#include "sofa.h" + +void iauPmat06(double date1, double date2, double rbp[3][3]) +/* +** - - - - - - - - - - +** i a u P m a t 0 6 +** - - - - - - - - - - +** +** Precession matrix (including frame bias) from GCRS to a specified +** date, IAU 2006 model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rbp double[3][3] bias-precession matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(date) = rbp * V(GCRS), where +** the p-vector V(GCRS) is with respect to the Geocentric Celestial +** Reference System (IAU, 2000) and the p-vector V(date) is with +** respect to the mean equatorial triad of the given date. +** +** Called: +** iauPfw06 bias-precession F-W angles, IAU 2006 +** iauFw2m F-W angles to r-matrix +** +** References: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** IAU: Trans. International Astronomical Union, Vol. XXIVB; Proc. +** 24th General Assembly, Manchester, UK. Resolutions B1.3, B1.6. +** (2000) +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gamb, phib, psib, epsa; + + +/* Bias-precession Fukushima-Williams angles. */ + iauPfw06(date1, date2, &gamb, &phib, &psib, &epsa); + +/* Form the matrix. */ + iauFw2m(gamb, phib, psib, epsa, rbp); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pmat76.c b/src/cpp/3rdparty/sofa/src/pmat76.c new file mode 100644 index 000000000..c19bdcca3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pmat76.c @@ -0,0 +1,192 @@ +#include "sofa.h" +#include "sofam.h" + +void iauPmat76(double date1, double date2, double rmatp[3][3]) +/* +** - - - - - - - - - - +** i a u P m a t 7 6 +** - - - - - - - - - - +** +** Precession matrix from J2000.0 to a specified date, IAU 1976 model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double ending date, TT (Note 1) +** +** Returned: +** rmatp double[3][3] precession matrix, J2000.0 -> date1+date2 +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(date) = RMATP * V(J2000), +** where the p-vector V(J2000) is with respect to the mean +** equatorial triad of epoch J2000.0 and the p-vector V(date) +** is with respect to the mean equatorial triad of the given +** date. +** +** 3) Though the matrix method itself is rigorous, the precession +** angles are expressed through canonical polynomials which are +** valid only for a limited time span. In addition, the IAU 1976 +** precession rate is known to be imperfect. The absolute accuracy +** of the present formulation is better than 0.1 arcsec from +** 1960AD to 2040AD, better than 1 arcsec from 1640AD to 2360AD, +** and remains below 3 arcsec for the whole of the period +** 500BC to 3000AD. The errors exceed 10 arcsec outside the +** range 1200BC to 3900AD, exceed 100 arcsec outside 4200BC to +** 5600AD and exceed 1000 arcsec outside 6800BC to 8200AD. +** +** Called: +** iauPrec76 accumulated precession angles, IAU 1976 +** iauIr initialize r-matrix to identity +** iauRz rotate around Z-axis +** iauRy rotate around Y-axis +** iauCr copy r-matrix +** +** References: +** +** Lieske, J.H., 1979, Astron.Astrophys. 73, 282. +** equations (6) & (7), p283. +** +** Kaplan,G.H., 1981. USNO circular no. 163, pA2. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double zeta, z, theta, wmat[3][3]; + + +/* Precession Euler angles, J2000.0 to specified date. */ + iauPrec76(DJ00, 0.0, date1, date2, &zeta, &z, &theta); + +/* Form the rotation matrix. */ + iauIr( wmat); + iauRz( -zeta, wmat); + iauRy( theta, wmat); + iauRz( -z, wmat); + iauCr( wmat, rmatp); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pmp.c b/src/cpp/3rdparty/sofa/src/pmp.c new file mode 100644 index 000000000..9cae65b22 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pmp.c @@ -0,0 +1,135 @@ +#include "sofa.h" + +void iauPmp(double a[3], double b[3], double amb[3]) +/* +** - - - - - - - +** i a u P m p +** - - - - - - - +** +** P-vector subtraction. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3] first p-vector +** b double[3] second p-vector +** +** Returned: +** amb double[3] a - b +** +** Note: +** It is permissible to re-use the same array for any of the +** arguments. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + amb[0] = a[0] - b[0]; + amb[1] = a[1] - b[1]; + amb[2] = a[2] - b[2]; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pmpx.c b/src/cpp/3rdparty/sofa/src/pmpx.c new file mode 100644 index 000000000..1d006b9c9 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pmpx.c @@ -0,0 +1,195 @@ +#include "sofa.h" +#include "sofam.h" + +void iauPmpx(double rc, double dc, double pr, double pd, + double px, double rv, double pmt, double pob[3], + double pco[3]) +/* +** - - - - - - - - +** i a u P m p x +** - - - - - - - - +** +** Proper motion and parallax. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** rc,dc double ICRS RA,Dec at catalog epoch (radians) +** pr double RA proper motion (radians/year, Note 1) +** pd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, +ve if receding) +** pmt double proper motion time interval (SSB, Julian years) +** pob double[3] SSB to observer vector (au) +** +** Returned: +** pco double[3] coordinate direction (BCRS unit vector) +** +** Notes: +** +** 1) The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt. +** +** 2) The proper motion time interval is for when the starlight +** reaches the solar system barycenter. +** +** 3) To avoid the need for iteration, the Roemer effect (i.e. the +** small annual modulation of the proper motion coming from the +** changing light time) is applied approximately, using the +** direction of the star at the catalog epoch. +** +** References: +** +** 1984 Astronomical Almanac, pp B39-B41. +** +** Urban, S. & Seidelmann, P. K. (eds), Explanatory Supplement to +** the Astronomical Almanac, 3rd ed., University Science Books +** (2013), Section 7.2. +** +** Called: +** iauPdp scalar product of two p-vectors +** iauPn decompose p-vector into modulus and direction +** +** This revision: 2021 April 3 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Km/s to au/year */ + const double VF = DAYSEC*DJM/DAU; + +/* Light time for 1 au, Julian years */ + const double AULTY = AULT/DAYSEC/DJY; + + int i; + double sr, cr, sd, cd, x, y, z, p[3], dt, pxr, w, pdz, pm[3]; + + +/* Spherical coordinates to unit vector (and useful functions). */ + sr = sin(rc); + cr = cos(rc); + sd = sin(dc); + cd = cos(dc); + p[0] = x = cr*cd; + p[1] = y = sr*cd; + p[2] = z = sd; + +/* Proper motion time interval (y) including Roemer effect. */ + dt = pmt + iauPdp(p,pob)*AULTY; + +/* Space motion (radians per year). */ + pxr = px * DAS2R; + w = VF * rv * pxr; + pdz = pd * z; + pm[0] = - pr*y - pdz*cr + w*x; + pm[1] = pr*x - pdz*sr + w*y; + pm[2] = pd*cd + w*z; + +/* Coordinate direction of star (unit vector, BCRS). */ + for (i = 0; i < 3; i++) { + p[i] += dt*pm[i] - pxr*pob[i]; + } + iauPn(p, &w, pco); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pmsafe.c b/src/cpp/3rdparty/sofa/src/pmsafe.c new file mode 100644 index 000000000..175ae71b3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pmsafe.c @@ -0,0 +1,247 @@ +#include "sofa.h" + +int iauPmsafe(double ra1, double dec1, double pmr1, double pmd1, + double px1, double rv1, + double ep1a, double ep1b, double ep2a, double ep2b, + double *ra2, double *dec2, double *pmr2, double *pmd2, + double *px2, double *rv2) +/* +** - - - - - - - - - - +** i a u P m s a f e +** - - - - - - - - - - +** +** Star proper motion: update star catalog data for space motion, with +** special handling to handle the zero parallax case. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ra1 double right ascension (radians), before +** dec1 double declination (radians), before +** pmr1 double RA proper motion (radians/year), before +** pmd1 double Dec proper motion (radians/year), before +** px1 double parallax (arcseconds), before +** rv1 double radial velocity (km/s, +ve = receding), before +** ep1a double "before" epoch, part A (Note 1) +** ep1b double "before" epoch, part B (Note 1) +** ep2a double "after" epoch, part A (Note 1) +** ep2b double "after" epoch, part B (Note 1) +** +** Returned: +** ra2 double right ascension (radians), after +** dec2 double declination (radians), after +** pmr2 double RA proper motion (radians/year), after +** pmd2 double Dec proper motion (radians/year), after +** px2 double parallax (arcseconds), after +** rv2 double radial velocity (km/s, +ve = receding), after +** +** Returned (function value): +** int status: +** -1 = system error (should not occur) +** 0 = no warnings or errors +** 1 = distance overridden (Note 6) +** 2 = excessive velocity (Note 7) +** 4 = solution didn't converge (Note 8) +** else = binary logical OR of the above warnings +** +** Notes: +** +** 1) The starting and ending TDB epochs ep1a+ep1b and ep2a+ep2b are +** Julian Dates, apportioned in any convenient way between the two +** parts (A and B). For example, JD(TDB)=2450123.7 could be +** expressed in any of these ways, among others: +** +** epNa epNb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** resolution. The MJD method and the date & time methods are both +** good compromises between resolution and convenience. +** +** 2) In accordance with normal star-catalog conventions, the object's +** right ascension and declination are freed from the effects of +** secular aberration. The frame, which is aligned to the catalog +** equator and equinox, is Lorentzian and centered on the SSB. +** +** The proper motions are the rate of change of the right ascension +** and declination at the catalog epoch and are in radians per TDB +** Julian year. +** +** The parallax and radial velocity are in the same frame. +** +** 3) Care is needed with units. The star coordinates are in radians +** and the proper motions in radians per Julian year, but the +** parallax is in arcseconds. +** +** 4) The RA proper motion is in terms of coordinate angle, not true +** angle. If the catalog uses arcseconds for both RA and Dec proper +** motions, the RA proper motion will need to be divided by cos(Dec) +** before use. +** +** 5) Straight-line motion at constant speed, in the inertial frame, is +** assumed. +** +** 6) An extremely small (or zero or negative) parallax is overridden +** to ensure that the object is at a finite but very large distance, +** but not so large that the proper motion is equivalent to a large +** but safe speed (about 0.1c using the chosen constant). A warning +** status of 1 is added to the status if this action has been taken. +** +** 7) If the space velocity is a significant fraction of c (see the +** constant VMAX in the function iauStarpv), it is arbitrarily set +** to zero. When this action occurs, 2 is added to the status. +** +** 8) The relativistic adjustment carried out in the iauStarpv function +** involves an iterative calculation. If the process fails to +** converge within a set number of iterations, 4 is added to the +** status. +** +** Called: +** iauSeps angle between two points +** iauStarpm update star catalog data for space motion +** +** This revision: 2014 July 1 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Minimum allowed parallax (arcsec) */ + const double PXMIN = 5e-7; + +/* Factor giving maximum allowed transverse speed of about 1% c */ + const double F = 326.0; + + int jpx, j; + double pm, px1a; + + +/* Proper motion in one year (radians). */ + pm = iauSeps(ra1, dec1, ra1+pmr1, dec1+pmd1); + +/* Override the parallax to reduce the chances of a warning status. */ + jpx = 0; + px1a = px1; + pm *= F; + if (px1a < pm) {jpx = 1; px1a = pm;} + if (px1a < PXMIN) {jpx = 1; px1a = PXMIN;} + +/* Carry out the transformation using the modified parallax. */ + j = iauStarpm(ra1, dec1, pmr1, pmd1, px1a, rv1, + ep1a, ep1b, ep2a, ep2b, + ra2, dec2, pmr2, pmd2, px2, rv2); + +/* Revise and return the status. */ + if ( !(j%2) ) j += jpx; + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pn.c b/src/cpp/3rdparty/sofa/src/pn.c new file mode 100644 index 000000000..6d9743ef8 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pn.c @@ -0,0 +1,159 @@ +#include "sofa.h" + +void iauPn(double p[3], double *r, double u[3]) +/* +** - - - - - - +** i a u P n +** - - - - - - +** +** Convert a p-vector into modulus and unit vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** p double[3] p-vector +** +** Returned: +** r double modulus +** u double[3] unit vector +** +** Notes: +** +** 1) If p is null, the result is null. Otherwise the result is a unit +** vector. +** +** 2) It is permissible to re-use the same array for any of the +** arguments. +** +** Called: +** iauPm modulus of p-vector +** iauZp zero p-vector +** iauSxp multiply p-vector by scalar +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double w; + + +/* Obtain the modulus and test for zero. */ + w = iauPm(p); + if (w == 0.0) { + + /* Null vector. */ + iauZp(u); + + } else { + + /* Unit vector. */ + iauSxp(1.0/w, p, u); + } + +/* Return the modulus. */ + *r = w; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pn00.c b/src/cpp/3rdparty/sofa/src/pn00.c new file mode 100644 index 000000000..10b137afb --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pn00.c @@ -0,0 +1,227 @@ +#include "sofa.h" + +void iauPn00(double date1, double date2, double dpsi, double deps, + double *epsa, + double rb[3][3], double rp[3][3], double rbp[3][3], + double rn[3][3], double rbpn[3][3]) +/* +** - - - - - - - - +** i a u P n 0 0 +** - - - - - - - - +** +** Precession-nutation, IAU 2000 model: a multi-purpose function, +** supporting classical (equinox-based) use directly and CIO-based +** use indirectly. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** dpsi,deps double nutation (Note 2) +** +** Returned: +** epsa double mean obliquity (Note 3) +** rb double[3][3] frame bias matrix (Note 4) +** rp double[3][3] precession matrix (Note 5) +** rbp double[3][3] bias-precession matrix (Note 6) +** rn double[3][3] nutation matrix (Note 7) +** rbpn double[3][3] GCRS-to-true matrix (Note 8) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The caller is responsible for providing the nutation components; +** they are in longitude and obliquity, in radians and are with +** respect to the equinox and ecliptic of date. For high-accuracy +** applications, free core nutation should be included as well as +** any other relevant corrections to the position of the CIP. +** +** 3) The returned mean obliquity is consistent with the IAU 2000 +** precession-nutation models. +** +** 4) The matrix rb transforms vectors from GCRS to J2000.0 mean +** equator and equinox by applying frame bias. +** +** 5) The matrix rp transforms vectors from J2000.0 mean equator and +** equinox to mean equator and equinox of date by applying +** precession. +** +** 6) The matrix rbp transforms vectors from GCRS to mean equator and +** equinox of date by applying frame bias then precession. It is +** the product rp x rb. +** +** 7) The matrix rn transforms vectors from mean equator and equinox of +** date to true equator and equinox of date by applying the nutation +** (luni-solar + planetary). +** +** 8) The matrix rbpn transforms vectors from GCRS to true equator and +** equinox of date. It is the product rn x rbp, applying frame +** bias, precession and nutation in that order. +** +** 9) It is permissible to re-use the same array in the returned +** arguments. The arrays are filled in the order given. +** +** Called: +** iauPr00 IAU 2000 precession adjustments +** iauObl80 mean obliquity, IAU 1980 +** iauBp00 frame bias and precession matrices, IAU 2000 +** iauCr copy r-matrix +** iauNumat form nutation matrix +** iauRxr product of two r-matrices +** +** Reference: +** +** Capitaine, N., Chapront, J., Lambert, S. and Wallace, P., +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsipr, depspr, rbpw[3][3], rnw[3][3]; + + +/* IAU 2000 precession-rate adjustments. */ + iauPr00(date1, date2, &dpsipr, &depspr); + +/* Mean obliquity, consistent with IAU 2000 precession-nutation. */ + *epsa = iauObl80(date1, date2) + depspr; + +/* Frame bias and precession matrices and their product. */ + iauBp00(date1, date2, rb, rp, rbpw); + iauCr(rbpw, rbp); + +/* Nutation matrix. */ + iauNumat(*epsa, dpsi, deps, rnw); + iauCr(rnw, rn); + +/* Bias-precession-nutation matrix (classical). */ + iauRxr(rnw, rbpw, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pn00a.c b/src/cpp/3rdparty/sofa/src/pn00a.c new file mode 100644 index 000000000..b68ac8b0d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pn00a.c @@ -0,0 +1,213 @@ +#include "sofa.h" + +void iauPn00a(double date1, double date2, + double *dpsi, double *deps, double *epsa, + double rb[3][3], double rp[3][3], double rbp[3][3], + double rn[3][3], double rbpn[3][3]) +/* +** - - - - - - - - - +** i a u P n 0 0 a +** - - - - - - - - - +** +** Precession-nutation, IAU 2000A model: a multi-purpose function, +** supporting classical (equinox-based) use directly and CIO-based +** use indirectly. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsi,deps double nutation (Note 2) +** epsa double mean obliquity (Note 3) +** rb double[3][3] frame bias matrix (Note 4) +** rp double[3][3] precession matrix (Note 5) +** rbp double[3][3] bias-precession matrix (Note 6) +** rn double[3][3] nutation matrix (Note 7) +** rbpn double[3][3] GCRS-to-true matrix (Notes 8,9) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The nutation components (luni-solar + planetary, IAU 2000A) in +** longitude and obliquity are in radians and with respect to the +** equinox and ecliptic of date. Free core nutation is omitted; +** for the utmost accuracy, use the iauPn00 function, where the +** nutation components are caller-specified. For faster but +** slightly less accurate results, use the iauPn00b function. +** +** 3) The mean obliquity is consistent with the IAU 2000 precession. +** +** 4) The matrix rb transforms vectors from GCRS to J2000.0 mean +** equator and equinox by applying frame bias. +** +** 5) The matrix rp transforms vectors from J2000.0 mean equator and +** equinox to mean equator and equinox of date by applying +** precession. +** +** 6) The matrix rbp transforms vectors from GCRS to mean equator and +** equinox of date by applying frame bias then precession. It is +** the product rp x rb. +** +** 7) The matrix rn transforms vectors from mean equator and equinox +** of date to true equator and equinox of date by applying the +** nutation (luni-solar + planetary). +** +** 8) The matrix rbpn transforms vectors from GCRS to true equator and +** equinox of date. It is the product rn x rbp, applying frame +** bias, precession and nutation in that order. +** +** 9) The X,Y,Z coordinates of the IAU 2000A Celestial Intermediate +** Pole are elements (3,1-3) of the GCRS-to-true matrix, +** i.e. rbpn[2][0-2]. +** +** 10) It is permissible to re-use the same array in the returned +** arguments. The arrays are filled in the stated order. +** +** Called: +** iauNut00a nutation, IAU 2000A +** iauPn00 bias/precession/nutation results, IAU 2000 +** +** Reference: +** +** Capitaine, N., Chapront, J., Lambert, S. and Wallace, P., +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Nutation. */ + iauNut00a(date1, date2, dpsi, deps); + +/* Remaining results. */ + iauPn00(date1, date2, *dpsi, *deps, epsa, rb, rp, rbp, rn, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pn00b.c b/src/cpp/3rdparty/sofa/src/pn00b.c new file mode 100644 index 000000000..bf86359fa --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pn00b.c @@ -0,0 +1,213 @@ +#include "sofa.h" + +void iauPn00b(double date1, double date2, + double *dpsi, double *deps, double *epsa, + double rb[3][3], double rp[3][3], double rbp[3][3], + double rn[3][3], double rbpn[3][3]) +/* +** - - - - - - - - - +** i a u P n 0 0 b +** - - - - - - - - - +** +** Precession-nutation, IAU 2000B model: a multi-purpose function, +** supporting classical (equinox-based) use directly and CIO-based +** use indirectly. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsi,deps double nutation (Note 2) +** epsa double mean obliquity (Note 3) +** rb double[3][3] frame bias matrix (Note 4) +** rp double[3][3] precession matrix (Note 5) +** rbp double[3][3] bias-precession matrix (Note 6) +** rn double[3][3] nutation matrix (Note 7) +** rbpn double[3][3] GCRS-to-true matrix (Notes 8,9) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The nutation components (luni-solar + planetary, IAU 2000B) in +** longitude and obliquity are in radians and with respect to the +** equinox and ecliptic of date. For more accurate results, but +** at the cost of increased computation, use the iauPn00a function. +** For the utmost accuracy, use the iauPn00 function, where the +** nutation components are caller-specified. +** +** 3) The mean obliquity is consistent with the IAU 2000 precession. +** +** 4) The matrix rb transforms vectors from GCRS to J2000.0 mean +** equator and equinox by applying frame bias. +** +** 5) The matrix rp transforms vectors from J2000.0 mean equator and +** equinox to mean equator and equinox of date by applying +** precession. +** +** 6) The matrix rbp transforms vectors from GCRS to mean equator and +** equinox of date by applying frame bias then precession. It is +** the product rp x rb. +** +** 7) The matrix rn transforms vectors from mean equator and equinox +** of date to true equator and equinox of date by applying the +** nutation (luni-solar + planetary). +** +** 8) The matrix rbpn transforms vectors from GCRS to true equator and +** equinox of date. It is the product rn x rbp, applying frame +** bias, precession and nutation in that order. +** +** 9) The X,Y,Z coordinates of the IAU 2000B Celestial Intermediate +** Pole are elements (3,1-3) of the GCRS-to-true matrix, +** i.e. rbpn[2][0-2]. +** +** 10) It is permissible to re-use the same array in the returned +** arguments. The arrays are filled in the stated order. +** +** Called: +** iauNut00b nutation, IAU 2000B +** iauPn00 bias/precession/nutation results, IAU 2000 +** +** Reference: +** +** Capitaine, N., Chapront, J., Lambert, S. and Wallace, P., +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003). +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Nutation. */ + iauNut00b(date1, date2, dpsi, deps); + +/* Remaining results. */ + iauPn00(date1, date2, *dpsi, *deps, epsa, rb, rp, rbp, rn, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pn06.c b/src/cpp/3rdparty/sofa/src/pn06.c new file mode 100644 index 000000000..8ac057d19 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pn06.c @@ -0,0 +1,238 @@ +#include "sofa.h" +#include "sofam.h" + +void iauPn06(double date1, double date2, double dpsi, double deps, + double *epsa, + double rb[3][3], double rp[3][3], double rbp[3][3], + double rn[3][3], double rbpn[3][3]) +/* +** - - - - - - - - +** i a u P n 0 6 +** - - - - - - - - +** +** Precession-nutation, IAU 2006 model: a multi-purpose function, +** supporting classical (equinox-based) use directly and CIO-based use +** indirectly. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** dpsi,deps double nutation (Note 2) +** +** Returned: +** epsa double mean obliquity (Note 3) +** rb double[3][3] frame bias matrix (Note 4) +** rp double[3][3] precession matrix (Note 5) +** rbp double[3][3] bias-precession matrix (Note 6) +** rn double[3][3] nutation matrix (Note 7) +** rbpn double[3][3] GCRS-to-true matrix (Notes 8,9) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The caller is responsible for providing the nutation components; +** they are in longitude and obliquity, in radians and are with +** respect to the equinox and ecliptic of date. For high-accuracy +** applications, free core nutation should be included as well as +** any other relevant corrections to the position of the CIP. +** +** 3) The returned mean obliquity is consistent with the IAU 2006 +** precession. +** +** 4) The matrix rb transforms vectors from GCRS to J2000.0 mean +** equator and equinox by applying frame bias. +** +** 5) The matrix rp transforms vectors from J2000.0 mean equator and +** equinox to mean equator and equinox of date by applying +** precession. +** +** 6) The matrix rbp transforms vectors from GCRS to mean equator and +** equinox of date by applying frame bias then precession. It is +** the product rp x rb. +** +** 7) The matrix rn transforms vectors from mean equator and equinox +** of date to true equator and equinox of date by applying the +** nutation (luni-solar + planetary). +** +** 8) The matrix rbpn transforms vectors from GCRS to true equator and +** equinox of date. It is the product rn x rbp, applying frame +** bias, precession and nutation in that order. +** +** 9) The X,Y,Z coordinates of the Celestial Intermediate Pole are +** elements (3,1-3) of the GCRS-to-true matrix, i.e. rbpn[2][0-2]. +** +** 10) It is permissible to re-use the same array in the returned +** arguments. The arrays are filled in the stated order. +** +** Called: +** iauPfw06 bias-precession F-W angles, IAU 2006 +** iauFw2m F-W angles to r-matrix +** iauCr copy r-matrix +** iauTr transpose r-matrix +** iauRxr product of two r-matrices +** +** References: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gamb, phib, psib, eps, r1[3][3], r2[3][3], rt[3][3]; + + +/* Bias-precession Fukushima-Williams angles of J2000.0 = frame bias. */ + iauPfw06(DJM0, DJM00, &gamb, &phib, &psib, &eps); + +/* B matrix. */ + iauFw2m(gamb, phib, psib, eps, r1); + iauCr(r1, rb); + +/* Bias-precession Fukushima-Williams angles of date. */ + iauPfw06(date1, date2, &gamb, &phib, &psib, &eps); + +/* Bias-precession matrix. */ + iauFw2m(gamb, phib, psib, eps, r2); + iauCr(r2, rbp); + +/* Solve for precession matrix. */ + iauTr(r1, rt); + iauRxr(r2, rt, rp); + +/* Equinox-based bias-precession-nutation matrix. */ + iauFw2m(gamb, phib, psib + dpsi, eps + deps, r1); + iauCr(r1, rbpn); + +/* Solve for nutation matrix. */ + iauTr(r2, rt); + iauRxr(r1, rt, rn); + +/* Obliquity, mean of date. */ + *epsa = eps; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pn06a.c b/src/cpp/3rdparty/sofa/src/pn06a.c new file mode 100644 index 000000000..b933ac800 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pn06a.c @@ -0,0 +1,203 @@ +#include "sofa.h" + +void iauPn06a(double date1, double date2, + double *dpsi, double *deps, double *epsa, + double rb[3][3], double rp[3][3], double rbp[3][3], + double rn[3][3], double rbpn[3][3]) +/* +** - - - - - - - - - +** i a u P n 0 6 a +** - - - - - - - - - +** +** Precession-nutation, IAU 2006/2000A models: a multi-purpose function, +** supporting classical (equinox-based) use directly and CIO-based use +** indirectly. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsi,deps double nutation (Note 2) +** epsa double mean obliquity (Note 3) +** rb double[3][3] frame bias matrix (Note 4) +** rp double[3][3] precession matrix (Note 5) +** rbp double[3][3] bias-precession matrix (Note 6) +** rn double[3][3] nutation matrix (Note 7) +** rbpn double[3][3] GCRS-to-true matrix (Notes 8,9) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The nutation components (luni-solar + planetary, IAU 2000A) in +** longitude and obliquity are in radians and with respect to the +** equinox and ecliptic of date. Free core nutation is omitted; +** for the utmost accuracy, use the iauPn06 function, where the +** nutation components are caller-specified. +** +** 3) The mean obliquity is consistent with the IAU 2006 precession. +** +** 4) The matrix rb transforms vectors from GCRS to mean J2000.0 by +** applying frame bias. +** +** 5) The matrix rp transforms vectors from mean J2000.0 to mean of +** date by applying precession. +** +** 6) The matrix rbp transforms vectors from GCRS to mean of date by +** applying frame bias then precession. It is the product rp x rb. +** +** 7) The matrix rn transforms vectors from mean of date to true of +** date by applying the nutation (luni-solar + planetary). +** +** 8) The matrix rbpn transforms vectors from GCRS to true of date +** (CIP/equinox). It is the product rn x rbp, applying frame bias, +** precession and nutation in that order. +** +** 9) The X,Y,Z coordinates of the IAU 2006/2000A Celestial +** Intermediate Pole are elements (3,1-3) of the GCRS-to-true +** matrix, i.e. rbpn[2][0-2]. +** +** 10) It is permissible to re-use the same array in the returned +** arguments. The arrays are filled in the stated order. +** +** Called: +** iauNut06a nutation, IAU 2006/2000A +** iauPn06 bias/precession/nutation results, IAU 2006 +** +** Reference: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Nutation. */ + iauNut06a(date1, date2, dpsi, deps); + +/* Remaining results. */ + iauPn06(date1, date2, *dpsi, *deps, epsa, rb, rp, rbp, rn, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pnm00a.c b/src/cpp/3rdparty/sofa/src/pnm00a.c new file mode 100644 index 000000000..c9be47316 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pnm00a.c @@ -0,0 +1,171 @@ +#include "sofa.h" + +void iauPnm00a(double date1, double date2, double rbpn[3][3]) +/* +** - - - - - - - - - - +** i a u P n m 0 0 a +** - - - - - - - - - - +** +** Form the matrix of precession-nutation for a given date (including +** frame bias), equinox based, IAU 2000A model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rbpn double[3][3] bias-precession-nutation matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(date) = rbpn * V(GCRS), where +** the p-vector V(date) is with respect to the true equatorial triad +** of date date1+date2 and the p-vector V(GCRS) is with respect to +** the Geocentric Celestial Reference System (IAU, 2000). +** +** 3) A faster, but slightly less accurate, result (about 1 mas) can be +** obtained by using instead the iauPnm00b function. +** +** Called: +** iauPn00a bias/precession/nutation, IAU 2000A +** +** Reference: +** +** IAU: Trans. International Astronomical Union, Vol. XXIVB; Proc. +** 24th General Assembly, Manchester, UK. Resolutions B1.3, B1.6. +** (2000) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsi, deps, epsa, rb[3][3], rp[3][3], rbp[3][3], rn[3][3]; + + +/* Obtain the required matrix (discarding other results). */ + iauPn00a(date1, date2, &dpsi, &deps, &epsa, rb, rp, rbp, rn, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pnm00b.c b/src/cpp/3rdparty/sofa/src/pnm00b.c new file mode 100644 index 000000000..757af0f80 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pnm00b.c @@ -0,0 +1,171 @@ +#include "sofa.h" + +void iauPnm00b(double date1, double date2, double rbpn[3][3]) +/* +** - - - - - - - - - - +** i a u P n m 0 0 b +** - - - - - - - - - - +** +** Form the matrix of precession-nutation for a given date (including +** frame bias), equinox-based, IAU 2000B model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rbpn double[3][3] bias-precession-nutation matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(date) = rbpn * V(GCRS), where +** the p-vector V(date) is with respect to the true equatorial triad +** of date date1+date2 and the p-vector V(GCRS) is with respect to +** the Geocentric Celestial Reference System (IAU, 2000). +** +** 3) The present function is faster, but slightly less accurate (about +** 1 mas), than the iauPnm00a function. +** +** Called: +** iauPn00b bias/precession/nutation, IAU 2000B +** +** Reference: +** +** IAU: Trans. International Astronomical Union, Vol. XXIVB; Proc. +** 24th General Assembly, Manchester, UK. Resolutions B1.3, B1.6. +** (2000) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dpsi, deps, epsa, rb[3][3], rp[3][3], rbp[3][3], rn[3][3]; + + +/* Obtain the required matrix (discarding other results). */ + iauPn00b(date1, date2, &dpsi, &deps, &epsa, rb, rp, rbp, rn, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pnm06a.c b/src/cpp/3rdparty/sofa/src/pnm06a.c new file mode 100644 index 000000000..d6b0a0e2a --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pnm06a.c @@ -0,0 +1,175 @@ +#include "sofa.h" + +void iauPnm06a(double date1, double date2, double rbpn[3][3]) +/* +** - - - - - - - - - - +** i a u P n m 0 6 a +** - - - - - - - - - - +** +** Form the matrix of precession-nutation for a given date (including +** frame bias), equinox based, IAU 2006 precession and IAU 2000A +** nutation models. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rbpn double[3][3] bias-precession-nutation matrix (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, among +** others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(date) = rbpn * V(GCRS), where +** the p-vector V(date) is with respect to the true equatorial triad +** of date date1+date2 and the p-vector V(GCRS) is with respect to +** the Geocentric Celestial Reference System (IAU, 2000). +** +** Called: +** iauPfw06 bias-precession F-W angles, IAU 2006 +** iauNut06a nutation, IAU 2006/2000A +** iauFw2m F-W angles to r-matrix +** +** Reference: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double gamb, phib, psib, epsa, dp, de; + + +/* Fukushima-Williams angles for frame bias and precession. */ + iauPfw06(date1, date2, &gamb, &phib, &psib, &epsa); + +/* Nutation components. */ + iauNut06a(date1, date2, &dp, &de); + +/* Equinox based nutation x precession x bias matrix. */ + iauFw2m(gamb, phib, psib + dp, epsa + de, rbpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pnm80.c b/src/cpp/3rdparty/sofa/src/pnm80.c new file mode 100644 index 000000000..77c0dfc43 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pnm80.c @@ -0,0 +1,176 @@ +#include "sofa.h" + +void iauPnm80(double date1, double date2, double rmatpn[3][3]) +/* +** - - - - - - - - - +** i a u P n m 8 0 +** - - - - - - - - - +** +** Form the matrix of precession/nutation for a given date, IAU 1976 +** precession model, IAU 1980 nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** rmatpn double[3][3] combined precession/nutation matrix +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The matrix operates in the sense V(date) = rmatpn * V(J2000), +** where the p-vector V(date) is with respect to the true equatorial +** triad of date date1+date2 and the p-vector V(J2000) is with +** respect to the mean equatorial triad of epoch J2000.0. +** +** Called: +** iauPmat76 precession matrix, IAU 1976 +** iauNutm80 nutation matrix, IAU 1980 +** iauRxr product of two r-matrices +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992), +** Section 3.3 (p145). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rmatp[3][3], rmatn[3][3]; + + +/* Precession matrix, J2000.0 to date. */ + iauPmat76(date1, date2, rmatp); + +/* Nutation matrix. */ + iauNutm80(date1, date2, rmatn); + +/* Combine the matrices: PN = N x P. */ + iauRxr(rmatn, rmatp, rmatpn); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pom00.c b/src/cpp/3rdparty/sofa/src/pom00.c new file mode 100644 index 000000000..e29d35d69 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pom00.c @@ -0,0 +1,165 @@ +#include "sofa.h" + +void iauPom00(double xp, double yp, double sp, double rpom[3][3]) +/* +** - - - - - - - - - - +** i a u P o m 0 0 +** - - - - - - - - - - +** +** Form the matrix of polar motion for a given date, IAU 2000. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** xp,yp double coordinates of the pole (radians, Note 1) +** sp double the TIO locator s' (radians, Note 2) +** +** Returned: +** rpom double[3][3] polar-motion matrix (Note 3) +** +** Notes: +** +** 1) The arguments xp and yp are the coordinates (in radians) of the +** Celestial Intermediate Pole with respect to the International +** Terrestrial Reference System (see IERS Conventions 2003), +** measured along the meridians 0 and 90 deg west respectively. +** +** 2) The argument sp is the TIO locator s', in radians, which +** positions the Terrestrial Intermediate Origin on the equator. It +** is obtained from polar motion observations by numerical +** integration, and so is in essence unpredictable. However, it is +** dominated by a secular drift of about 47 microarcseconds per +** century, and so can be taken into account by using s' = -47*t, +** where t is centuries since J2000.0. The function iauSp00 +** implements this approximation. +** +** 3) The matrix operates in the sense V(TRS) = rpom * V(CIP), meaning +** that it is the final rotation when computing the pointing +** direction to a celestial source. +** +** Called: +** iauIr initialize r-matrix to identity +** iauRz rotate around Z-axis +** iauRy rotate around Y-axis +** iauRx rotate around X-axis +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Construct the matrix. */ + iauIr(rpom); + iauRz(sp, rpom); + iauRy(-xp, rpom); + iauRx(-yp, rpom); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ppp.c b/src/cpp/3rdparty/sofa/src/ppp.c new file mode 100644 index 000000000..1934da372 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ppp.c @@ -0,0 +1,135 @@ +#include "sofa.h" + +void iauPpp(double a[3], double b[3], double apb[3]) +/* +** - - - - - - - +** i a u P p p +** - - - - - - - +** +** P-vector addition. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3] first p-vector +** b double[3] second p-vector +** +** Returned: +** apb double[3] a + b +** +** Note: +** It is permissible to re-use the same array for any of the +** arguments. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + apb[0] = a[0] + b[0]; + apb[1] = a[1] + b[1]; + apb[2] = a[2] + b[2]; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ppsp.c b/src/cpp/3rdparty/sofa/src/ppsp.c new file mode 100644 index 000000000..9c8b1705f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ppsp.c @@ -0,0 +1,144 @@ +#include "sofa.h" + +void iauPpsp(double a[3], double s, double b[3], double apsb[3]) +/* +** - - - - - - - - +** i a u P p s p +** - - - - - - - - +** +** P-vector plus scaled p-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3] first p-vector +** s double scalar (multiplier for b) +** b double[3] second p-vector +** +** Returned: +** apsb double[3] a + s*b +** +** Note: +** It is permissible for any of a, b and apsb to be the same array. +** +** Called: +** iauSxp multiply p-vector by scalar +** iauPpp p-vector plus p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double sb[3]; + + +/* s*b. */ + iauSxp(s, b, sb); + +/* a + s*b. */ + iauPpp(a, sb, apsb); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pr00.c b/src/cpp/3rdparty/sofa/src/pr00.c new file mode 100644 index 000000000..948b884ba --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pr00.c @@ -0,0 +1,193 @@ +#include "sofa.h" +#include "sofam.h" + +void iauPr00(double date1, double date2, double *dpsipr, double *depspr) +/* +** - - - - - - - - +** i a u P r 0 0 +** - - - - - - - - +** +** Precession-rate part of the IAU 2000 precession-nutation models +** (part of MHB2000). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** dpsipr,depspr double precession corrections (Notes 2,3) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The precession adjustments are expressed as "nutation +** components", corrections in longitude and obliquity with respect +** to the J2000.0 equinox and ecliptic. +** +** 3) Although the precession adjustments are stated to be with respect +** to Lieske et al. (1977), the MHB2000 model does not specify which +** set of Euler angles are to be used and how the adjustments are to +** be applied. The most literal and straightforward procedure is to +** adopt the 4-rotation epsilon_0, psi_A, omega_A, xi_A option, and +** to add dpsipr to psi_A and depspr to both omega_A and eps_A. +** +** 4) This is an implementation of one aspect of the IAU 2000A nutation +** model, formally adopted by the IAU General Assembly in 2000, +** namely MHB2000 (Mathews et al. 2002). +** +** References: +** +** Lieske, J.H., Lederle, T., Fricke, W. & Morando, B., "Expressions +** for the precession quantities based upon the IAU (1976) System of +** Astronomical Constants", Astron.Astrophys., 58, 1-16 (1977) +** +** Mathews, P.M., Herring, T.A., Buffet, B.A., "Modeling of nutation +** and precession New nutation series for nonrigid Earth and +** insights into the Earth's interior", J.Geophys.Res., 107, B4, +** 2002. The MHB2000 code itself was obtained on 9th September 2002 +** from ftp://maia.usno.navy.mil/conv2000/chapter5/IAU2000A. +** +** Wallace, P.T., "Software for Implementing the IAU 2000 +** Resolutions", in IERS Workshop 5.1 (2002). +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t; + +/* Precession and obliquity corrections (radians per century) */ + static const double PRECOR = -0.29965 * DAS2R, + OBLCOR = -0.02524 * DAS2R; + + +/* Interval between fundamental epoch J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Precession rate contributions with respect to IAU 1976/80. */ + *dpsipr = PRECOR * t; + *depspr = OBLCOR * t; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/prec76.c b/src/cpp/3rdparty/sofa/src/prec76.c new file mode 100644 index 000000000..49b9addcd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/prec76.c @@ -0,0 +1,199 @@ +#include "sofa.h" +#include "sofam.h" + +void iauPrec76(double date01, double date02, double date11, double date12, + double *zeta, double *z, double *theta) +/* +** - - - - - - - - - - +** i a u P r e c 7 6 +** - - - - - - - - - - +** +** IAU 1976 precession model. +** +** This function forms the three Euler angles which implement general +** precession between two dates, using the IAU 1976 model (as for the +** FK5 catalog). +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date01,date02 double TDB starting date (Note 1) +** date11,date12 double TDB ending date (Note 1) +** +** Returned: +** zeta double 1st rotation: radians cw around z +** z double 3rd rotation: radians cw around z +** theta double 2nd rotation: radians ccw around y +** +** Notes: +** +** 1) The dates date01+date02 and date11+date12 are Julian Dates, +** apportioned in any convenient way between the arguments daten1 +** and daten2. For example, JD(TDB)=2450123.7 could be expressed in +** any of these ways, among others: +** +** daten1 daten2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in cases +** where the loss of several decimal digits of resolution is +** acceptable. The J2000 method is best matched to the way the +** argument is handled internally and will deliver the optimum +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** The two dates may be expressed using different methods, but at +** the risk of losing some resolution. +** +** 2) The accumulated precession angles zeta, z, theta are expressed +** through canonical polynomials which are valid only for a limited +** time span. In addition, the IAU 1976 precession rate is known to +** be imperfect. The absolute accuracy of the present formulation +** is better than 0.1 arcsec from 1960AD to 2040AD, better than +** 1 arcsec from 1640AD to 2360AD, and remains below 3 arcsec for +** the whole of the period 500BC to 3000AD. The errors exceed +** 10 arcsec outside the range 1200BC to 3900AD, exceed 100 arcsec +** outside 4200BC to 5600AD and exceed 1000 arcsec outside 6800BC to +** 8200AD. +** +** 3) The three angles are returned in the conventional order, which +** is not the same as the order of the corresponding Euler +** rotations. The precession matrix is +** R_3(-z) x R_2(+theta) x R_3(-zeta). +** +** Reference: +** +** Lieske, J.H., 1979, Astron.Astrophys. 73, 282, equations +** (6) & (7), p283. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t0, t, tas2r, w; + + +/* Interval between fundamental epoch J2000.0 and start date (JC). */ + t0 = ((date01 - DJ00) + date02) / DJC; + +/* Interval over which precession required (JC). */ + t = ((date11 - date01) + (date12 - date02)) / DJC; + +/* Euler angles. */ + tas2r = t * DAS2R; + w = 2306.2181 + (1.39656 - 0.000139 * t0) * t0; + + *zeta = (w + ((0.30188 - 0.000344 * t0) + 0.017998 * t) * t) * tas2r; + + *z = (w + ((1.09468 + 0.000066 * t0) + 0.018203 * t) * t) * tas2r; + + *theta = ((2004.3109 + (-0.85330 - 0.000217 * t0) * t0) + + ((-0.42665 - 0.000217 * t0) - 0.041833 * t) * t) * tas2r; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pv2p.c b/src/cpp/3rdparty/sofa/src/pv2p.c new file mode 100644 index 000000000..0b61767e7 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pv2p.c @@ -0,0 +1,131 @@ +#include "sofa.h" + +void iauPv2p(double pv[2][3], double p[3]) +/* +** - - - - - - - - +** i a u P v 2 p +** - - - - - - - - +** +** Discard velocity component of a pv-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** pv double[2][3] pv-vector +** +** Returned: +** p double[3] p-vector +** +** Called: +** iauCp copy p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauCp(pv[0], p); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pv2s.c b/src/cpp/3rdparty/sofa/src/pv2s.c new file mode 100644 index 000000000..7d1434f26 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pv2s.c @@ -0,0 +1,194 @@ +#include "sofa.h" + +void iauPv2s(double pv[2][3], + double *theta, double *phi, double *r, + double *td, double *pd, double *rd) +/* +** - - - - - - - - +** i a u P v 2 s +** - - - - - - - - +** +** Convert position/velocity from Cartesian to spherical coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** pv double[2][3] pv-vector +** +** Returned: +** theta double longitude angle (radians) +** phi double latitude angle (radians) +** r double radial distance +** td double rate of change of theta +** pd double rate of change of phi +** rd double rate of change of r +** +** Notes: +** +** 1) If the position part of pv is null, theta, phi, td and pd +** are indeterminate. This is handled by extrapolating the +** position through unit time by using the velocity part of +** pv. This moves the origin without changing the direction +** of the velocity component. If the position and velocity +** components of pv are both null, zeroes are returned for all +** six results. +** +** 2) If the position is a pole, theta, td and pd are indeterminate. +** In such cases zeroes are returned for all three. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y, z, xd, yd, zd, rxy2, rxy, r2, rtrue, rw, xyp; + + +/* Components of position/velocity vector. */ + x = pv[0][0]; + y = pv[0][1]; + z = pv[0][2]; + xd = pv[1][0]; + yd = pv[1][1]; + zd = pv[1][2]; + +/* Component of r in XY plane squared. */ + rxy2 = x*x + y*y; + +/* Modulus squared. */ + r2 = rxy2 + z*z; + +/* Modulus. */ + rtrue = sqrt(r2); + +/* If null vector, move the origin along the direction of movement. */ + rw = rtrue; + if (rtrue == 0.0) { + x = xd; + y = yd; + z = zd; + rxy2 = x*x + y*y; + r2 = rxy2 + z*z; + rw = sqrt(r2); + } + +/* Position and velocity in spherical coordinates. */ + rxy = sqrt(rxy2); + xyp = x*xd + y*yd; + if (rxy2 != 0.0) { + *theta = atan2(y, x); + *phi = atan2(z, rxy); + *td = (x*yd - y*xd) / rxy2; + *pd = (zd*rxy2 - z*xyp) / (r2*rxy); + } else { + *theta = 0.0; + *phi = (z != 0.0) ? atan2(z, rxy) : 0.0; + *td = 0.0; + *pd = 0.0; + } + *r = rtrue; + *rd = (rw != 0.0) ? (xyp + z*zd) / rw : 0.0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvdpv.c b/src/cpp/3rdparty/sofa/src/pvdpv.c new file mode 100644 index 000000000..6cef5e761 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvdpv.c @@ -0,0 +1,152 @@ +#include "sofa.h" + +void iauPvdpv(double a[2][3], double b[2][3], double adb[2]) +/* +** - - - - - - - - - +** i a u P v d p v +** - - - - - - - - - +** +** Inner (=scalar=dot) product of two pv-vectors. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[2][3] first pv-vector +** b double[2][3] second pv-vector +** +** Returned: +** adb double[2] a . b (see note) +** +** Note: +** +** If the position and velocity components of the two pv-vectors are +** ( ap, av ) and ( bp, bv ), the result, a . b, is the pair of +** numbers ( ap . bp , ap . bv + av . bp ). The two numbers are the +** dot-product of the two p-vectors and its derivative. +** +** Called: +** iauPdp scalar product of two p-vectors +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double adbd, addb; + + +/* a . b = constant part of result. */ + adb[0] = iauPdp(a[0], b[0]); + +/* a . bdot */ + adbd = iauPdp(a[0], b[1]); + +/* adot . b */ + addb = iauPdp(a[1], b[0]); + +/* Velocity part of result. */ + adb[1] = adbd + addb; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvm.c b/src/cpp/3rdparty/sofa/src/pvm.c new file mode 100644 index 000000000..cabce009f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvm.c @@ -0,0 +1,136 @@ +#include "sofa.h" + +void iauPvm(double pv[2][3], double *r, double *s) +/* +** - - - - - - - +** i a u P v m +** - - - - - - - +** +** Modulus of pv-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** pv double[2][3] pv-vector +** +** Returned: +** r double modulus of position component +** s double modulus of velocity component +** +** Called: +** iauPm modulus of p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Distance. */ + *r = iauPm(pv[0]); + +/* Speed. */ + *s = iauPm(pv[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvmpv.c b/src/cpp/3rdparty/sofa/src/pvmpv.c new file mode 100644 index 000000000..81328f7dc --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvmpv.c @@ -0,0 +1,137 @@ +#include "sofa.h" + +void iauPvmpv(double a[2][3], double b[2][3], double amb[2][3]) +/* +** - - - - - - - - - +** i a u P v m p v +** - - - - - - - - - +** +** Subtract one pv-vector from another. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[2][3] first pv-vector +** b double[2][3] second pv-vector +** +** Returned: +** amb double[2][3] a - b +** +** Note: +** It is permissible to re-use the same array for any of the +** arguments. +** +** Called: +** iauPmp p-vector minus p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauPmp(a[0], b[0], amb[0]); + iauPmp(a[1], b[1], amb[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvppv.c b/src/cpp/3rdparty/sofa/src/pvppv.c new file mode 100644 index 000000000..7f03f7730 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvppv.c @@ -0,0 +1,137 @@ +#include "sofa.h" + +void iauPvppv(double a[2][3], double b[2][3], double apb[2][3]) +/* +** - - - - - - - - - +** i a u P v p p v +** - - - - - - - - - +** +** Add one pv-vector to another. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[2][3] first pv-vector +** b double[2][3] second pv-vector +** +** Returned: +** apb double[2][3] a + b +** +** Note: +** It is permissible to re-use the same array for any of the +** arguments. +** +** Called: +** iauPpp p-vector plus p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauPpp(a[0], b[0], apb[0]); + iauPpp(a[1], b[1], apb[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvstar.c b/src/cpp/3rdparty/sofa/src/pvstar.c new file mode 100644 index 000000000..dd6262ea7 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvstar.c @@ -0,0 +1,260 @@ +#include "sofa.h" +#include "sofam.h" + +int iauPvstar(double pv[2][3], double *ra, double *dec, + double *pmr, double *pmd, double *px, double *rv) +/* +** - - - - - - - - - - +** i a u P v s t a r +** - - - - - - - - - - +** +** Convert star position+velocity vector to catalog coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given (Note 1): +** pv double[2][3] pv-vector (au, au/day) +** +** Returned (Note 2): +** ra double right ascension (radians) +** dec double declination (radians) +** pmr double RA proper motion (radians/year) +** pmd double Dec proper motion (radians/year) +** px double parallax (arcsec) +** rv double radial velocity (km/s, positive = receding) +** +** Returned (function value): +** int status: +** 0 = OK +** -1 = superluminal speed (Note 5) +** -2 = null position vector +** +** Notes: +** +** 1) The specified pv-vector is the coordinate direction (and its rate +** of change) for the date at which the light leaving the star +** reached the solar-system barycenter. +** +** 2) The star data returned by this function are "observables" for an +** imaginary observer at the solar-system barycenter. Proper motion +** and radial velocity are, strictly, in terms of barycentric +** coordinate time, TCB. For most practical applications, it is +** permissible to neglect the distinction between TCB and ordinary +** "proper" time on Earth (TT/TAI). The result will, as a rule, be +** limited by the intrinsic accuracy of the proper-motion and +** radial-velocity data; moreover, the supplied pv-vector is likely +** to be merely an intermediate result (for example generated by the +** function iauStarpv), so that a change of time unit will cancel +** out overall. +** +** In accordance with normal star-catalog conventions, the object's +** right ascension and declination are freed from the effects of +** secular aberration. The frame, which is aligned to the catalog +** equator and equinox, is Lorentzian and centered on the SSB. +** +** Summarizing, the specified pv-vector is for most stars almost +** identical to the result of applying the standard geometrical +** "space motion" transformation to the catalog data. The +** differences, which are the subject of the Stumpff paper cited +** below, are: +** +** (i) In stars with significant radial velocity and proper motion, +** the constantly changing light-time distorts the apparent proper +** motion. Note that this is a classical, not a relativistic, +** effect. +** +** (ii) The transformation complies with special relativity. +** +** 3) Care is needed with units. The star coordinates are in radians +** and the proper motions in radians per Julian year, but the +** parallax is in arcseconds; the radial velocity is in km/s, but +** the pv-vector result is in au and au/day. +** +** 4) The proper motions are the rate of change of the right ascension +** and declination at the catalog epoch and are in radians per Julian +** year. The RA proper motion is in terms of coordinate angle, not +** true angle, and will thus be numerically larger at high +** declinations. +** +** 5) Straight-line motion at constant speed in the inertial frame is +** assumed. If the speed is greater than or equal to the speed of +** light, the function aborts with an error status. +** +** 6) The inverse transformation is performed by the function iauStarpv. +** +** Called: +** iauPn decompose p-vector into modulus and direction +** iauPdp scalar product of two p-vectors +** iauSxp multiply p-vector by scalar +** iauPmp p-vector minus p-vector +** iauPm modulus of p-vector +** iauPpp p-vector plus p-vector +** iauPv2s pv-vector to spherical +** iauAnp normalize angle into range 0 to 2pi +** +** Reference: +** +** Stumpff, P., 1985, Astron.Astrophys. 144, 232-240. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double r, x[3], vr, ur[3], vt, ut[3], bett, betr, d, w, del, + usr[3], ust[3], a, rad, decd, rd; + + +/* Isolate the radial component of the velocity (au/day, inertial). */ + iauPn(pv[0], &r, x); + vr = iauPdp(x, pv[1]); + iauSxp(vr, x, ur); + +/* Isolate the transverse component of the velocity (au/day, inertial). */ + iauPmp(pv[1], ur, ut); + vt = iauPm(ut); + +/* Special-relativity dimensionless parameters. */ + bett = vt / DC; + betr = vr / DC; + +/* The inertial-to-observed correction terms. */ + d = 1.0 + betr; + w = betr*betr + bett*bett; + if (d == 0.0 || w > 1.0) return -1; + del = - w / (sqrt(1.0-w) + 1.0); + +/* Apply relativistic correction factor to radial velocity component. */ + w = (betr != 0) ? (betr - del) / (betr * d) : 1.0; + iauSxp(w, ur, usr); + +/* Apply relativistic correction factor to tangential velocity */ +/* component. */ + iauSxp(1.0/d, ut, ust); + +/* Combine the two to obtain the observed velocity vector (au/day). */ + iauPpp(usr, ust, pv[1]); + +/* Cartesian to spherical. */ + iauPv2s(pv, &a, dec, &r, &rad, &decd, &rd); + if (r == 0.0) return -2; + +/* Return RA in range 0 to 2pi. */ + *ra = iauAnp(a); + +/* Return proper motions in radians per year. */ + *pmr = rad * DJY; + *pmd = decd * DJY; + +/* Return parallax in arcsec. */ + *px = DR2AS / r; + +/* Return radial velocity in km/s. */ + *rv = 1e-3 * rd * DAU / DAYSEC; + +/* Success. */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvtob.c b/src/cpp/3rdparty/sofa/src/pvtob.c new file mode 100644 index 000000000..1bd4f33b4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvtob.c @@ -0,0 +1,204 @@ +#include "sofa.h" +#include "sofam.h" + +void iauPvtob(double elong, double phi, double hm, + double xp, double yp, double sp, double theta, + double pv[2][3]) +/* +** - - - - - - - - - +** i a u P v t o b +** - - - - - - - - - +** +** Position and velocity of a terrestrial observing station. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** elong double longitude (radians, east +ve, Note 1) +** phi double latitude (geodetic, radians, Note 1) +** hm double height above ref. ellipsoid (geodetic, m) +** xp,yp double coordinates of the pole (radians, Note 2) +** sp double the TIO locator s' (radians, Note 2) +** theta double Earth rotation angle (radians, Note 3) +** +** Returned: +** pv double[2][3] position/velocity vector (m, m/s, CIRS) +** +** Notes: +** +** 1) The terrestrial coordinates are with respect to the WGS84 +** reference ellipsoid. +** +** 2) xp and yp are the coordinates (in radians) of the Celestial +** Intermediate Pole with respect to the International Terrestrial +** Reference System (see IERS Conventions), measured along the +** meridians 0 and 90 deg west respectively. sp is the TIO locator +** s', in radians, which positions the Terrestrial Intermediate +** Origin on the equator. For many applications, xp, yp and +** (especially) sp can be set to zero. +** +** 3) If theta is Greenwich apparent sidereal time instead of Earth +** rotation angle, the result is with respect to the true equator +** and equinox of date, i.e. with the x-axis at the equinox rather +** than the celestial intermediate origin. +** +** 4) The velocity units are meters per UT1 second, not per SI second. +** This is unlikely to have any practical consequences in the modern +** era. +** +** 5) No validation is performed on the arguments. Error cases that +** could lead to arithmetic exceptions are trapped by the iauGd2gc +** function, and the result set to zeros. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Urban, S. & Seidelmann, P. K. (eds), Explanatory Supplement to +** the Astronomical Almanac, 3rd ed., University Science Books +** (2013), Section 7.4.3.3. +** +** Called: +** iauGd2gc geodetic to geocentric transformation +** iauPom00 polar motion matrix +** iauTrxp product of transpose of r-matrix and p-vector +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Earth rotation rate in radians per UT1 second */ + const double OM = 1.00273781191135448 * D2PI / DAYSEC; + + double xyzm[3], rpm[3][3], xyz[3], x, y, z, s, c; + + +/* Geodetic to geocentric transformation (WGS84). */ + (void) iauGd2gc(1, elong, phi, hm, xyzm); + +/* Polar motion and TIO position. */ + iauPom00(xp, yp, sp, rpm); + iauTrxp(rpm, xyzm, xyz); + x = xyz[0]; + y = xyz[1]; + z = xyz[2]; + +/* Functions of ERA. */ + s = sin(theta); + c = cos(theta); + +/* Position. */ + pv[0][0] = c*x - s*y; + pv[0][1] = s*x + c*y; + pv[0][2] = z; + +/* Velocity. */ + pv[1][0] = OM * ( -s*x - c*y ); + pv[1][1] = OM * ( c*x - s*y ); + pv[1][2] = 0.0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvu.c b/src/cpp/3rdparty/sofa/src/pvu.c new file mode 100644 index 000000000..443a50ee5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvu.c @@ -0,0 +1,143 @@ +#include "sofa.h" + +void iauPvu(double dt, double pv[2][3], double upv[2][3]) +/* +** - - - - - - - +** i a u P v u +** - - - - - - - +** +** Update a pv-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** dt double time interval +** pv double[2][3] pv-vector +** +** Returned: +** upv double[2][3] p updated, v unchanged +** +** Notes: +** +** 1) "Update" means "refer the position component of the vector +** to a new date dt time units from the existing date". +** +** 2) The time units of dt must match those of the velocity. +** +** 3) It is permissible for pv and upv to be the same array. +** +** Called: +** iauPpsp p-vector plus scaled p-vector +** iauCp copy p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauPpsp(pv[0], dt, pv[1], upv[0]); + iauCp(pv[1], upv[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvup.c b/src/cpp/3rdparty/sofa/src/pvup.c new file mode 100644 index 000000000..f4f892923 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvup.c @@ -0,0 +1,138 @@ +#include "sofa.h" + +void iauPvup(double dt, double pv[2][3], double p[3]) +/* +** - - - - - - - - +** i a u P v u p +** - - - - - - - - +** +** Update a pv-vector, discarding the velocity component. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** dt double time interval +** pv double[2][3] pv-vector +** +** Returned: +** p double[3] p-vector +** +** Notes: +** +** 1) "Update" means "refer the position component of the vector to a +** new date dt time units from the existing date". +** +** 2) The time units of dt must match those of the velocity. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + p[0] = pv[0][0] + dt * pv[1][0]; + p[1] = pv[0][1] + dt * pv[1][1]; + p[2] = pv[0][2] + dt * pv[1][2]; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pvxpv.c b/src/cpp/3rdparty/sofa/src/pvxpv.c new file mode 100644 index 000000000..e279b8241 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pvxpv.c @@ -0,0 +1,157 @@ +#include "sofa.h" + +void iauPvxpv(double a[2][3], double b[2][3], double axb[2][3]) +/* +** - - - - - - - - - +** i a u P v x p v +** - - - - - - - - - +** +** Outer (=vector=cross) product of two pv-vectors. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[2][3] first pv-vector +** b double[2][3] second pv-vector +** +** Returned: +** axb double[2][3] a x b +** +** Notes: +** +** 1) If the position and velocity components of the two pv-vectors are +** ( ap, av ) and ( bp, bv ), the result, a x b, is the pair of +** vectors ( ap x bp, ap x bv + av x bp ). The two vectors are the +** cross-product of the two p-vectors and its derivative. +** +** 2) It is permissible to re-use the same array for any of the +** arguments. +** +** Called: +** iauCpv copy pv-vector +** iauPxp vector product of two p-vectors +** iauPpp p-vector plus p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double wa[2][3], wb[2][3], axbd[3], adxb[3]; + + +/* Make copies of the inputs. */ + iauCpv(a, wa); + iauCpv(b, wb); + +/* a x b = position part of result. */ + iauPxp(wa[0], wb[0], axb[0]); + +/* a x bdot + adot x b = velocity part of result. */ + iauPxp(wa[0], wb[1], axbd); + iauPxp(wa[1], wb[0], adxb); + iauPpp(axbd, adxb, axb[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/pxp.c b/src/cpp/3rdparty/sofa/src/pxp.c new file mode 100644 index 000000000..159dd4b59 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/pxp.c @@ -0,0 +1,144 @@ +#include "sofa.h" + +void iauPxp(double a[3], double b[3], double axb[3]) +/* +** - - - - - - - +** i a u P x p +** - - - - - - - +** +** p-vector outer (=vector=cross) product. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3] first p-vector +** b double[3] second p-vector +** +** Returned: +** axb double[3] a x b +** +** Note: +** It is permissible to re-use the same array for any of the +** arguments. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double xa, ya, za, xb, yb, zb; + + + xa = a[0]; + ya = a[1]; + za = a[2]; + xb = b[0]; + yb = b[1]; + zb = b[2]; + axb[0] = ya*zb - za*yb; + axb[1] = za*xb - xa*zb; + axb[2] = xa*yb - ya*xb; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/refco.c b/src/cpp/3rdparty/sofa/src/refco.c new file mode 100644 index 000000000..1837fc18b --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/refco.c @@ -0,0 +1,308 @@ +#include "sofa.h" +#include "sofam.h" + +void iauRefco(double phpa, double tc, double rh, double wl, + double *refa, double *refb) +/* +** - - - - - - - - - +** i a u R e f c o +** - - - - - - - - - +** +** Determine the constants A and B in the atmospheric refraction model +** dZ = A tan Z + B tan^3 Z. +** +** Z is the "observed" zenith distance (i.e. affected by refraction) +** and dZ is what to add to Z to give the "topocentric" (i.e. in vacuo) +** zenith distance. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** phpa double pressure at the observer (hPa = millibar) +** tc double ambient temperature at the observer (deg C) +** rh double relative humidity at the observer (range 0-1) +** wl double wavelength (micrometers) +** +** Returned: +** refa double* tan Z coefficient (radians) +** refb double* tan^3 Z coefficient (radians) +** +** Notes: +** +** 1) The model balances speed and accuracy to give good results in +** applications where performance at low altitudes is not paramount. +** Performance is maintained across a range of conditions, and +** applies to both optical/IR and radio. +** +** 2) The model omits the effects of (i) height above sea level (apart +** from the reduced pressure itself), (ii) latitude (i.e. the +** flattening of the Earth), (iii) variations in tropospheric lapse +** rate and (iv) dispersive effects in the radio. +** +** The model was tested using the following range of conditions: +** +** lapse rates 0.0055, 0.0065, 0.0075 deg/meter +** latitudes 0, 25, 50, 75 degrees +** heights 0, 2500, 5000 meters ASL +** pressures mean for height -10% to +5% in steps of 5% +** temperatures -10 deg to +20 deg with respect to 280 deg at SL +** relative humidity 0, 0.5, 1 +** wavelengths 0.4, 0.6, ... 2 micron, + radio +** zenith distances 15, 45, 75 degrees +** +** The accuracy with respect to raytracing through a model +** atmosphere was as follows: +** +** worst RMS +** +** optical/IR 62 mas 8 mas +** radio 319 mas 49 mas +** +** For this particular set of conditions: +** +** lapse rate 0.0065 K/meter +** latitude 50 degrees +** sea level +** pressure 1005 mb +** temperature 280.15 K +** humidity 80% +** wavelength 5740 Angstroms +** +** the results were as follows: +** +** ZD raytrace iauRefco Saastamoinen +** +** 10 10.27 10.27 10.27 +** 20 21.19 21.20 21.19 +** 30 33.61 33.61 33.60 +** 40 48.82 48.83 48.81 +** 45 58.16 58.18 58.16 +** 50 69.28 69.30 69.27 +** 55 82.97 82.99 82.95 +** 60 100.51 100.54 100.50 +** 65 124.23 124.26 124.20 +** 70 158.63 158.68 158.61 +** 72 177.32 177.37 177.31 +** 74 200.35 200.38 200.32 +** 76 229.45 229.43 229.42 +** 78 267.44 267.29 267.41 +** 80 319.13 318.55 319.10 +** +** deg arcsec arcsec arcsec +** +** The values for Saastamoinen's formula (which includes terms +** up to tan^5) are taken from Hohenkerk and Sinclair (1985). +** +** 3) A wl value in the range 0-100 selects the optical/IR case and is +** wavelength in micrometers. Any value outside this range selects +** the radio case. +** +** 4) Outlandish input parameters are silently limited to +** mathematically safe values. Zero pressure is permissible, and +** causes zeroes to be returned. +** +** 5) The algorithm draws on several sources, as follows: +** +** a) The formula for the saturation vapour pressure of water as +** a function of temperature and temperature is taken from +** Equations (A4.5-A4.7) of Gill (1982). +** +** b) The formula for the water vapour pressure, given the +** saturation pressure and the relative humidity, is from +** Crane (1976), Equation (2.5.5). +** +** c) The refractivity of air is a function of temperature, +** total pressure, water-vapour pressure and, in the case +** of optical/IR, wavelength. The formulae for the two cases are +** developed from Hohenkerk & Sinclair (1985) and Rueger (2002). +** The IAG (1999) optical refractivity for dry air is used. +** +** d) The formula for beta, the ratio of the scale height of the +** atmosphere to the geocentric distance of the observer, is +** an adaption of Equation (9) from Stone (1996). The +** adaptations, arrived at empirically, consist of (i) a small +** adjustment to the coefficient and (ii) a humidity term for the +** radio case only. +** +** e) The formulae for the refraction constants as a function of +** n-1 and beta are from Green (1987), Equation (4.31). +** +** References: +** +** Crane, R.K., Meeks, M.L. (ed), "Refraction Effects in the Neutral +** Atmosphere", Methods of Experimental Physics: Astrophysics 12B, +** Academic Press, 1976. +** +** Gill, Adrian E., "Atmosphere-Ocean Dynamics", Academic Press, +** 1982. +** +** Green, R.M., "Spherical Astronomy", Cambridge University Press, +** 1987. +** +** Hohenkerk, C.Y., & Sinclair, A.T., NAO Technical Note No. 63, +** 1985. +** +** IAG Resolutions adopted at the XXIIth General Assembly in +** Birmingham, 1999, Resolution 3. +** +** Rueger, J.M., "Refractive Index Formulae for Electronic Distance +** Measurement with Radio and Millimetre Waves", in Unisurv Report +** S-68, School of Surveying and Spatial Information Systems, +** University of New South Wales, Sydney, Australia, 2002. +** +** Stone, Ronald C., P.A.S.P. 108, 1051-1058, 1996. +** +** This revision: 2021 February 24 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int optic; + double p, t, r, w, ps, pw, tk, wlsq, gamma, beta; + + +/* Decide whether optical/IR or radio case: switch at 100 microns. */ + optic = ( wl <= 100.0 ); + +/* Restrict parameters to safe values. */ + t = gmax ( tc, -150.0 ); + t = gmin ( t, 200.0 ); + p = gmax ( phpa, 0.0 ); + p = gmin ( p, 10000.0 ); + r = gmax ( rh, 0.0 ); + r = gmin ( r, 1.0 ); + w = gmax ( wl, 0.1 ); + w = gmin ( w, 1e6 ); + +/* Water vapour pressure at the observer. */ + if ( p > 0.0 ) { + ps = pow ( 10.0, ( 0.7859 + 0.03477*t ) / + ( 1.0 + 0.00412*t ) ) * + ( 1.0 + p * ( 4.5e-6 + 6e-10*t*t ) ); + pw = r * ps / ( 1.0 - (1.0-r)*ps/p ); + } else { + pw = 0.0; + } + +/* Refractive index minus 1 at the observer. */ + tk = t + 273.15; + if ( optic ) { + wlsq = w * w; + gamma = ( ( 77.53484e-6 + + ( 4.39108e-7 + 3.666e-9/wlsq ) / wlsq ) * p + - 11.2684e-6*pw ) / tk; + } else { + gamma = ( 77.6890e-6*p - ( 6.3938e-6 - 0.375463/tk ) * pw ) / tk; + } + +/* Formula for beta from Stone, with empirical adjustments. */ + beta = 4.4474e-6 * tk; + if ( ! optic ) beta -= 0.0074 * pw * beta; + +/* Refraction constants from Green. */ + *refa = gamma * ( 1.0 - beta ); + *refb = - gamma * ( beta - gamma / 2.0 ); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/rm2v.c b/src/cpp/3rdparty/sofa/src/rm2v.c new file mode 100644 index 000000000..305f7c0d8 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/rm2v.c @@ -0,0 +1,161 @@ +#include "sofa.h" + +void iauRm2v(double r[3][3], double w[3]) +/* +** - - - - - - - - +** i a u R m 2 v +** - - - - - - - - +** +** Express an r-matrix as an r-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** r double[3][3] rotation matrix +** +** Returned: +** w double[3] rotation vector (Note 1) +** +** Notes: +** +** 1) A rotation matrix describes a rotation through some angle about +** some arbitrary axis called the Euler axis. The "rotation vector" +** returned by this function has the same direction as the Euler axis, +** and its magnitude is the angle in radians. (The magnitude and +** direction can be separated by means of the function iauPn.) +** +** 2) If r is null, so is the result. If r is not a rotation matrix +** the result is undefined; r must be proper (i.e. have a positive +** determinant) and real orthogonal (inverse = transpose). +** +** 3) The reference frame rotates clockwise as seen looking along +** the rotation vector from the origin. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y, z, s2, c2, phi, f; + + + x = r[1][2] - r[2][1]; + y = r[2][0] - r[0][2]; + z = r[0][1] - r[1][0]; + s2 = sqrt(x*x + y*y + z*z); + if (s2 > 0) { + c2 = r[0][0] + r[1][1] + r[2][2] - 1.0; + phi = atan2(s2, c2); + f = phi / s2; + w[0] = x * f; + w[1] = y * f; + w[2] = z * f; + } else { + w[0] = 0.0; + w[1] = 0.0; + w[2] = 0.0; + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/rv2m.c b/src/cpp/3rdparty/sofa/src/rv2m.c new file mode 100644 index 000000000..d41088f89 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/rv2m.c @@ -0,0 +1,168 @@ +#include "sofa.h" + +void iauRv2m(double w[3], double r[3][3]) +/* +** - - - - - - - - +** i a u R v 2 m +** - - - - - - - - +** +** Form the r-matrix corresponding to a given r-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** w double[3] rotation vector (Note 1) +** +** Returned: +** r double[3][3] rotation matrix +** +** Notes: +** +** 1) A rotation matrix describes a rotation through some angle about +** some arbitrary axis called the Euler axis. The "rotation vector" +** supplied to This function has the same direction as the Euler +** axis, and its magnitude is the angle in radians. +** +** 2) If w is null, the identity matrix is returned. +** +** 3) The reference frame rotates clockwise as seen looking along the +** rotation vector from the origin. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y, z, phi, s, c, f; + + +/* Euler angle (magnitude of rotation vector) and functions. */ + x = w[0]; + y = w[1]; + z = w[2]; + phi = sqrt(x*x + y*y + z*z); + s = sin(phi); + c = cos(phi); + f = 1.0 - c; + +/* Euler axis (direction of rotation vector), perhaps null. */ + if (phi > 0.0) { + x /= phi; + y /= phi; + z /= phi; + } + +/* Form the rotation matrix. */ + r[0][0] = x*x*f + c; + r[0][1] = x*y*f + z*s; + r[0][2] = x*z*f - y*s; + r[1][0] = y*x*f - z*s; + r[1][1] = y*y*f + c; + r[1][2] = y*z*f + x*s; + r[2][0] = z*x*f + y*s; + r[2][1] = z*y*f - x*s; + r[2][2] = z*z*f + c; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/rx.c b/src/cpp/3rdparty/sofa/src/rx.c new file mode 100644 index 000000000..699f14373 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/rx.c @@ -0,0 +1,160 @@ +#include "sofa.h" + +void iauRx(double phi, double r[3][3]) +/* +** - - - - - - +** i a u R x +** - - - - - - +** +** Rotate an r-matrix about the x-axis. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** phi double angle (radians) +** +** Given and returned: +** r double[3][3] r-matrix, rotated +** +** Notes: +** +** 1) Calling this function with positive phi incorporates in the +** supplied r-matrix r an additional rotation, about the x-axis, +** anticlockwise as seen looking towards the origin from positive x. +** +** 2) The additional rotation can be represented by this matrix: +** +** ( 1 0 0 ) +** ( ) +** ( 0 + cos(phi) + sin(phi) ) +** ( ) +** ( 0 - sin(phi) + cos(phi) ) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double s, c, a10, a11, a12, a20, a21, a22; + + + s = sin(phi); + c = cos(phi); + + a10 = c*r[1][0] + s*r[2][0]; + a11 = c*r[1][1] + s*r[2][1]; + a12 = c*r[1][2] + s*r[2][2]; + a20 = - s*r[1][0] + c*r[2][0]; + a21 = - s*r[1][1] + c*r[2][1]; + a22 = - s*r[1][2] + c*r[2][2]; + + r[1][0] = a10; + r[1][1] = a11; + r[1][2] = a12; + r[2][0] = a20; + r[2][1] = a21; + r[2][2] = a22; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/rxp.c b/src/cpp/3rdparty/sofa/src/rxp.c new file mode 100644 index 000000000..f91d15507 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/rxp.c @@ -0,0 +1,149 @@ +#include "sofa.h" + +void iauRxp(double r[3][3], double p[3], double rp[3]) +/* +** - - - - - - - +** i a u R x p +** - - - - - - - +** +** Multiply a p-vector by an r-matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** r double[3][3] r-matrix +** p double[3] p-vector +** +** Returned: +** rp double[3] r * p +** +** Note: +** It is permissible for p and rp to be the same array. +** +** Called: +** iauCp copy p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double w, wrp[3]; + int i, j; + + +/* Matrix r * vector p. */ + for (j = 0; j < 3; j++) { + w = 0.0; + for (i = 0; i < 3; i++) { + w += r[j][i] * p[i]; + } + wrp[j] = w; + } + +/* Return the result. */ + iauCp(wrp, rp); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/rxpv.c b/src/cpp/3rdparty/sofa/src/rxpv.c new file mode 100644 index 000000000..35438ecfc --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/rxpv.c @@ -0,0 +1,142 @@ +#include "sofa.h" + +void iauRxpv(double r[3][3], double pv[2][3], double rpv[2][3]) +/* +** - - - - - - - - +** i a u R x p v +** - - - - - - - - +** +** Multiply a pv-vector by an r-matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** r double[3][3] r-matrix +** pv double[2][3] pv-vector +** +** Returned: +** rpv double[2][3] r * pv +** +** Notes: +** +** 1) The algorithm is for the simple case where the r-matrix r is not +** a function of time. The case where r is a function of time leads +** to an additional velocity component equal to the product of the +** derivative of r and the position vector. +** +** 2) It is permissible for pv and rpv to be the same array. +** +** Called: +** iauRxp product of r-matrix and p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauRxp(r, pv[0], rpv[0]); + iauRxp(r, pv[1], rpv[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/rxr.c b/src/cpp/3rdparty/sofa/src/rxr.c new file mode 100644 index 000000000..cba6d4231 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/rxr.c @@ -0,0 +1,149 @@ +#include "sofa.h" + +void iauRxr(double a[3][3], double b[3][3], double atb[3][3]) +/* +** - - - - - - - +** i a u R x r +** - - - - - - - +** +** Multiply two r-matrices. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3][3] first r-matrix +** b double[3][3] second r-matrix +** +** Returned: +** atb double[3][3] a * b +** +** Note: +** It is permissible to re-use the same array for any of the +** arguments. +** +** Called: +** iauCr copy r-matrix +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int i, j, k; + double w, wm[3][3]; + + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + w = 0.0; + for (k = 0; k < 3; k++) { + w += a[i][k] * b[k][j]; + } + wm[i][j] = w; + } + } + iauCr(wm, atb); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ry.c b/src/cpp/3rdparty/sofa/src/ry.c new file mode 100644 index 000000000..f7d8f1d65 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ry.c @@ -0,0 +1,160 @@ +#include "sofa.h" + +void iauRy(double theta, double r[3][3]) +/* +** - - - - - - +** i a u R y +** - - - - - - +** +** Rotate an r-matrix about the y-axis. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** theta double angle (radians) +** +** Given and returned: +** r double[3][3] r-matrix, rotated +** +** Notes: +** +** 1) Calling this function with positive theta incorporates in the +** supplied r-matrix r an additional rotation, about the y-axis, +** anticlockwise as seen looking towards the origin from positive y. +** +** 2) The additional rotation can be represented by this matrix: +** +** ( + cos(theta) 0 - sin(theta) ) +** ( ) +** ( 0 1 0 ) +** ( ) +** ( + sin(theta) 0 + cos(theta) ) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double s, c, a00, a01, a02, a20, a21, a22; + + + s = sin(theta); + c = cos(theta); + + a00 = c*r[0][0] - s*r[2][0]; + a01 = c*r[0][1] - s*r[2][1]; + a02 = c*r[0][2] - s*r[2][2]; + a20 = s*r[0][0] + c*r[2][0]; + a21 = s*r[0][1] + c*r[2][1]; + a22 = s*r[0][2] + c*r[2][2]; + + r[0][0] = a00; + r[0][1] = a01; + r[0][2] = a02; + r[2][0] = a20; + r[2][1] = a21; + r[2][2] = a22; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/rz.c b/src/cpp/3rdparty/sofa/src/rz.c new file mode 100644 index 000000000..08f41513d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/rz.c @@ -0,0 +1,160 @@ +#include "sofa.h" + +void iauRz(double psi, double r[3][3]) +/* +** - - - - - - +** i a u R z +** - - - - - - +** +** Rotate an r-matrix about the z-axis. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** psi double angle (radians) +** +** Given and returned: +** r double[3][3] r-matrix, rotated +** +** Notes: +** +** 1) Calling this function with positive psi incorporates in the +** supplied r-matrix r an additional rotation, about the z-axis, +** anticlockwise as seen looking towards the origin from positive z. +** +** 2) The additional rotation can be represented by this matrix: +** +** ( + cos(psi) + sin(psi) 0 ) +** ( ) +** ( - sin(psi) + cos(psi) 0 ) +** ( ) +** ( 0 0 1 ) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double s, c, a00, a01, a02, a10, a11, a12; + + + s = sin(psi); + c = cos(psi); + + a00 = c*r[0][0] + s*r[1][0]; + a01 = c*r[0][1] + s*r[1][1]; + a02 = c*r[0][2] + s*r[1][2]; + a10 = - s*r[0][0] + c*r[1][0]; + a11 = - s*r[0][1] + c*r[1][1]; + a12 = - s*r[0][2] + c*r[1][2]; + + r[0][0] = a00; + r[0][1] = a01; + r[0][2] = a02; + r[1][0] = a10; + r[1][1] = a11; + r[1][2] = a12; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s00.c b/src/cpp/3rdparty/sofa/src/s00.c new file mode 100644 index 000000000..dc116144c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s00.c @@ -0,0 +1,424 @@ +#include "sofa.h" +#include "sofam.h" + +double iauS00(double date1, double date2, double x, double y) +/* +** - - - - - - - +** i a u S 0 0 +** - - - - - - - +** +** The CIO locator s, positioning the Celestial Intermediate Origin on +** the equator of the Celestial Intermediate Pole, given the CIP's X,Y +** coordinates. Compatible with IAU 2000A precession-nutation. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** x,y double CIP coordinates (Note 3) +** +** Returned (function value): +** double the CIO locator s in radians (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The CIO locator s is the difference between the right ascensions +** of the same point in two systems: the two systems are the GCRS +** and the CIP,CIO, and the point is the ascending node of the +** CIP equator. The quantity s remains below 0.1 arcsecond +** throughout 1900-2100. +** +** 3) The series used to compute s is in fact for s+XY/2, where X and Y +** are the x and y components of the CIP unit vector; this series +** is more compact than a direct series for s would be. This +** function requires X,Y to be supplied by the caller, who is +** responsible for providing values that are consistent with the +** supplied date. +** +** 4) The model is consistent with the IAU 2000A precession-nutation. +** +** Called: +** iauFal03 mean anomaly of the Moon +** iauFalp03 mean anomaly of the Sun +** iauFaf03 mean argument of the latitude of the Moon +** iauFad03 mean elongation of the Moon from the Sun +** iauFaom03 mean longitude of the Moon's ascending node +** iauFave03 mean longitude of Venus +** iauFae03 mean longitude of Earth +** iauFapa03 general accumulated precession in longitude +** +** References: +** +** Capitaine, N., Chapront, J., Lambert, S. and Wallace, P., +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Time since J2000.0, in Julian centuries */ + double t; + +/* Miscellaneous */ + int i, j; + double a, w0, w1, w2, w3, w4, w5; + +/* Fundamental arguments */ + double fa[8]; + +/* Returned value */ + double s; + +/* --------------------- */ +/* The series for s+XY/2 */ +/* --------------------- */ + + typedef struct { + int nfa[8]; /* coefficients of l,l',F,D,Om,LVe,LE,pA */ + double s, c; /* sine and cosine coefficients */ + } TERM; + +/* Polynomial coefficients */ + static const double sp[] = { + + /* 1-6 */ + 94.00e-6, + 3808.35e-6, + -119.94e-6, + -72574.09e-6, + 27.70e-6, + 15.61e-6 + }; + +/* Terms of order t^0 */ + static const TERM s0[] = { + + /* 1-10 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, -2640.73e-6, 0.39e-6 }, + {{ 0, 0, 0, 0, 2, 0, 0, 0}, -63.53e-6, 0.02e-6 }, + {{ 0, 0, 2, -2, 3, 0, 0, 0}, -11.75e-6, -0.01e-6 }, + {{ 0, 0, 2, -2, 1, 0, 0, 0}, -11.21e-6, -0.01e-6 }, + {{ 0, 0, 2, -2, 2, 0, 0, 0}, 4.57e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 3, 0, 0, 0}, -2.02e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 1, 0, 0, 0}, -1.98e-6, 0.00e-6 }, + {{ 0, 0, 0, 0, 3, 0, 0, 0}, 1.72e-6, 0.00e-6 }, + {{ 0, 1, 0, 0, 1, 0, 0, 0}, 1.41e-6, 0.01e-6 }, + {{ 0, 1, 0, 0, -1, 0, 0, 0}, 1.26e-6, 0.01e-6 }, + + /* 11-20 */ + {{ 1, 0, 0, 0, -1, 0, 0, 0}, 0.63e-6, 0.00e-6 }, + {{ 1, 0, 0, 0, 1, 0, 0, 0}, 0.63e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 3, 0, 0, 0}, -0.46e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 1, 0, 0, 0}, -0.45e-6, 0.00e-6 }, + {{ 0, 0, 4, -4, 4, 0, 0, 0}, -0.36e-6, 0.00e-6 }, + {{ 0, 0, 1, -1, 1, -8, 12, 0}, 0.24e-6, 0.12e-6 }, + {{ 0, 0, 2, 0, 0, 0, 0, 0}, -0.32e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 2, 0, 0, 0}, -0.28e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 3, 0, 0, 0}, -0.27e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 1, 0, 0, 0}, -0.26e-6, 0.00e-6 }, + + /* 21-30 */ + {{ 0, 0, 2, -2, 0, 0, 0, 0}, 0.21e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -3, 0, 0, 0}, -0.19e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -1, 0, 0, 0}, -0.18e-6, 0.00e-6 }, + {{ 0, 0, 0, 0, 0, 8,-13, -1}, 0.10e-6, -0.05e-6 }, + {{ 0, 0, 0, 2, 0, 0, 0, 0}, -0.15e-6, 0.00e-6 }, + {{ 2, 0, -2, 0, -1, 0, 0, 0}, 0.14e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 2, 0, 0, 0}, 0.14e-6, 0.00e-6 }, + {{ 1, 0, 0, -2, 1, 0, 0, 0}, -0.14e-6, 0.00e-6 }, + {{ 1, 0, 0, -2, -1, 0, 0, 0}, -0.14e-6, 0.00e-6 }, + {{ 0, 0, 4, -2, 4, 0, 0, 0}, -0.13e-6, 0.00e-6 }, + + /* 31-33 */ + {{ 0, 0, 2, -2, 4, 0, 0, 0}, 0.11e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -3, 0, 0, 0}, -0.11e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -1, 0, 0, 0}, -0.11e-6, 0.00e-6 } + }; + +/* Terms of order t^1 */ + static const TERM s1[] ={ + + /* 1-3 */ + {{ 0, 0, 0, 0, 2, 0, 0, 0}, -0.07e-6, 3.57e-6 }, + {{ 0, 0, 0, 0, 1, 0, 0, 0}, 1.71e-6, -0.03e-6 }, + {{ 0, 0, 2, -2, 3, 0, 0, 0}, 0.00e-6, 0.48e-6 } + }; + +/* Terms of order t^2 */ + static const TERM s2[] ={ + + /* 1-10 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, 743.53e-6, -0.17e-6 }, + {{ 0, 0, 2, -2, 2, 0, 0, 0}, 56.91e-6, 0.06e-6 }, + {{ 0, 0, 2, 0, 2, 0, 0, 0}, 9.84e-6, -0.01e-6 }, + {{ 0, 0, 0, 0, 2, 0, 0, 0}, -8.85e-6, 0.01e-6 }, + {{ 0, 1, 0, 0, 0, 0, 0, 0}, -6.38e-6, -0.05e-6 }, + {{ 1, 0, 0, 0, 0, 0, 0, 0}, -3.07e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 2, 0, 0, 0}, 2.23e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 1, 0, 0, 0}, 1.67e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 2, 0, 0, 0}, 1.30e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -2, 0, 0, 0}, 0.93e-6, 0.00e-6 }, + + /* 11-20 */ + {{ 1, 0, 0, -2, 0, 0, 0, 0}, 0.68e-6, 0.00e-6 }, + {{ 0, 0, 2, -2, 1, 0, 0, 0}, -0.55e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -2, 0, 0, 0}, 0.53e-6, 0.00e-6 }, + {{ 0, 0, 0, 2, 0, 0, 0, 0}, -0.27e-6, 0.00e-6 }, + {{ 1, 0, 0, 0, 1, 0, 0, 0}, -0.27e-6, 0.00e-6 }, + {{ 1, 0, -2, -2, -2, 0, 0, 0}, -0.26e-6, 0.00e-6 }, + {{ 1, 0, 0, 0, -1, 0, 0, 0}, -0.25e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 1, 0, 0, 0}, 0.22e-6, 0.00e-6 }, + {{ 2, 0, 0, -2, 0, 0, 0, 0}, -0.21e-6, 0.00e-6 }, + {{ 2, 0, -2, 0, -1, 0, 0, 0}, 0.20e-6, 0.00e-6 }, + + /* 21-25 */ + {{ 0, 0, 2, 2, 2, 0, 0, 0}, 0.17e-6, 0.00e-6 }, + {{ 2, 0, 2, 0, 2, 0, 0, 0}, 0.13e-6, 0.00e-6 }, + {{ 2, 0, 0, 0, 0, 0, 0, 0}, -0.13e-6, 0.00e-6 }, + {{ 1, 0, 2, -2, 2, 0, 0, 0}, -0.12e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 0, 0, 0, 0}, -0.11e-6, 0.00e-6 } + }; + +/* Terms of order t^3 */ + static const TERM s3[] ={ + + /* 1-4 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, 0.30e-6, -23.51e-6 }, + {{ 0, 0, 2, -2, 2, 0, 0, 0}, -0.03e-6, -1.39e-6 }, + {{ 0, 0, 2, 0, 2, 0, 0, 0}, -0.01e-6, -0.24e-6 }, + {{ 0, 0, 0, 0, 2, 0, 0, 0}, 0.00e-6, 0.22e-6 } + }; + +/* Terms of order t^4 */ + static const TERM s4[] ={ + + /* 1-1 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, -0.26e-6, -0.01e-6 } + }; + +/* Number of terms in the series */ + const int NS0 = (int) (sizeof s0 / sizeof (TERM)); + const int NS1 = (int) (sizeof s1 / sizeof (TERM)); + const int NS2 = (int) (sizeof s2 / sizeof (TERM)); + const int NS3 = (int) (sizeof s3 / sizeof (TERM)); + const int NS4 = (int) (sizeof s4 / sizeof (TERM)); + +/* ------------------------------------------------------------------ */ + +/* Interval between fundamental epoch J2000.0 and current date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Fundamental Arguments (from IERS Conventions 2003) */ + +/* Mean anomaly of the Moon. */ + fa[0] = iauFal03(t); + +/* Mean anomaly of the Sun. */ + fa[1] = iauFalp03(t); + +/* Mean longitude of the Moon minus that of the ascending node. */ + fa[2] = iauFaf03(t); + +/* Mean elongation of the Moon from the Sun. */ + fa[3] = iauFad03(t); + +/* Mean longitude of the ascending node of the Moon. */ + fa[4] = iauFaom03(t); + +/* Mean longitude of Venus. */ + fa[5] = iauFave03(t); + +/* Mean longitude of Earth. */ + fa[6] = iauFae03(t); + +/* General precession in longitude. */ + fa[7] = iauFapa03(t); + +/* Evaluate s. */ + w0 = sp[0]; + w1 = sp[1]; + w2 = sp[2]; + w3 = sp[3]; + w4 = sp[4]; + w5 = sp[5]; + + for (i = NS0-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s0[i].nfa[j] * fa[j]; + } + w0 += s0[i].s * sin(a) + s0[i].c * cos(a); + } + + for (i = NS1-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s1[i].nfa[j] * fa[j]; + } + w1 += s1[i].s * sin(a) + s1[i].c * cos(a); + } + + for (i = NS2-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s2[i].nfa[j] * fa[j]; + } + w2 += s2[i].s * sin(a) + s2[i].c * cos(a); + } + + for (i = NS3-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s3[i].nfa[j] * fa[j]; + } + w3 += s3[i].s * sin(a) + s3[i].c * cos(a); + } + + for (i = NS4-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s4[i].nfa[j] * fa[j]; + } + w4 += s4[i].s * sin(a) + s4[i].c * cos(a); + } + + s = (w0 + + (w1 + + (w2 + + (w3 + + (w4 + + w5 * t) * t) * t) * t) * t) * DAS2R - x*y/2.0; + + return s; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s00a.c b/src/cpp/3rdparty/sofa/src/s00a.c new file mode 100644 index 000000000..d008dc36d --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s00a.c @@ -0,0 +1,195 @@ +#include "sofa.h" + +double iauS00a(double date1, double date2) +/* +** - - - - - - - - +** i a u S 0 0 a +** - - - - - - - - +** +** The CIO locator s, positioning the Celestial Intermediate Origin on +** the equator of the Celestial Intermediate Pole, using the IAU 2000A +** precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double the CIO locator s in radians (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The CIO locator s is the difference between the right ascensions +** of the same point in two systems. The two systems are the GCRS +** and the CIP,CIO, and the point is the ascending node of the +** CIP equator. The CIO locator s remains a small fraction of +** 1 arcsecond throughout 1900-2100. +** +** 3) The series used to compute s is in fact for s+XY/2, where X and Y +** are the x and y components of the CIP unit vector; this series +** is more compact than a direct series for s would be. The present +** function uses the full IAU 2000A nutation model when predicting +** the CIP position. Faster results, with no significant loss of +** accuracy, can be obtained via the function iauS00b, which uses +** instead the IAU 2000B truncated model. +** +** Called: +** iauPnm00a classical NPB matrix, IAU 2000A +** iauBnp2xy extract CIP X,Y from the BPN matrix +** iauS00 the CIO locator s, given X,Y, IAU 2000A +** +** References: +** +** Capitaine, N., Chapront, J., Lambert, S. and Wallace, P., +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3], x, y, s; + + +/* Bias-precession-nutation-matrix, IAU 2000A. */ + iauPnm00a(date1, date2, rbpn); + +/* Extract the CIP coordinates. */ + iauBpn2xy(rbpn, &x, &y); + +/* Compute the CIO locator s, given the CIP coordinates. */ + s = iauS00(date1, date2, x, y); + + return s; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s00b.c b/src/cpp/3rdparty/sofa/src/s00b.c new file mode 100644 index 000000000..f59aa4b67 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s00b.c @@ -0,0 +1,195 @@ +#include "sofa.h" + +double iauS00b(double date1, double date2) +/* +** - - - - - - - - +** i a u S 0 0 b +** - - - - - - - - +** +** The CIO locator s, positioning the Celestial Intermediate Origin on +** the equator of the Celestial Intermediate Pole, using the IAU 2000B +** precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double the CIO locator s in radians (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The CIO locator s is the difference between the right ascensions +** of the same point in two systems. The two systems are the GCRS +** and the CIP,CIO, and the point is the ascending node of the +** CIP equator. The CIO locator s remains a small fraction of +** 1 arcsecond throughout 1900-2100. +** +** 3) The series used to compute s is in fact for s+XY/2, where X and Y +** are the x and y components of the CIP unit vector; this series +** is more compact than a direct series for s would be. The present +** function uses the IAU 2000B truncated nutation model when +** predicting the CIP position. The function iauS00a uses instead +** the full IAU 2000A model, but with no significant increase in +** accuracy and at some cost in speed. +** +** Called: +** iauPnm00b classical NPB matrix, IAU 2000B +** iauBnp2xy extract CIP X,Y from the BPN matrix +** iauS00 the CIO locator s, given X,Y, IAU 2000A +** +** References: +** +** Capitaine, N., Chapront, J., Lambert, S. and Wallace, P., +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3], x, y, s; + + +/* Bias-precession-nutation-matrix, IAU 2000B. */ + iauPnm00b(date1, date2, rbpn); + +/* Extract the CIP coordinates. */ + iauBpn2xy(rbpn, &x, &y); + +/* Compute the CIO locator s, given the CIP coordinates. */ + s = iauS00(date1, date2, x, y); + + return s; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s06.c b/src/cpp/3rdparty/sofa/src/s06.c new file mode 100644 index 000000000..143fc2cd6 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s06.c @@ -0,0 +1,421 @@ +#include "sofa.h" +#include "sofam.h" + +double iauS06(double date1, double date2, double x, double y) +/* +** - - - - - - - +** i a u S 0 6 +** - - - - - - - +** +** The CIO locator s, positioning the Celestial Intermediate Origin on +** the equator of the Celestial Intermediate Pole, given the CIP's X,Y +** coordinates. Compatible with IAU 2006/2000A precession-nutation. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** x,y double CIP coordinates (Note 3) +** +** Returned (function value): +** double the CIO locator s in radians (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The CIO locator s is the difference between the right ascensions +** of the same point in two systems: the two systems are the GCRS +** and the CIP,CIO, and the point is the ascending node of the +** CIP equator. The quantity s remains below 0.1 arcsecond +** throughout 1900-2100. +** +** 3) The series used to compute s is in fact for s+XY/2, where X and Y +** are the x and y components of the CIP unit vector; this series +** is more compact than a direct series for s would be. This +** function requires X,Y to be supplied by the caller, who is +** responsible for providing values that are consistent with the +** supplied date. +** +** 4) The model is consistent with the "P03" precession (Capitaine et +** al. 2003), adopted by IAU 2006 Resolution 1, 2006, and the +** IAU 2000A nutation (with P03 adjustments). +** +** Called: +** iauFal03 mean anomaly of the Moon +** iauFalp03 mean anomaly of the Sun +** iauFaf03 mean argument of the latitude of the Moon +** iauFad03 mean elongation of the Moon from the Sun +** iauFaom03 mean longitude of the Moon's ascending node +** iauFave03 mean longitude of Venus +** iauFae03 mean longitude of Earth +** iauFapa03 general accumulated precession in longitude +** +** References: +** +** Capitaine, N., Wallace, P.T. & Chapront, J., 2003, Astron. +** Astrophys. 432, 355 +** +** McCarthy, D.D., Petit, G. (eds.) 2004, IERS Conventions (2003), +** IERS Technical Note No. 32, BKG +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Time since J2000.0, in Julian centuries */ + double t; + +/* Miscellaneous */ + int i, j; + double a, w0, w1, w2, w3, w4, w5; + +/* Fundamental arguments */ + double fa[8]; + +/* Returned value */ + double s; + +/* --------------------- */ +/* The series for s+XY/2 */ +/* --------------------- */ + + typedef struct { + int nfa[8]; /* coefficients of l,l',F,D,Om,LVe,LE,pA */ + double s, c; /* sine and cosine coefficients */ + } TERM; + +/* Polynomial coefficients */ + static const double sp[] = { + + /* 1-6 */ + 94.00e-6, + 3808.65e-6, + -122.68e-6, + -72574.11e-6, + 27.98e-6, + 15.62e-6 + }; + +/* Terms of order t^0 */ + static const TERM s0[] = { + + /* 1-10 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, -2640.73e-6, 0.39e-6 }, + {{ 0, 0, 0, 0, 2, 0, 0, 0}, -63.53e-6, 0.02e-6 }, + {{ 0, 0, 2, -2, 3, 0, 0, 0}, -11.75e-6, -0.01e-6 }, + {{ 0, 0, 2, -2, 1, 0, 0, 0}, -11.21e-6, -0.01e-6 }, + {{ 0, 0, 2, -2, 2, 0, 0, 0}, 4.57e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 3, 0, 0, 0}, -2.02e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 1, 0, 0, 0}, -1.98e-6, 0.00e-6 }, + {{ 0, 0, 0, 0, 3, 0, 0, 0}, 1.72e-6, 0.00e-6 }, + {{ 0, 1, 0, 0, 1, 0, 0, 0}, 1.41e-6, 0.01e-6 }, + {{ 0, 1, 0, 0, -1, 0, 0, 0}, 1.26e-6, 0.01e-6 }, + + /* 11-20 */ + {{ 1, 0, 0, 0, -1, 0, 0, 0}, 0.63e-6, 0.00e-6 }, + {{ 1, 0, 0, 0, 1, 0, 0, 0}, 0.63e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 3, 0, 0, 0}, -0.46e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 1, 0, 0, 0}, -0.45e-6, 0.00e-6 }, + {{ 0, 0, 4, -4, 4, 0, 0, 0}, -0.36e-6, 0.00e-6 }, + {{ 0, 0, 1, -1, 1, -8, 12, 0}, 0.24e-6, 0.12e-6 }, + {{ 0, 0, 2, 0, 0, 0, 0, 0}, -0.32e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 2, 0, 0, 0}, -0.28e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 3, 0, 0, 0}, -0.27e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 1, 0, 0, 0}, -0.26e-6, 0.00e-6 }, + + /* 21-30 */ + {{ 0, 0, 2, -2, 0, 0, 0, 0}, 0.21e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -3, 0, 0, 0}, -0.19e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -1, 0, 0, 0}, -0.18e-6, 0.00e-6 }, + {{ 0, 0, 0, 0, 0, 8,-13, -1}, 0.10e-6, -0.05e-6 }, + {{ 0, 0, 0, 2, 0, 0, 0, 0}, -0.15e-6, 0.00e-6 }, + {{ 2, 0, -2, 0, -1, 0, 0, 0}, 0.14e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 2, 0, 0, 0}, 0.14e-6, 0.00e-6 }, + {{ 1, 0, 0, -2, 1, 0, 0, 0}, -0.14e-6, 0.00e-6 }, + {{ 1, 0, 0, -2, -1, 0, 0, 0}, -0.14e-6, 0.00e-6 }, + {{ 0, 0, 4, -2, 4, 0, 0, 0}, -0.13e-6, 0.00e-6 }, + + /* 31-33 */ + {{ 0, 0, 2, -2, 4, 0, 0, 0}, 0.11e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -3, 0, 0, 0}, -0.11e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -1, 0, 0, 0}, -0.11e-6, 0.00e-6 } + }; + +/* Terms of order t^1 */ + static const TERM s1[] = { + + /* 1 - 3 */ + {{ 0, 0, 0, 0, 2, 0, 0, 0}, -0.07e-6, 3.57e-6 }, + {{ 0, 0, 0, 0, 1, 0, 0, 0}, 1.73e-6, -0.03e-6 }, + {{ 0, 0, 2, -2, 3, 0, 0, 0}, 0.00e-6, 0.48e-6 } + }; + +/* Terms of order t^2 */ + static const TERM s2[] = { + + /* 1-10 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, 743.52e-6, -0.17e-6 }, + {{ 0, 0, 2, -2, 2, 0, 0, 0}, 56.91e-6, 0.06e-6 }, + {{ 0, 0, 2, 0, 2, 0, 0, 0}, 9.84e-6, -0.01e-6 }, + {{ 0, 0, 0, 0, 2, 0, 0, 0}, -8.85e-6, 0.01e-6 }, + {{ 0, 1, 0, 0, 0, 0, 0, 0}, -6.38e-6, -0.05e-6 }, + {{ 1, 0, 0, 0, 0, 0, 0, 0}, -3.07e-6, 0.00e-6 }, + {{ 0, 1, 2, -2, 2, 0, 0, 0}, 2.23e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 1, 0, 0, 0}, 1.67e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 2, 0, 0, 0}, 1.30e-6, 0.00e-6 }, + {{ 0, 1, -2, 2, -2, 0, 0, 0}, 0.93e-6, 0.00e-6 }, + + /* 11-20 */ + {{ 1, 0, 0, -2, 0, 0, 0, 0}, 0.68e-6, 0.00e-6 }, + {{ 0, 0, 2, -2, 1, 0, 0, 0}, -0.55e-6, 0.00e-6 }, + {{ 1, 0, -2, 0, -2, 0, 0, 0}, 0.53e-6, 0.00e-6 }, + {{ 0, 0, 0, 2, 0, 0, 0, 0}, -0.27e-6, 0.00e-6 }, + {{ 1, 0, 0, 0, 1, 0, 0, 0}, -0.27e-6, 0.00e-6 }, + {{ 1, 0, -2, -2, -2, 0, 0, 0}, -0.26e-6, 0.00e-6 }, + {{ 1, 0, 0, 0, -1, 0, 0, 0}, -0.25e-6, 0.00e-6 }, + {{ 1, 0, 2, 0, 1, 0, 0, 0}, 0.22e-6, 0.00e-6 }, + {{ 2, 0, 0, -2, 0, 0, 0, 0}, -0.21e-6, 0.00e-6 }, + {{ 2, 0, -2, 0, -1, 0, 0, 0}, 0.20e-6, 0.00e-6 }, + + /* 21-25 */ + {{ 0, 0, 2, 2, 2, 0, 0, 0}, 0.17e-6, 0.00e-6 }, + {{ 2, 0, 2, 0, 2, 0, 0, 0}, 0.13e-6, 0.00e-6 }, + {{ 2, 0, 0, 0, 0, 0, 0, 0}, -0.13e-6, 0.00e-6 }, + {{ 1, 0, 2, -2, 2, 0, 0, 0}, -0.12e-6, 0.00e-6 }, + {{ 0, 0, 2, 0, 0, 0, 0, 0}, -0.11e-6, 0.00e-6 } + }; + +/* Terms of order t^3 */ + static const TERM s3[] = { + + /* 1-4 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, 0.30e-6, -23.42e-6 }, + {{ 0, 0, 2, -2, 2, 0, 0, 0}, -0.03e-6, -1.46e-6 }, + {{ 0, 0, 2, 0, 2, 0, 0, 0}, -0.01e-6, -0.25e-6 }, + {{ 0, 0, 0, 0, 2, 0, 0, 0}, 0.00e-6, 0.23e-6 } + }; + +/* Terms of order t^4 */ + static const TERM s4[] = { + + /* 1-1 */ + {{ 0, 0, 0, 0, 1, 0, 0, 0}, -0.26e-6, -0.01e-6 } + }; + +/* Number of terms in the series */ + static const int NS0 = (int) (sizeof s0 / sizeof (TERM)); + static const int NS1 = (int) (sizeof s1 / sizeof (TERM)); + static const int NS2 = (int) (sizeof s2 / sizeof (TERM)); + static const int NS3 = (int) (sizeof s3 / sizeof (TERM)); + static const int NS4 = (int) (sizeof s4 / sizeof (TERM)); + +/* ------------------------------------------------------------------ */ + +/* Interval between fundamental epoch J2000.0 and current date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Fundamental Arguments (from IERS Conventions 2003) */ + +/* Mean anomaly of the Moon. */ + fa[0] = iauFal03(t); + +/* Mean anomaly of the Sun. */ + fa[1] = iauFalp03(t); + +/* Mean longitude of the Moon minus that of the ascending node. */ + fa[2] = iauFaf03(t); + +/* Mean elongation of the Moon from the Sun. */ + fa[3] = iauFad03(t); + +/* Mean longitude of the ascending node of the Moon. */ + fa[4] = iauFaom03(t); + +/* Mean longitude of Venus. */ + fa[5] = iauFave03(t); + +/* Mean longitude of Earth. */ + fa[6] = iauFae03(t); + +/* General precession in longitude. */ + fa[7] = iauFapa03(t); + +/* Evaluate s. */ + w0 = sp[0]; + w1 = sp[1]; + w2 = sp[2]; + w3 = sp[3]; + w4 = sp[4]; + w5 = sp[5]; + + for (i = NS0-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s0[i].nfa[j] * fa[j]; + } + w0 += s0[i].s * sin(a) + s0[i].c * cos(a); + } + + for (i = NS1-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s1[i].nfa[j] * fa[j]; + } + w1 += s1[i].s * sin(a) + s1[i].c * cos(a); + } + + for (i = NS2-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s2[i].nfa[j] * fa[j]; + } + w2 += s2[i].s * sin(a) + s2[i].c * cos(a); + } + + for (i = NS3-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s3[i].nfa[j] * fa[j]; + } + w3 += s3[i].s * sin(a) + s3[i].c * cos(a); + } + + for (i = NS4-1; i >= 0; i--) { + a = 0.0; + for (j = 0; j < 8; j++) { + a += (double)s4[i].nfa[j] * fa[j]; + } + w4 += s4[i].s * sin(a) + s4[i].c * cos(a); + } + + s = (w0 + + (w1 + + (w2 + + (w3 + + (w4 + + w5 * t) * t) * t) * t) * t) * DAS2R - x*y/2.0; + + return s; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s06a.c b/src/cpp/3rdparty/sofa/src/s06a.c new file mode 100644 index 000000000..c594cb733 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s06a.c @@ -0,0 +1,197 @@ +#include "sofa.h" + +double iauS06a(double date1, double date2) +/* +** - - - - - - - - +** i a u S 0 6 a +** - - - - - - - - +** +** The CIO locator s, positioning the Celestial Intermediate Origin on +** the equator of the Celestial Intermediate Pole, using the IAU 2006 +** precession and IAU 2000A nutation models. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double the CIO locator s in radians (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The CIO locator s is the difference between the right ascensions +** of the same point in two systems. The two systems are the GCRS +** and the CIP,CIO, and the point is the ascending node of the +** CIP equator. The CIO locator s remains a small fraction of +** 1 arcsecond throughout 1900-2100. +** +** 3) The series used to compute s is in fact for s+XY/2, where X and Y +** are the x and y components of the CIP unit vector; this series is +** more compact than a direct series for s would be. The present +** function uses the full IAU 2000A nutation model when predicting +** the CIP position. +** +** Called: +** iauPnm06a classical NPB matrix, IAU 2006/2000A +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS06 the CIO locator s, given X,Y, IAU 2006 +** +** References: +** +** Capitaine, N., Chapront, J., Lambert, S. and Wallace, P., +** "Expressions for the Celestial Intermediate Pole and Celestial +** Ephemeris Origin consistent with the IAU 2000A precession- +** nutation model", Astron.Astrophys. 400, 1145-1154 (2003) +** +** n.b. The celestial ephemeris origin (CEO) was renamed "celestial +** intermediate origin" (CIO) by IAU 2006 Resolution 2. +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** McCarthy, D. D., Petit, G. (eds.), 2004, IERS Conventions (2003), +** IERS Technical Note No. 32, BKG +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rnpb[3][3], x, y, s; + + +/* Bias-precession-nutation-matrix, IAU 20006/2000A. */ + iauPnm06a(date1, date2, rnpb); + +/* Extract the CIP coordinates. */ + iauBpn2xy(rnpb, &x, &y); + +/* Compute the CIO locator s, given the CIP coordinates. */ + s = iauS06(date1, date2, x, y); + + return s; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s2c.c b/src/cpp/3rdparty/sofa/src/s2c.c new file mode 100644 index 000000000..ac498ae6c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s2c.c @@ -0,0 +1,135 @@ +#include "sofa.h" + +void iauS2c(double theta, double phi, double c[3]) +/* +** - - - - - - - +** i a u S 2 c +** - - - - - - - +** +** Convert spherical coordinates to Cartesian. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** theta double longitude angle (radians) +** phi double latitude angle (radians) +** +** Returned: +** c double[3] direction cosines +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double cp; + + + cp = cos(phi); + c[0] = cos(theta) * cp; + c[1] = sin(theta) * cp; + c[2] = sin(phi); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s2p.c b/src/cpp/3rdparty/sofa/src/s2p.c new file mode 100644 index 000000000..8a4c6a2a3 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s2p.c @@ -0,0 +1,138 @@ +#include "sofa.h" + +void iauS2p(double theta, double phi, double r, double p[3]) +/* +** - - - - - - - +** i a u S 2 p +** - - - - - - - +** +** Convert spherical polar coordinates to p-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** theta double longitude angle (radians) +** phi double latitude angle (radians) +** r double radial distance +** +** Returned: +** p double[3] Cartesian coordinates +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauSxp multiply p-vector by scalar +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double u[3]; + + + iauS2c(theta, phi, u); + iauSxp(r, u, p); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s2pv.c b/src/cpp/3rdparty/sofa/src/s2pv.c new file mode 100644 index 000000000..563348663 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s2pv.c @@ -0,0 +1,153 @@ +#include "sofa.h" + +void iauS2pv(double theta, double phi, double r, + double td, double pd, double rd, + double pv[2][3]) +/* +** - - - - - - - - +** i a u S 2 p v +** - - - - - - - - +** +** Convert position/velocity from spherical to Cartesian coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** theta double longitude angle (radians) +** phi double latitude angle (radians) +** r double radial distance +** td double rate of change of theta +** pd double rate of change of phi +** rd double rate of change of r +** +** Returned: +** pv double[2][3] pv-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double st, ct, sp, cp, rcp, x, y, rpd, w; + + + st = sin(theta); + ct = cos(theta); + sp = sin(phi); + cp = cos(phi); + rcp = r * cp; + x = rcp * ct; + y = rcp * st; + rpd = r * pd; + w = rpd*sp - cp*rd; + + pv[0][0] = x; + pv[0][1] = y; + pv[0][2] = r * sp; + pv[1][0] = -y*td - w*ct; + pv[1][1] = x*td - w*st; + pv[1][2] = rpd*cp + sp*rd; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/s2xpv.c b/src/cpp/3rdparty/sofa/src/s2xpv.c new file mode 100644 index 000000000..2de30b9e8 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/s2xpv.c @@ -0,0 +1,137 @@ +#include "sofa.h" + +void iauS2xpv(double s1, double s2, double pv[2][3], double spv[2][3]) +/* +** - - - - - - - - - +** i a u S 2 x p v +** - - - - - - - - - +** +** Multiply a pv-vector by two scalars. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** s1 double scalar to multiply position component by +** s2 double scalar to multiply velocity component by +** pv double[2][3] pv-vector +** +** Returned: +** spv double[2][3] pv-vector: p scaled by s1, v scaled by s2 +** +** Note: +** It is permissible for pv and spv to be the same array. +** +** Called: +** iauSxp multiply p-vector by scalar +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauSxp(s1, pv[0], spv[0]); + iauSxp(s2, pv[1], spv[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/sepp.c b/src/cpp/3rdparty/sofa/src/sepp.c new file mode 100644 index 000000000..0b9e14fd4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/sepp.c @@ -0,0 +1,157 @@ +#include "sofa.h" + +double iauSepp(double a[3], double b[3]) +/* +** - - - - - - - - +** i a u S e p p +** - - - - - - - - +** +** Angular separation between two p-vectors. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** a double[3] first p-vector (not necessarily unit length) +** b double[3] second p-vector (not necessarily unit length) +** +** Returned (function value): +** double angular separation (radians, always positive) +** +** Notes: +** +** 1) If either vector is null, a zero result is returned. +** +** 2) The angular separation is most simply formulated in terms of +** scalar product. However, this gives poor accuracy for angles +** near zero and pi. The present algorithm uses both cross product +** and dot product, to deliver full accuracy whatever the size of +** the angle. +** +** Called: +** iauPxp vector product of two p-vectors +** iauPm modulus of p-vector +** iauPdp scalar product of two p-vectors +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double axb[3], ss, cs, s; + + +/* Sine of angle between the vectors, multiplied by the two moduli. */ + iauPxp(a, b, axb); + ss = iauPm(axb); + +/* Cosine of the angle, multiplied by the two moduli. */ + cs = iauPdp(a, b); + +/* The angle. */ + s = ((ss != 0.0) || (cs != 0.0)) ? atan2(ss, cs) : 0.0; + + return s; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/seps.c b/src/cpp/3rdparty/sofa/src/seps.c new file mode 100644 index 000000000..98522b6b9 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/seps.c @@ -0,0 +1,145 @@ +#include "sofa.h" + +double iauSeps(double al, double ap, double bl, double bp) +/* +** - - - - - - - - +** i a u S e p s +** - - - - - - - - +** +** Angular separation between two sets of spherical coordinates. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** al double first longitude (radians) +** ap double first latitude (radians) +** bl double second longitude (radians) +** bp double second latitude (radians) +** +** Returned (function value): +** double angular separation (radians) +** +** Called: +** iauS2c spherical coordinates to unit vector +** iauSepp angular separation between two p-vectors +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double ac[3], bc[3], s; + + +/* Spherical to Cartesian. */ + iauS2c(al, ap, ac); + iauS2c(bl, bp, bc); + +/* Angle between the vectors. */ + s = iauSepp(ac, bc); + + return s; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/sofa.hpp b/src/cpp/3rdparty/sofa/src/sofa.h similarity index 99% rename from src/cpp/3rdparty/sofa/sofa.hpp rename to src/cpp/3rdparty/sofa/src/sofa.h index 2e7c6fda9..6b5545edc 100644 --- a/src/cpp/3rdparty/sofa/sofa.hpp +++ b/src/cpp/3rdparty/sofa/src/sofa.h @@ -1,5 +1,5 @@ -#ifndef SOFAHPPDEF -#define SOFAHPPDEF +#ifndef SOFAHDEF +#define SOFAHDEF /* ** - - - - - - - diff --git a/src/cpp/3rdparty/sofa/sofam.hpp b/src/cpp/3rdparty/sofa/src/sofam.h similarity index 99% rename from src/cpp/3rdparty/sofa/sofam.hpp rename to src/cpp/3rdparty/sofa/src/sofam.h index 02afa972c..a7b828dba 100644 --- a/src/cpp/3rdparty/sofa/sofam.hpp +++ b/src/cpp/3rdparty/sofa/src/sofam.h @@ -1,5 +1,5 @@ -#ifndef SOFAMHPPDEF -#define SOFAMHPPDEF +#ifndef SOFAMHDEF +#define SOFAMHDEF /* ** - - - - - - - - diff --git a/src/cpp/3rdparty/sofa/src/sp00.c b/src/cpp/3rdparty/sofa/src/sp00.c new file mode 100644 index 000000000..ff8fe4981 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/sp00.c @@ -0,0 +1,171 @@ +#include "sofa.h" +#include "sofam.h" + +double iauSp00(double date1, double date2) +/* +** - - - - - - - - +** i a u S p 0 0 +** - - - - - - - - +** +** The TIO locator s', positioning the Terrestrial Intermediate Origin +** on the equator of the Celestial Intermediate Pole. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned (function value): +** double the TIO locator s' in radians (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The TIO locator s' is obtained from polar motion observations by +** numerical integration, and so is in essence unpredictable. +** However, it is dominated by a secular drift of about +** 47 microarcseconds per century, which is the approximation +** evaluated by the present function. +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double t, sp; + + +/* Interval between fundamental epoch J2000.0 and current date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Approximate s'. */ + sp = -47e-6 * t * DAS2R; + + return sp; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/starpm.c b/src/cpp/3rdparty/sofa/src/starpm.c new file mode 100644 index 000000000..b403d56bf --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/starpm.c @@ -0,0 +1,258 @@ +#include "sofa.h" +#include "sofam.h" + +int iauStarpm(double ra1, double dec1, + double pmr1, double pmd1, double px1, double rv1, + double ep1a, double ep1b, double ep2a, double ep2b, + double *ra2, double *dec2, + double *pmr2, double *pmd2, double *px2, double *rv2) +/* +** - - - - - - - - - - +** i a u S t a r p m +** - - - - - - - - - - +** +** Star proper motion: update star catalog data for space motion. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** ra1 double right ascension (radians), before +** dec1 double declination (radians), before +** pmr1 double RA proper motion (radians/year), before +** pmd1 double Dec proper motion (radians/year), before +** px1 double parallax (arcseconds), before +** rv1 double radial velocity (km/s, +ve = receding), before +** ep1a double "before" epoch, part A (Note 1) +** ep1b double "before" epoch, part B (Note 1) +** ep2a double "after" epoch, part A (Note 1) +** ep2b double "after" epoch, part B (Note 1) +** +** Returned: +** ra2 double right ascension (radians), after +** dec2 double declination (radians), after +** pmr2 double RA proper motion (radians/year), after +** pmd2 double Dec proper motion (radians/year), after +** px2 double parallax (arcseconds), after +** rv2 double radial velocity (km/s, +ve = receding), after +** +** Returned (function value): +** int status: +** -1 = system error (should not occur) +** 0 = no warnings or errors +** 1 = distance overridden (Note 6) +** 2 = excessive velocity (Note 7) +** 4 = solution didn't converge (Note 8) +** else = binary logical OR of the above warnings +** +** Notes: +** +** 1) The starting and ending TDB dates ep1a+ep1b and ep2a+ep2b are +** Julian Dates, apportioned in any convenient way between the two +** parts (A and B). For example, JD(TDB)=2450123.7 could be +** expressed in any of these ways, among others: +** +** epna epnb +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) In accordance with normal star-catalog conventions, the object's +** right ascension and declination are freed from the effects of +** secular aberration. The frame, which is aligned to the catalog +** equator and equinox, is Lorentzian and centered on the SSB. +** +** The proper motions are the rate of change of the right ascension +** and declination at the catalog epoch and are in radians per TDB +** Julian year. +** +** The parallax and radial velocity are in the same frame. +** +** 3) Care is needed with units. The star coordinates are in radians +** and the proper motions in radians per Julian year, but the +** parallax is in arcseconds. +** +** 4) The RA proper motion is in terms of coordinate angle, not true +** angle. If the catalog uses arcseconds for both RA and Dec proper +** motions, the RA proper motion will need to be divided by cos(Dec) +** before use. +** +** 5) Straight-line motion at constant speed, in the inertial frame, +** is assumed. +** +** 6) An extremely small (or zero or negative) parallax is interpreted +** to mean that the object is on the "celestial sphere", the radius +** of which is an arbitrary (large) value (see the iauStarpv +** function for the value used). When the distance is overridden in +** this way, the status, initially zero, has 1 added to it. +** +** 7) If the space velocity is a significant fraction of c (see the +** constant VMAX in the function iauStarpv), it is arbitrarily set +** to zero. When this action occurs, 2 is added to the status. +** +** 8) The relativistic adjustment carried out in the iauStarpv function +** involves an iterative calculation. If the process fails to +** converge within a set number of iterations, 4 is added to the +** status. +** +** Called: +** iauStarpv star catalog data to space motion pv-vector +** iauPvu update a pv-vector +** iauPdp scalar product of two p-vectors +** iauPvstar space motion pv-vector to star catalog data +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double pv1[2][3], tl1, dt, pv[2][3], r2, rdv, v2, c2mv2, tl2, + pv2[2][3]; + int j1, j2, j; + + +/* RA,Dec etc. at the "before" epoch to space motion pv-vector. */ + j1 = iauStarpv(ra1, dec1, pmr1, pmd1, px1, rv1, pv1); + +/* Light time when observed (days). */ + tl1 = iauPm(pv1[0]) / DC; + +/* Time interval, "before" to "after" (days). */ + dt = (ep2a - ep1a) + (ep2b - ep1b); + +/* Move star along track from the "before" observed position to the */ +/* "after" geometric position. */ + iauPvu(dt + tl1, pv1, pv); + +/* From this geometric position, deduce the observed light time (days) */ +/* at the "after" epoch (with theoretically unneccessary error check). */ + r2 = iauPdp(pv[0], pv[0]); + rdv = iauPdp(pv[0], pv[1]); + v2 = iauPdp(pv[1], pv[1]); + c2mv2 = DC*DC - v2; + if (c2mv2 <= 0) return -1; + tl2 = (-rdv + sqrt(rdv*rdv + c2mv2*r2)) / c2mv2; + +/* Move the position along track from the observed place at the */ +/* "before" epoch to the observed place at the "after" epoch. */ + iauPvu(dt + (tl1 - tl2), pv1, pv2); + +/* Space motion pv-vector to RA,Dec etc. at the "after" epoch. */ + j2 = iauPvstar(pv2, ra2, dec2, pmr2, pmd2, px2, rv2); + +/* Final status. */ + j = (j2 == 0) ? j1 : -1; + + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/starpv.c b/src/cpp/3rdparty/sofa/src/starpv.c new file mode 100644 index 000000000..5cb27ec0b --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/starpv.c @@ -0,0 +1,318 @@ +#include "sofa.h" +#include "sofam.h" + +int iauStarpv(double ra, double dec, + double pmr, double pmd, double px, double rv, + double pv[2][3]) +/* +** - - - - - - - - - - +** i a u S t a r p v +** - - - - - - - - - - +** +** Convert star catalog coordinates to position+velocity vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given (Note 1): +** ra double right ascension (radians) +** dec double declination (radians) +** pmr double RA proper motion (radians/year) +** pmd double Dec proper motion (radians/year) +** px double parallax (arcseconds) +** rv double radial velocity (km/s, positive = receding) +** +** Returned (Note 2): +** pv double[2][3] pv-vector (au, au/day) +** +** Returned (function value): +** int status: +** 0 = no warnings +** 1 = distance overridden (Note 6) +** 2 = excessive speed (Note 7) +** 4 = solution didn't converge (Note 8) +** else = binary logical OR of the above +** +** Notes: +** +** 1) The star data accepted by this function are "observables" for an +** imaginary observer at the solar-system barycenter. Proper motion +** and radial velocity are, strictly, in terms of barycentric +** coordinate time, TCB. For most practical applications, it is +** permissible to neglect the distinction between TCB and ordinary +** "proper" time on Earth (TT/TAI). The result will, as a rule, be +** limited by the intrinsic accuracy of the proper-motion and +** radial-velocity data; moreover, the pv-vector is likely to be +** merely an intermediate result, so that a change of time unit +** would cancel out overall. +** +** In accordance with normal star-catalog conventions, the object's +** right ascension and declination are freed from the effects of +** secular aberration. The frame, which is aligned to the catalog +** equator and equinox, is Lorentzian and centered on the SSB. +** +** 2) The resulting position and velocity pv-vector is with respect to +** the same frame and, like the catalog coordinates, is freed from +** the effects of secular aberration. Should the "coordinate +** direction", where the object was located at the catalog epoch, be +** required, it may be obtained by calculating the magnitude of the +** position vector pv[0][0-2] dividing by the speed of light in +** au/day to give the light-time, and then multiplying the space +** velocity pv[1][0-2] by this light-time and adding the result to +** pv[0][0-2]. +** +** Summarizing, the pv-vector returned is for most stars almost +** identical to the result of applying the standard geometrical +** "space motion" transformation. The differences, which are the +** subject of the Stumpff paper referenced below, are: +** +** (i) In stars with significant radial velocity and proper motion, +** the constantly changing light-time distorts the apparent proper +** motion. Note that this is a classical, not a relativistic, +** effect. +** +** (ii) The transformation complies with special relativity. +** +** 3) Care is needed with units. The star coordinates are in radians +** and the proper motions in radians per Julian year, but the +** parallax is in arcseconds; the radial velocity is in km/s, but +** the pv-vector result is in au and au/day. +** +** 4) The RA proper motion is in terms of coordinate angle, not true +** angle. If the catalog uses arcseconds for both RA and Dec proper +** motions, the RA proper motion will need to be divided by cos(Dec) +** before use. +** +** 5) Straight-line motion at constant speed, in the inertial frame, +** is assumed. +** +** 6) An extremely small (or zero or negative) parallax is interpreted +** to mean that the object is on the "celestial sphere", the radius +** of which is an arbitrary (large) value (see the constant PXMIN). +** When the distance is overridden in this way, the status, +** initially zero, has 1 added to it. +** +** 7) If the space velocity is a significant fraction of c (see the +** constant VMAX), it is arbitrarily set to zero. When this action +** occurs, 2 is added to the status. +** +** 8) The relativistic adjustment involves an iterative calculation. +** If the process fails to converge within a set number (IMAX) of +** iterations, 4 is added to the status. +** +** 9) The inverse transformation is performed by the function +** iauPvstar. +** +** Called: +** iauS2pv spherical coordinates to pv-vector +** iauPm modulus of p-vector +** iauZp zero p-vector +** iauPn decompose p-vector into modulus and direction +** iauPdp scalar product of two p-vectors +** iauSxp multiply p-vector by scalar +** iauPmp p-vector minus p-vector +** iauPpp p-vector plus p-vector +** +** Reference: +** +** Stumpff, P., 1985, Astron.Astrophys. 144, 232-240. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ +/* Smallest allowed parallax */ + static const double PXMIN = 1e-7; + +/* Largest allowed speed (fraction of c) */ + static const double VMAX = 0.5; + +/* Maximum number of iterations for relativistic solution */ + static const int IMAX = 100; + + int i, iwarn; + double w, r, rd, rad, decd, v, x[3], usr[3], ust[3], + vsr, vst, betst, betsr, bett, betr, + dd, ddel, ur[3], ut[3], + d = 0.0, del = 0.0, /* to prevent */ + odd = 0.0, oddel = 0.0, /* compiler */ + od = 0.0, odel = 0.0; /* warnings */ + + +/* Distance (au). */ + if (px >= PXMIN) { + w = px; + iwarn = 0; + } else { + w = PXMIN; + iwarn = 1; + } + r = DR2AS / w; + +/* Radial velocity (au/day). */ + rd = DAYSEC * rv * 1e3 / DAU; + +/* Proper motion (radian/day). */ + rad = pmr / DJY; + decd = pmd / DJY; + +/* To pv-vector (au,au/day). */ + iauS2pv(ra, dec, r, rad, decd, rd, pv); + +/* If excessive velocity, arbitrarily set it to zero. */ + v = iauPm(pv[1]); + if (v / DC > VMAX) { + iauZp(pv[1]); + iwarn += 2; + } + +/* Isolate the radial component of the velocity (au/day). */ + iauPn(pv[0], &w, x); + vsr = iauPdp(x, pv[1]); + iauSxp(vsr, x, usr); + +/* Isolate the transverse component of the velocity (au/day). */ + iauPmp(pv[1], usr, ust); + vst = iauPm(ust); + +/* Special-relativity dimensionless parameters. */ + betsr = vsr / DC; + betst = vst / DC; + +/* Determine the inertial-to-observed relativistic correction terms. */ + bett = betst; + betr = betsr; + for (i = 0; i < IMAX; i++) { + d = 1.0 + betr; + w = betr*betr + bett*bett; + del = - w / (sqrt(1.0 - w) + 1.0); + betr = d * betsr + del; + bett = d * betst; + if (i > 0) { + dd = fabs(d - od); + ddel = fabs(del - odel); + if ((i > 1) && (dd >= odd) && (ddel >= oddel)) break; + odd = dd; + oddel = ddel; + } + od = d; + odel = del; + } + if (i >= IMAX) iwarn += 4; + +/* Replace observed radial velocity with inertial value. */ + w = (betsr != 0.0) ? d + del / betsr : 1.0; + iauSxp(w, usr, ur); + +/* Replace observed tangential velocity with inertial value. */ + iauSxp(d, ust, ut); + +/* Combine the two to obtain the inertial space velocity. */ + iauPpp(ur, ut, pv[1]); + +/* Return the status. */ + return iwarn; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/sxp.c b/src/cpp/3rdparty/sofa/src/sxp.c new file mode 100644 index 000000000..e48b156a0 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/sxp.c @@ -0,0 +1,134 @@ +#include "sofa.h" + +void iauSxp(double s, double p[3], double sp[3]) +/* +** - - - - - - - +** i a u S x p +** - - - - - - - +** +** Multiply a p-vector by a scalar. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** s double scalar +** p double[3] p-vector +** +** Returned: +** sp double[3] s * p +** +** Note: +** It is permissible for p and sp to be the same array. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + sp[0] = s * p[0]; + sp[1] = s * p[1]; + sp[2] = s * p[2]; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/sxpv.c b/src/cpp/3rdparty/sofa/src/sxpv.c new file mode 100644 index 000000000..59e941d01 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/sxpv.c @@ -0,0 +1,135 @@ +#include "sofa.h" + +void iauSxpv(double s, double pv[2][3], double spv[2][3]) +/* +** - - - - - - - - +** i a u S x p v +** - - - - - - - - +** +** Multiply a pv-vector by a scalar. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** s double scalar +** pv double[2][3] pv-vector +** +** Returned: +** spv double[2][3] s * pv +** +** Note: +** It is permissible for pv and spv to be the same array. +** +** Called: +** iauS2xpv multiply pv-vector by two scalars +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauS2xpv(s, s, pv, spv); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/t_sofa_c.c b/src/cpp/3rdparty/sofa/src/t_sofa_c.c new file mode 100644 index 000000000..d288fcf98 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/t_sofa_c.c @@ -0,0 +1,10366 @@ +#include +#include "sofam.h" +#include + +static int verbose = 0; + +/* +** - - - - - - - - - +** t _ s o f a _ c +** - - - - - - - - - +** +** Validate the SOFA C functions. +** +** Each SOFA function is at least called and a usually quite basic test +** is performed. Successful completion is signalled by a confirming +** message. Failure of a given function or group of functions results +** in error messages. +** +** All messages go to stdout. +** +** This revision: 2021 April 18 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ + +static void viv(int ival, int ivalok, + const char *func, const char *test, int *status) +/* +** - - - - +** v i v +** - - - - +** +** Validate an integer result. +** +** Internal function used by t_sofa_c program. +** +** Given: +** ival int value computed by function under test +** ivalok int correct value +** func char[] name of function under test +** test char[] name of individual test +** +** Given and returned: +** status int set to TRUE if test fails +** +** This revision: 2013 August 7 +*/ +{ + if (ival != ivalok) { + *status = 1; + printf("%s failed: %s want %d got %d\n", + func, test, ivalok, ival); + } else if (verbose) { + printf("%s passed: %s want %d got %d\n", + func, test, ivalok, ival); + } + +} + +static void vvd(double val, double valok, double dval, + const char *func, const char *test, int *status) +/* +** - - - - +** v v d +** - - - - +** +** Validate a double result. +** +** Internal function used by t_sofa_c program. +** +** Given: +** val double value computed by function under test +** valok double expected value +** dval double maximum allowable error +** func char[] name of function under test +** test char[] name of individual test +** +** Given and returned: +** status int set to TRUE if test fails +** +** This revision: 2016 April 21 +*/ +{ + double a, f; /* absolute and fractional error */ + + + a = val - valok; + if (a != 0.0 && fabs(a) > fabs(dval)) { + f = fabs(valok / a); + *status = 1; + printf("%s failed: %s want %.20g got %.20g (1/%.3g)\n", + func, test, valok, val, f); + } else if (verbose) { + printf("%s passed: %s want %.20g got %.20g\n", + func, test, valok, val); + } + +} + +static void t_a2af(int *status) +/* +** - - - - - - - +** t _ a 2 a f +** - - - - - - - +** +** Test iauA2af function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauA2af, viv +** +** This revision: 2013 August 7 +*/ +{ + int idmsf[4]; + char s; + + + iauA2af(4, 2.345, &s, idmsf); + + viv(s, '+', "iauA2af", "s", status); + + viv(idmsf[0], 134, "iauA2af", "0", status); + viv(idmsf[1], 21, "iauA2af", "1", status); + viv(idmsf[2], 30, "iauA2af", "2", status); + viv(idmsf[3], 9706, "iauA2af", "3", status); + +} + +static void t_a2tf(int *status) +/* +** - - - - - - - +** t _ a 2 t f +** - - - - - - - +** +** Test iauA2tf function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauA2tf, viv +** +** This revision: 2013 August 7 +*/ +{ + int ihmsf[4]; + char s; + + + iauA2tf(4, -3.01234, &s, ihmsf); + + viv((int)s, '-', "iauA2tf", "s", status); + + viv(ihmsf[0], 11, "iauA2tf", "0", status); + viv(ihmsf[1], 30, "iauA2tf", "1", status); + viv(ihmsf[2], 22, "iauA2tf", "2", status); + viv(ihmsf[3], 6484, "iauA2tf", "3", status); + +} + +static void t_ab(int *status) +/* +** - - - - - +** t _ a b +** - - - - - +** +** Test iauAb function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAb, vvd +** +** This revision: 2013 October 1 +*/ +{ + double pnat[3], v[3], s, bm1, ppr[3]; + + + pnat[0] = -0.76321968546737951; + pnat[1] = -0.60869453983060384; + pnat[2] = -0.21676408580639883; + v[0] = 2.1044018893653786e-5; + v[1] = -8.9108923304429319e-5; + v[2] = -3.8633714797716569e-5; + s = 0.99980921395708788; + bm1 = 0.99999999506209258; + + iauAb(pnat, v, s, bm1, ppr); + + vvd(ppr[0], -0.7631631094219556269, 1e-12, "iauAb", "1", status); + vvd(ppr[1], -0.6087553082505590832, 1e-12, "iauAb", "2", status); + vvd(ppr[2], -0.2167926269368471279, 1e-12, "iauAb", "3", status); + +} + +static void t_ae2hd(int *status) +/* +** - - - - - - - - +** t _ a e 2 h d +** - - - - - - - - +** +** Test iauAe2hd function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAe2hd and vvd +** +** This revision: 2017 October 21 +*/ +{ + double a, e, p, h, d; + + + a = 5.5; + e = 1.1; + p = 0.7; + + iauAe2hd(a, e, p, &h, &d); + + vvd(h, 0.5933291115507309663, 1e-14, "iauAe2hd", "h", status); + vvd(d, 0.9613934761647817620, 1e-14, "iauAe2hd", "d", status); + +} + +static void t_af2a(int *status) +/* +** - - - - - - - +** t _ a f 2 a +** - - - - - - - +** +** Test iauAf2a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAf2a, viv +** +** This revision: 2013 August 7 +*/ +{ + double a; + int j; + + + j = iauAf2a('-', 45, 13, 27.2, &a); + + vvd(a, -0.7893115794313644842, 1e-12, "iauAf2a", "a", status); + viv(j, 0, "iauAf2a", "j", status); + +} + +static void t_anp(int *status) +/* +** - - - - - - +** t _ a n p +** - - - - - - +** +** Test iauAnp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAnp, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauAnp(-0.1), 6.183185307179586477, 1e-12, "iauAnp", "", status); +} + +static void t_anpm(int *status) +/* +** - - - - - - - +** t _ a n p m +** - - - - - - - +** +** Test iauAnpm function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAnpm, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauAnpm(-4.0), 2.283185307179586477, 1e-12, "iauAnpm", "", status); +} + +static void t_apcg(int *status) +/* +** - - - - - - - +** t _ a p c g +** - - - - - - - +** +** Test iauApcg function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApcg, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, ebpv[2][3], ehp[3]; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + ebpv[0][0] = 0.901310875; + ebpv[0][1] = -0.417402664; + ebpv[0][2] = -0.180982288; + ebpv[1][0] = 0.00742727954; + ebpv[1][1] = 0.0140507459; + ebpv[1][2] = 0.00609045792; + ehp[0] = 0.903358544; + ehp[1] = -0.415395237; + ehp[2] = -0.180084014; + + iauApcg(date1, date2, ebpv, ehp, &astrom); + + vvd(astrom.pmt, 12.65133794027378508, 1e-11, + "iauApcg", "pmt", status); + vvd(astrom.eb[0], 0.901310875, 1e-12, + "iauApcg", "eb(1)", status); + vvd(astrom.eb[1], -0.417402664, 1e-12, + "iauApcg", "eb(2)", status); + vvd(astrom.eb[2], -0.180982288, 1e-12, + "iauApcg", "eb(3)", status); + vvd(astrom.eh[0], 0.8940025429324143045, 1e-12, + "iauApcg", "eh(1)", status); + vvd(astrom.eh[1], -0.4110930268679817955, 1e-12, + "iauApcg", "eh(2)", status); + vvd(astrom.eh[2], -0.1782189004872870264, 1e-12, + "iauApcg", "eh(3)", status); + vvd(astrom.em, 1.010465295811013146, 1e-12, + "iauApcg", "em", status); + vvd(astrom.v[0], 0.4289638913597693554e-4, 1e-16, + "iauApcg", "v(1)", status); + vvd(astrom.v[1], 0.8115034051581320575e-4, 1e-16, + "iauApcg", "v(2)", status); + vvd(astrom.v[2], 0.3517555136380563427e-4, 1e-16, + "iauApcg", "v(3)", status); + vvd(astrom.bm1, 0.9999999951686012981, 1e-12, + "iauApcg", "bm1", status); + vvd(astrom.bpn[0][0], 1.0, 0.0, + "iauApcg", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0.0, 0.0, + "iauApcg", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0.0, 0.0, + "iauApcg", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], 0.0, 0.0, + "iauApcg", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 1.0, 0.0, + "iauApcg", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], 0.0, 0.0, + "iauApcg", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], 0.0, 0.0, + "iauApcg", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0.0, 0.0, + "iauApcg", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 1.0, 0.0, + "iauApcg", "bpn(3,3)", status); + +} + +static void t_apcg13(int *status) +/* +** - - - - - - - - - +** t _ a p c g 1 3 +** - - - - - - - - - +** +** Test iauApcg13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApcg13, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + + iauApcg13(date1, date2, &astrom); + + vvd(astrom.pmt, 12.65133794027378508, 1e-11, + "iauApcg13", "pmt", status); + vvd(astrom.eb[0], 0.9013108747340644755, 1e-12, + "iauApcg13", "eb(1)", status); + vvd(astrom.eb[1], -0.4174026640406119957, 1e-12, + "iauApcg13", "eb(2)", status); + vvd(astrom.eb[2], -0.1809822877867817771, 1e-12, + "iauApcg13", "eb(3)", status); + vvd(astrom.eh[0], 0.8940025429255499549, 1e-12, + "iauApcg13", "eh(1)", status); + vvd(astrom.eh[1], -0.4110930268331896318, 1e-12, + "iauApcg13", "eh(2)", status); + vvd(astrom.eh[2], -0.1782189006019749850, 1e-12, + "iauApcg13", "eh(3)", status); + vvd(astrom.em, 1.010465295964664178, 1e-12, + "iauApcg13", "em", status); + vvd(astrom.v[0], 0.4289638912941341125e-4, 1e-16, + "iauApcg13", "v(1)", status); + vvd(astrom.v[1], 0.8115034032405042132e-4, 1e-16, + "iauApcg13", "v(2)", status); + vvd(astrom.v[2], 0.3517555135536470279e-4, 1e-16, + "iauApcg13", "v(3)", status); + vvd(astrom.bm1, 0.9999999951686013142, 1e-12, + "iauApcg13", "bm1", status); + vvd(astrom.bpn[0][0], 1.0, 0.0, + "iauApcg13", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0.0, 0.0, + "iauApcg13", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0.0, 0.0, + "iauApcg13", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], 0.0, 0.0, + "iauApcg13", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 1.0, 0.0, + "iauApcg13", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], 0.0, 0.0, + "iauApcg13", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], 0.0, 0.0, + "iauApcg13", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0.0, 0.0, + "iauApcg13", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 1.0, 0.0, + "iauApcg13", "bpn(3,3)", status); + +} + +static void t_apci(int *status) +/* +** - - - - - - - +** t _ a p c i +** - - - - - - - +** +** Test iauApci function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApci, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, ebpv[2][3], ehp[3], x, y, s; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + ebpv[0][0] = 0.901310875; + ebpv[0][1] = -0.417402664; + ebpv[0][2] = -0.180982288; + ebpv[1][0] = 0.00742727954; + ebpv[1][1] = 0.0140507459; + ebpv[1][2] = 0.00609045792; + ehp[0] = 0.903358544; + ehp[1] = -0.415395237; + ehp[2] = -0.180084014; + x = 0.0013122272; + y = -2.92808623e-5; + s = 3.05749468e-8; + + iauApci(date1, date2, ebpv, ehp, x, y, s, &astrom); + + vvd(astrom.pmt, 12.65133794027378508, 1e-11, + "iauApci", "pmt", status); + vvd(astrom.eb[0], 0.901310875, 1e-12, + "iauApci", "eb(1)", status); + vvd(astrom.eb[1], -0.417402664, 1e-12, + "iauApci", "eb(2)", status); + vvd(astrom.eb[2], -0.180982288, 1e-12, + "iauApci", "eb(3)", status); + vvd(astrom.eh[0], 0.8940025429324143045, 1e-12, + "iauApci", "eh(1)", status); + vvd(astrom.eh[1], -0.4110930268679817955, 1e-12, + "iauApci", "eh(2)", status); + vvd(astrom.eh[2], -0.1782189004872870264, 1e-12, + "iauApci", "eh(3)", status); + vvd(astrom.em, 1.010465295811013146, 1e-12, + "iauApci", "em", status); + vvd(astrom.v[0], 0.4289638913597693554e-4, 1e-16, + "iauApci", "v(1)", status); + vvd(astrom.v[1], 0.8115034051581320575e-4, 1e-16, + "iauApci", "v(2)", status); + vvd(astrom.v[2], 0.3517555136380563427e-4, 1e-16, + "iauApci", "v(3)", status); + vvd(astrom.bm1, 0.9999999951686012981, 1e-12, + "iauApci", "bm1", status); + vvd(astrom.bpn[0][0], 0.9999991390295159156, 1e-12, + "iauApci", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0.4978650072505016932e-7, 1e-12, + "iauApci", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0.1312227200000000000e-2, 1e-12, + "iauApci", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], -0.1136336653771609630e-7, 1e-12, + "iauApci", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 0.9999999995713154868, 1e-12, + "iauApci", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], -0.2928086230000000000e-4, 1e-12, + "iauApci", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], -0.1312227200895260194e-2, 1e-12, + "iauApci", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0.2928082217872315680e-4, 1e-12, + "iauApci", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 0.9999991386008323373, 1e-12, + "iauApci", "bpn(3,3)", status); + +} + +static void t_apci13(int *status) +/* +** - - - - - - - - - +** t _ a p c i 1 3 +** - - - - - - - - - +** +** Test iauApci13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApci13, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, eo; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + + iauApci13(date1, date2, &astrom, &eo); + + vvd(astrom.pmt, 12.65133794027378508, 1e-11, + "iauApci13", "pmt", status); + vvd(astrom.eb[0], 0.9013108747340644755, 1e-12, + "iauApci13", "eb(1)", status); + vvd(astrom.eb[1], -0.4174026640406119957, 1e-12, + "iauApci13", "eb(2)", status); + vvd(astrom.eb[2], -0.1809822877867817771, 1e-12, + "iauApci13", "eb(3)", status); + vvd(astrom.eh[0], 0.8940025429255499549, 1e-12, + "iauApci13", "eh(1)", status); + vvd(astrom.eh[1], -0.4110930268331896318, 1e-12, + "iauApci13", "eh(2)", status); + vvd(astrom.eh[2], -0.1782189006019749850, 1e-12, + "iauApci13", "eh(3)", status); + vvd(astrom.em, 1.010465295964664178, 1e-12, + "iauApci13", "em", status); + vvd(astrom.v[0], 0.4289638912941341125e-4, 1e-16, + "iauApci13", "v(1)", status); + vvd(astrom.v[1], 0.8115034032405042132e-4, 1e-16, + "iauApci13", "v(2)", status); + vvd(astrom.v[2], 0.3517555135536470279e-4, 1e-16, + "iauApci13", "v(3)", status); + vvd(astrom.bm1, 0.9999999951686013142, 1e-12, + "iauApci13", "bm1", status); + vvd(astrom.bpn[0][0], 0.9999992060376761710, 1e-12, + "iauApci13", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0.4124244860106037157e-7, 1e-12, + "iauApci13", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0.1260128571051709670e-2, 1e-12, + "iauApci13", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], -0.1282291987222130690e-7, 1e-12, + "iauApci13", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 0.9999999997456835325, 1e-12, + "iauApci13", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], -0.2255288829420524935e-4, 1e-12, + "iauApci13", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], -0.1260128571661374559e-2, 1e-12, + "iauApci13", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0.2255285422953395494e-4, 1e-12, + "iauApci13", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 0.9999992057833604343, 1e-12, + "iauApci13", "bpn(3,3)", status); + vvd(eo, -0.2900618712657375647e-2, 1e-12, + "iauApci13", "eo", status); + +} + +static void t_apco(int *status) +/* +** - - - - - - - +** t _ a p c o +** - - - - - - - +** +** Test iauApco function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApco, vvd +** +** This revision: 2021 January 5 +*/ +{ + double date1, date2, ebpv[2][3], ehp[3], x, y, s, + theta, elong, phi, hm, xp, yp, sp, refa, refb; + iauASTROM astrom; + + + date1 = 2456384.5; + date2 = 0.970031644; + ebpv[0][0] = -0.974170438; + ebpv[0][1] = -0.211520082; + ebpv[0][2] = -0.0917583024; + ebpv[1][0] = 0.00364365824; + ebpv[1][1] = -0.0154287319; + ebpv[1][2] = -0.00668922024; + ehp[0] = -0.973458265; + ehp[1] = -0.209215307; + ehp[2] = -0.0906996477; + x = 0.0013122272; + y = -2.92808623e-5; + s = 3.05749468e-8; + theta = 3.14540971; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + sp = -3.01974337e-11; + refa = 0.000201418779; + refb = -2.36140831e-7; + + iauApco(date1, date2, ebpv, ehp, x, y, s, + theta, elong, phi, hm, xp, yp, sp, + refa, refb, &astrom); + + vvd(astrom.pmt, 13.25248468622587269, 1e-11, + "iauApco", "pmt", status); + vvd(astrom.eb[0], -0.9741827110630322720, 1e-12, + "iauApco", "eb(1)", status); + vvd(astrom.eb[1], -0.2115130190135344832, 1e-12, + "iauApco", "eb(2)", status); + vvd(astrom.eb[2], -0.09179840186949532298, 1e-12, + "iauApco", "eb(3)", status); + vvd(astrom.eh[0], -0.9736425571689739035, 1e-12, + "iauApco", "eh(1)", status); + vvd(astrom.eh[1], -0.2092452125849330936, 1e-12, + "iauApco", "eh(2)", status); + vvd(astrom.eh[2], -0.09075578152243272599, 1e-12, + "iauApco", "eh(3)", status); + vvd(astrom.em, 0.9998233241709957653, 1e-12, + "iauApco", "em", status); + vvd(astrom.v[0], 0.2078704992916728762e-4, 1e-16, + "iauApco", "v(1)", status); + vvd(astrom.v[1], -0.8955360107151952319e-4, 1e-16, + "iauApco", "v(2)", status); + vvd(astrom.v[2], -0.3863338994288951082e-4, 1e-16, + "iauApco", "v(3)", status); + vvd(astrom.bm1, 0.9999999950277561236, 1e-12, + "iauApco", "bm1", status); + vvd(astrom.bpn[0][0], 0.9999991390295159156, 1e-12, + "iauApco", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0.4978650072505016932e-7, 1e-12, + "iauApco", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0.1312227200000000000e-2, 1e-12, + "iauApco", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], -0.1136336653771609630e-7, 1e-12, + "iauApco", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 0.9999999995713154868, 1e-12, + "iauApco", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], -0.2928086230000000000e-4, 1e-12, + "iauApco", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], -0.1312227200895260194e-2, 1e-12, + "iauApco", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0.2928082217872315680e-4, 1e-12, + "iauApco", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 0.9999991386008323373, 1e-12, + "iauApco", "bpn(3,3)", status); + vvd(astrom.along, -0.5278008060295995734, 1e-12, + "iauApco", "along", status); + vvd(astrom.xpl, 0.1133427418130752958e-5, 1e-17, + "iauApco", "xpl", status); + vvd(astrom.ypl, 0.1453347595780646207e-5, 1e-17, + "iauApco", "ypl", status); + vvd(astrom.sphi, -0.9440115679003211329, 1e-12, + "iauApco", "sphi", status); + vvd(astrom.cphi, 0.3299123514971474711, 1e-12, + "iauApco", "cphi", status); + vvd(astrom.diurab, 0, 0, + "iauApco", "diurab", status); + vvd(astrom.eral, 2.617608903970400427, 1e-12, + "iauApco", "eral", status); + vvd(astrom.refa, 0.2014187790000000000e-3, 1e-15, + "iauApco", "refa", status); + vvd(astrom.refb, -0.2361408310000000000e-6, 1e-18, + "iauApco", "refb", status); + +} + +static void t_apco13(int *status) +/* +** - - - - - - - - - +** t _ a p c o 1 3 +** - - - - - - - - - +** +** Test iauApco13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApco13, vvd, viv +** +** This revision: 2021 January 5 +*/ +{ + double utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, eo; + iauASTROM astrom; + int j; + + + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + + j = iauApco13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom, &eo); + + vvd(astrom.pmt, 13.25248468622475727, 1e-11, + "iauApco13", "pmt", status); + vvd(astrom.eb[0], -0.9741827107320875162, 1e-12, + "iauApco13", "eb(1)", status); + vvd(astrom.eb[1], -0.2115130190489716682, 1e-12, + "iauApco13", "eb(2)", status); + vvd(astrom.eb[2], -0.09179840189496755339, 1e-12, + "iauApco13", "eb(3)", status); + vvd(astrom.eh[0], -0.9736425572586935247, 1e-12, + "iauApco13", "eh(1)", status); + vvd(astrom.eh[1], -0.2092452121603336166, 1e-12, + "iauApco13", "eh(2)", status); + vvd(astrom.eh[2], -0.09075578153885665295, 1e-12, + "iauApco13", "eh(3)", status); + vvd(astrom.em, 0.9998233240913898141, 1e-12, + "iauApco13", "em", status); + vvd(astrom.v[0], 0.2078704994520489246e-4, 1e-16, + "iauApco13", "v(1)", status); + vvd(astrom.v[1], -0.8955360133238868938e-4, 1e-16, + "iauApco13", "v(2)", status); + vvd(astrom.v[2], -0.3863338993055887398e-4, 1e-16, + "iauApco13", "v(3)", status); + vvd(astrom.bm1, 0.9999999950277561004, 1e-12, + "iauApco13", "bm1", status); + vvd(astrom.bpn[0][0], 0.9999991390295147999, 1e-12, + "iauApco13", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0.4978650075315529277e-7, 1e-12, + "iauApco13", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0.001312227200850293372, 1e-12, + "iauApco13", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], -0.1136336652812486604e-7, 1e-12, + "iauApco13", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 0.9999999995713154865, 1e-12, + "iauApco13", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], -0.2928086230975367296e-4, 1e-12, + "iauApco13", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], -0.001312227201745553566, 1e-12, + "iauApco13", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0.2928082218847679162e-4, 1e-12, + "iauApco13", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 0.9999991386008312212, 1e-12, + "iauApco13", "bpn(3,3)", status); + vvd(astrom.along, -0.5278008060295995733, 1e-12, + "iauApco13", "along", status); + vvd(astrom.xpl, 0.1133427418130752958e-5, 1e-17, + "iauApco13", "xpl", status); + vvd(astrom.ypl, 0.1453347595780646207e-5, 1e-17, + "iauApco13", "ypl", status); + vvd(astrom.sphi, -0.9440115679003211329, 1e-12, + "iauApco13", "sphi", status); + vvd(astrom.cphi, 0.3299123514971474711, 1e-12, + "iauApco13", "cphi", status); + vvd(astrom.diurab, 0, 0, + "iauApco13", "diurab", status); + vvd(astrom.eral, 2.617608909189664000, 1e-12, + "iauApco13", "eral", status); + vvd(astrom.refa, 0.2014187785940396921e-3, 1e-15, + "iauApco13", "refa", status); + vvd(astrom.refb, -0.2361408314943696227e-6, 1e-18, + "iauApco13", "refb", status); + vvd(eo, -0.003020548354802412839, 1e-14, + "iauApco13", "eo", status); + viv(j, 0, "iauApco13", "j", status); + +} + +static void t_apcs(int *status) +/* +** - - - - - - - +** t _ a p c s +** - - - - - - - +** +** Test iauApcs function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApcs, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, pv[2][3], ebpv[2][3], ehp[3]; + iauASTROM astrom; + + + date1 = 2456384.5; + date2 = 0.970031644; + pv[0][0] = -1836024.09; + pv[0][1] = 1056607.72; + pv[0][2] = -5998795.26; + pv[1][0] = -77.0361767; + pv[1][1] = -133.310856; + pv[1][2] = 0.0971855934; + ebpv[0][0] = -0.974170438; + ebpv[0][1] = -0.211520082; + ebpv[0][2] = -0.0917583024; + ebpv[1][0] = 0.00364365824; + ebpv[1][1] = -0.0154287319; + ebpv[1][2] = -0.00668922024; + ehp[0] = -0.973458265; + ehp[1] = -0.209215307; + ehp[2] = -0.0906996477; + + iauApcs(date1, date2, pv, ebpv, ehp, &astrom); + + vvd(astrom.pmt, 13.25248468622587269, 1e-11, + "iauApcs", "pmt", status); + vvd(astrom.eb[0], -0.9741827110629881886, 1e-12, + "iauApcs", "eb(1)", status); + vvd(astrom.eb[1], -0.2115130190136415986, 1e-12, + "iauApcs", "eb(2)", status); + vvd(astrom.eb[2], -0.09179840186954412099, 1e-12, + "iauApcs", "eb(3)", status); + vvd(astrom.eh[0], -0.9736425571689454706, 1e-12, + "iauApcs", "eh(1)", status); + vvd(astrom.eh[1], -0.2092452125850435930, 1e-12, + "iauApcs", "eh(2)", status); + vvd(astrom.eh[2], -0.09075578152248299218, 1e-12, + "iauApcs", "eh(3)", status); + vvd(astrom.em, 0.9998233241709796859, 1e-12, + "iauApcs", "em", status); + vvd(astrom.v[0], 0.2078704993282685510e-4, 1e-16, + "iauApcs", "v(1)", status); + vvd(astrom.v[1], -0.8955360106989405683e-4, 1e-16, + "iauApcs", "v(2)", status); + vvd(astrom.v[2], -0.3863338994289409097e-4, 1e-16, + "iauApcs", "v(3)", status); + vvd(astrom.bm1, 0.9999999950277561237, 1e-12, + "iauApcs", "bm1", status); + vvd(astrom.bpn[0][0], 1, 0, + "iauApcs", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0, 0, + "iauApcs", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0, 0, + "iauApcs", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], 0, 0, + "iauApcs", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 1, 0, + "iauApcs", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], 0, 0, + "iauApcs", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], 0, 0, + "iauApcs", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0, 0, + "iauApcs", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 1, 0, + "iauApcs", "bpn(3,3)", status); + +} + +static void t_apcs13(int *status) +/* +** - - - - - - - - - +** t _ a p c s 1 3 +** - - - - - - - - - +** +** Test iauApcs13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApcs13, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, pv[2][3]; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + pv[0][0] = -6241497.16; + pv[0][1] = 401346.896; + pv[0][2] = -1251136.04; + pv[1][0] = -29.264597; + pv[1][1] = -455.021831; + pv[1][2] = 0.0266151194; + + iauApcs13(date1, date2, pv, &astrom); + + vvd(astrom.pmt, 12.65133794027378508, 1e-11, + "iauApcs13", "pmt", status); + vvd(astrom.eb[0], 0.9012691529025250644, 1e-12, + "iauApcs13", "eb(1)", status); + vvd(astrom.eb[1], -0.4173999812023194317, 1e-12, + "iauApcs13", "eb(2)", status); + vvd(astrom.eb[2], -0.1809906511146429670, 1e-12, + "iauApcs13", "eb(3)", status); + vvd(astrom.eh[0], 0.8939939101760130792, 1e-12, + "iauApcs13", "eh(1)", status); + vvd(astrom.eh[1], -0.4111053891734021478, 1e-12, + "iauApcs13", "eh(2)", status); + vvd(astrom.eh[2], -0.1782336880636997374, 1e-12, + "iauApcs13", "eh(3)", status); + vvd(astrom.em, 1.010428384373491095, 1e-12, + "iauApcs13", "em", status); + vvd(astrom.v[0], 0.4279877294121697570e-4, 1e-16, + "iauApcs13", "v(1)", status); + vvd(astrom.v[1], 0.7963255087052120678e-4, 1e-16, + "iauApcs13", "v(2)", status); + vvd(astrom.v[2], 0.3517564013384691531e-4, 1e-16, + "iauApcs13", "v(3)", status); + vvd(astrom.bm1, 0.9999999952947980978, 1e-12, + "iauApcs13", "bm1", status); + vvd(astrom.bpn[0][0], 1, 0, + "iauApcs13", "bpn(1,1)", status); + vvd(astrom.bpn[1][0], 0, 0, + "iauApcs13", "bpn(2,1)", status); + vvd(astrom.bpn[2][0], 0, 0, + "iauApcs13", "bpn(3,1)", status); + vvd(astrom.bpn[0][1], 0, 0, + "iauApcs13", "bpn(1,2)", status); + vvd(astrom.bpn[1][1], 1, 0, + "iauApcs13", "bpn(2,2)", status); + vvd(astrom.bpn[2][1], 0, 0, + "iauApcs13", "bpn(3,2)", status); + vvd(astrom.bpn[0][2], 0, 0, + "iauApcs13", "bpn(1,3)", status); + vvd(astrom.bpn[1][2], 0, 0, + "iauApcs13", "bpn(2,3)", status); + vvd(astrom.bpn[2][2], 1, 0, + "iauApcs13", "bpn(3,3)", status); + +} + +static void t_aper(int *status) +/* +** - - - - - - - +** t _ a p e r +** - - - - - - - +* +** Test iauAper function. +* +** Returned: +** status int FALSE = success, TRUE = fail +* +** Called: iauAper, vvd +* +** This revision: 2013 October 3 +*/ +{ + double theta; + iauASTROM astrom; + + + astrom.along = 1.234; + theta = 5.678; + + iauAper(theta, &astrom); + + vvd(astrom.eral, 6.912000000000000000, 1e-12, + "iauAper", "pmt", status); + +} + +static void t_aper13(int *status) +/* +** - - - - - - - - - +** t _ a p e r 1 3 +** - - - - - - - - - +** +** Test iauAper13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAper13, vvd +** +** This revision: 2013 October 3 +*/ +{ + double ut11, ut12; + iauASTROM astrom; + + + astrom.along = 1.234; + ut11 = 2456165.5; + ut12 = 0.401182685; + + iauAper13(ut11, ut12, &astrom); + + vvd(astrom.eral, 3.316236661789694933, 1e-12, + "iauAper13", "pmt", status); + +} + +static void t_apio(int *status) +/* +** - - - - - - - +** t _ a p i o +** - - - - - - - +** +** Test iauApio function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApio, vvd +** +** This revision: 2021 January 5 +*/ +{ + double sp, theta, elong, phi, hm, xp, yp, refa, refb; + iauASTROM astrom; + + + sp = -3.01974337e-11; + theta = 3.14540971; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + refa = 0.000201418779; + refb = -2.36140831e-7; + + iauApio(sp, theta, elong, phi, hm, xp, yp, refa, refb, &astrom); + + vvd(astrom.along, -0.5278008060295995734, 1e-12, + "iauApio", "along", status); + vvd(astrom.xpl, 0.1133427418130752958e-5, 1e-17, + "iauApio", "xpl", status); + vvd(astrom.ypl, 0.1453347595780646207e-5, 1e-17, + "iauApio", "ypl", status); + vvd(astrom.sphi, -0.9440115679003211329, 1e-12, + "iauApio", "sphi", status); + vvd(astrom.cphi, 0.3299123514971474711, 1e-12, + "iauApio", "cphi", status); + vvd(astrom.diurab, 0.5135843661699913529e-6, 1e-12, + "iauApio", "diurab", status); + vvd(astrom.eral, 2.617608903970400427, 1e-12, + "iauApio", "eral", status); + vvd(astrom.refa, 0.2014187790000000000e-3, 1e-15, + "iauApio", "refa", status); + vvd(astrom.refb, -0.2361408310000000000e-6, 1e-18, + "iauApio", "refb", status); + +} + +static void t_apio13(int *status) +/* +** - - - - - - - - - +** t _ a p i o 1 3 +** - - - - - - - - - +** +** Test iauApio13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApio13, vvd, viv +** +** This revision: 2021 January 5 +*/ +{ + double utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tc, rh, wl; + int j; + iauASTROM astrom; + + + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + + j = iauApio13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom); + + vvd(astrom.along, -0.5278008060295995733, 1e-12, + "iauApio13", "along", status); + vvd(astrom.xpl, 0.1133427418130752958e-5, 1e-17, + "iauApio13", "xpl", status); + vvd(astrom.ypl, 0.1453347595780646207e-5, 1e-17, + "iauApio13", "ypl", status); + vvd(astrom.sphi, -0.9440115679003211329, 1e-12, + "iauApio13", "sphi", status); + vvd(astrom.cphi, 0.3299123514971474711, 1e-12, + "iauApio13", "cphi", status); + vvd(astrom.diurab, 0.5135843661699913529e-6, 1e-12, + "iauApio13", "diurab", status); + vvd(astrom.eral, 2.617608909189664000, 1e-12, + "iauApio13", "eral", status); + vvd(astrom.refa, 0.2014187785940396921e-3, 1e-15, + "iauApio13", "refa", status); + vvd(astrom.refb, -0.2361408314943696227e-6, 1e-18, + "iauApio13", "refb", status); + viv(j, 0, "iauApio13", "j", status); + +} + +static void t_atcc13(int *status) +/* +** - - - - - - - - - +** t _ a t c c 1 3 +** - - - - - - - - - +** +** Test iauAtcc13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAtcc13, vvd +** +** This revision: 2021 April 18 +*/ +{ + double rc, dc, pr, pd, px, rv, date1, date2, ra, da; + + + rc = 2.71; + dc = 0.174; + pr = 1e-5; + pd = 5e-6; + px = 0.1; + rv = 55.0; + date1 = 2456165.5; + date2 = 0.401182685; + + iauAtcc13(rc, dc, pr, pd, px, rv, date1, date2, &ra, &da); + + vvd(ra, 2.710126504531372384, 1e-12, + "iauAtcc13", "ra", status); + vvd(da, 0.1740632537628350152, 1e-12, + "iauAtcc13", "da", status); + +} + +static void t_atccq(int *status) +/* +** - - - - - - - - +** t _ a t c c q +** - - - - - - - - +** +** Test iauAtccq function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApcc13, iauAtccq, vvd +** +** This revision: 2021 April 18 +*/ +{ + double date1, date2, eo, rc, dc, pr, pd, px, rv, ra, da; + iauASTROM astrom; + + date1 = 2456165.5; + date2 = 0.401182685; + iauApci13(date1, date2, &astrom, &eo); + rc = 2.71; + dc = 0.174; + pr = 1e-5; + pd = 5e-6; + px = 0.1; + rv = 55.0; + + iauAtccq(rc, dc, pr, pd, px, rv, &astrom, &ra, &da); + + vvd(ra, 2.710126504531372384, 1e-12, "iauAtccq", "ra", status); + vvd(da, 0.1740632537628350152, 1e-12, "iauAtccq", "da", status); + +} + +static void t_atci13(int *status) +/* +** - - - - - - - - - +** t _ a t c i 1 3 +** - - - - - - - - - +** +** Test iauAtci13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAtci13, vvd +** +** This revision: 2017 March 15 +*/ +{ + double rc, dc, pr, pd, px, rv, date1, date2, ri, di, eo; + + + rc = 2.71; + dc = 0.174; + pr = 1e-5; + pd = 5e-6; + px = 0.1; + rv = 55.0; + date1 = 2456165.5; + date2 = 0.401182685; + + iauAtci13(rc, dc, pr, pd, px, rv, date1, date2, &ri, &di, &eo); + + vvd(ri, 2.710121572968696744, 1e-12, + "iauAtci13", "ri", status); + vvd(di, 0.1729371367219539137, 1e-12, + "iauAtci13", "di", status); + vvd(eo, -0.002900618712657375647, 1e-14, + "iauAtci13", "eo", status); + +} + +static void t_atciq(int *status) +/* +** - - - - - - - - +** t _ a t c i q +** - - - - - - - - +** +** Test iauAtciq function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApci13, iauAtciq, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, eo, rc, dc, pr, pd, px, rv, ri, di; + iauASTROM astrom; + + date1 = 2456165.5; + date2 = 0.401182685; + iauApci13(date1, date2, &astrom, &eo); + rc = 2.71; + dc = 0.174; + pr = 1e-5; + pd = 5e-6; + px = 0.1; + rv = 55.0; + + iauAtciq(rc, dc, pr, pd, px, rv, &astrom, &ri, &di); + + vvd(ri, 2.710121572968696744, 1e-12, "iauAtciq", "ri", status); + vvd(di, 0.1729371367219539137, 1e-12, "iauAtciq", "di", status); + +} + +static void t_atciqn(int *status) +/* +** - - - - - - - - - +** t _ a t c i q n +** - - - - - - - - - +** +** Test iauAtciqn function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApci13, iauAtciqn, vvd +** +** This revision: 2017 March 15 +*/ +{ + iauLDBODY b[3]; + double date1, date2, eo, rc, dc, pr, pd, px, rv, ri, di; + iauASTROM astrom; + + date1 = 2456165.5; + date2 = 0.401182685; + iauApci13(date1, date2, &astrom, &eo); + rc = 2.71; + dc = 0.174; + pr = 1e-5; + pd = 5e-6; + px = 0.1; + rv = 55.0; + b[0].bm = 0.00028574; + b[0].dl = 3e-10; + b[0].pv[0][0] = -7.81014427; + b[0].pv[0][1] = -5.60956681; + b[0].pv[0][2] = -1.98079819; + b[0].pv[1][0] = 0.0030723249; + b[0].pv[1][1] = -0.00406995477; + b[0].pv[1][2] = -0.00181335842; + b[1].bm = 0.00095435; + b[1].dl = 3e-9; + b[1].pv[0][0] = 0.738098796; + b[1].pv[0][1] = 4.63658692; + b[1].pv[0][2] = 1.9693136; + b[1].pv[1][0] = -0.00755816922; + b[1].pv[1][1] = 0.00126913722; + b[1].pv[1][2] = 0.000727999001; + b[2].bm = 1.0; + b[2].dl = 6e-6; + b[2].pv[0][0] = -0.000712174377; + b[2].pv[0][1] = -0.00230478303; + b[2].pv[0][2] = -0.00105865966; + b[2].pv[1][0] = 6.29235213e-6; + b[2].pv[1][1] = -3.30888387e-7; + b[2].pv[1][2] = -2.96486623e-7; + + iauAtciqn ( rc, dc, pr, pd, px, rv, &astrom, 3, b, &ri, &di); + + vvd(ri, 2.710122008104983335, 1e-12, "iauAtciqn", "ri", status); + vvd(di, 0.1729371916492767821, 1e-12, "iauAtciqn", "di", status); + +} + +static void t_atciqz(int *status) +/* +** - - - - - - - - - +** t _ a t c i q z +** - - - - - - - - - +** +** Test iauAtciqz function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApci13, iauAtciqz, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, eo, rc, dc, ri, di; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + iauApci13(date1, date2, &astrom, &eo); + rc = 2.71; + dc = 0.174; + + iauAtciqz(rc, dc, &astrom, &ri, &di); + + vvd(ri, 2.709994899247256984, 1e-12, "iauAtciqz", "ri", status); + vvd(di, 0.1728740720984931891, 1e-12, "iauAtciqz", "di", status); + +} + +static void t_atco13(int *status) +/* +** - - - - - - - - - +** t _ a t c o 1 3 +** - - - - - - - - - +** +** Test iauAtco13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAtco13, vvd, viv +** +** This revision: 2021 January 5 +*/ +{ + double rc, dc, pr, pd, px, rv, utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + aob, zob, hob, dob, rob, eo; + int j; + + + rc = 2.71; + dc = 0.174; + pr = 1e-5; + pd = 5e-6; + px = 0.1; + rv = 55.0; + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + + j = iauAtco13(rc, dc, pr, pd, px, rv, + utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, + &aob, &zob, &hob, &dob, &rob, &eo); + + vvd(aob, 0.9251774485485515207e-1, 1e-12, "iauAtco13", "aob", status); + vvd(zob, 1.407661405256499357, 1e-12, "iauAtco13", "zob", status); + vvd(hob, -0.9265154431529724692e-1, 1e-12, "iauAtco13", "hob", status); + vvd(dob, 0.1716626560072526200, 1e-12, "iauAtco13", "dob", status); + vvd(rob, 2.710260453504961012, 1e-12, "iauAtco13", "rob", status); + vvd(eo, -0.003020548354802412839, 1e-14, "iauAtco13", "eo", status); + viv(j, 0, "iauAtco13", "j", status); + +} + +static void t_atic13(int *status) +/* +** - - - - - - - - - +** t _ a t i c 1 3 +** - - - - - - - - - +** +** Test iauAtic13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAtic13, vvd +** +** This revision: 2017 March 15 +*/ +{ + double ri, di, date1, date2, rc, dc, eo; + + + ri = 2.710121572969038991; + di = 0.1729371367218230438; + date1 = 2456165.5; + date2 = 0.401182685; + + iauAtic13(ri, di, date1, date2, &rc, &dc, &eo); + + vvd(rc, 2.710126504531716819, 1e-12, "iauAtic13", "rc", status); + vvd(dc, 0.1740632537627034482, 1e-12, "iauAtic13", "dc", status); + vvd(eo, -0.002900618712657375647, 1e-14, "iauAtic13", "eo", status); + +} + +static void t_aticq(int *status) +/* +** - - - - - - - - +** t _ a t i c q +** - - - - - - - - +** +** Test iauAticq function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApci13, iauAticq, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, eo, ri, di, rc, dc; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + iauApci13(date1, date2, &astrom, &eo); + ri = 2.710121572969038991; + di = 0.1729371367218230438; + + iauAticq(ri, di, &astrom, &rc, &dc); + + vvd(rc, 2.710126504531716819, 1e-12, "iauAticq", "rc", status); + vvd(dc, 0.1740632537627034482, 1e-12, "iauAticq", "dc", status); + +} + +static void t_aticqn(int *status) +/* +** - - - - - - - - - +** t _ a t i c q n +** - - - - - - - - - +** +** Test iauAticqn function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApci13, iauAticqn, vvd +** +** This revision: 2017 March 15 +*/ +{ + double date1, date2, eo, ri, di, rc, dc; + iauLDBODY b[3]; + iauASTROM astrom; + + + date1 = 2456165.5; + date2 = 0.401182685; + iauApci13(date1, date2, &astrom, &eo); + ri = 2.709994899247599271; + di = 0.1728740720983623469; + b[0].bm = 0.00028574; + b[0].dl = 3e-10; + b[0].pv[0][0] = -7.81014427; + b[0].pv[0][1] = -5.60956681; + b[0].pv[0][2] = -1.98079819; + b[0].pv[1][0] = 0.0030723249; + b[0].pv[1][1] = -0.00406995477; + b[0].pv[1][2] = -0.00181335842; + b[1].bm = 0.00095435; + b[1].dl = 3e-9; + b[1].pv[0][0] = 0.738098796; + b[1].pv[0][1] = 4.63658692; + b[1].pv[0][2] = 1.9693136; + b[1].pv[1][0] = -0.00755816922; + b[1].pv[1][1] = 0.00126913722; + b[1].pv[1][2] = 0.000727999001; + b[2].bm = 1.0; + b[2].dl = 6e-6; + b[2].pv[0][0] = -0.000712174377; + b[2].pv[0][1] = -0.00230478303; + b[2].pv[0][2] = -0.00105865966; + b[2].pv[1][0] = 6.29235213e-6; + b[2].pv[1][1] = -3.30888387e-7; + b[2].pv[1][2] = -2.96486623e-7; + + iauAticqn(ri, di, &astrom, 3, b, &rc, &dc); + + vvd(rc, 2.709999575033027333, 1e-12, "iauAtciqn", "rc", status); + vvd(dc, 0.1739999656316469990, 1e-12, "iauAtciqn", "dc", status); + +} + +static void t_atio13(int *status) +/* +** - - - - - - - - - +** t _ a t i o 1 3 +** - - - - - - - - - +** +** Test iauAtio13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAtio13, vvd, viv +** +** This revision: 2021 January 5 +*/ +{ + double ri, di, utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, aob, zob, hob, dob, rob; + int j; + + + ri = 2.710121572969038991; + di = 0.1729371367218230438; + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + + j = iauAtio13(ri, di, utc1, utc2, dut1, elong, phi, hm, + xp, yp, phpa, tc, rh, wl, + &aob, &zob, &hob, &dob, &rob); + + vvd(aob, 0.9233952224895122499e-1, 1e-12, "iauAtio13", "aob", status); + vvd(zob, 1.407758704513549991, 1e-12, "iauAtio13", "zob", status); + vvd(hob, -0.9247619879881698140e-1, 1e-12, "iauAtio13", "hob", status); + vvd(dob, 0.1717653435756234676, 1e-12, "iauAtio13", "dob", status); + vvd(rob, 2.710085107988480746, 1e-12, "iauAtio13", "rob", status); + viv(j, 0, "iauAtio13", "j", status); + +} + +static void t_atioq(int *status) +/* +** - - - - - - - - +** t _ a t i o q +** - - - - - - - - +** +** Test iauAtioq function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauApio13, iauAtioq, vvd, viv +** +** This revision: 2021 January 5 +*/ +{ + double utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, ri, di, aob, zob, hob, dob, rob; + iauASTROM astrom; + + + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + (void) iauApio13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom); + ri = 2.710121572969038991; + di = 0.1729371367218230438; + + iauAtioq(ri, di, &astrom, &aob, &zob, &hob, &dob, &rob); + + vvd(aob, 0.9233952224895122499e-1, 1e-12, "iauAtioq", "aob", status); + vvd(zob, 1.407758704513549991, 1e-12, "iauAtioq", "zob", status); + vvd(hob, -0.9247619879881698140e-1, 1e-12, "iauAtioq", "hob", status); + vvd(dob, 0.1717653435756234676, 1e-12, "iauAtioq", "dob", status); + vvd(rob, 2.710085107988480746, 1e-12, "iauAtioq", "rob", status); + +} + +static void t_atoc13(int *status) +/* +** - - - - - - - - - +** t _ a t o c 1 3 +** - - - - - - - - - +** +** Test iauAtoc13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAtoc13, vvd, viv +** +** This revision: 2021 January 5 +*/ +{ + double utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + ob1, ob2, rc, dc; + int j; + + + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + + ob1 = 2.710085107986886201; + ob2 = 0.1717653435758265198; + j = iauAtoc13 ( "R", ob1, ob2, utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + &rc, &dc); + vvd(rc, 2.709956744659136129, 1e-12, "iauAtoc13", "R/rc", status); + vvd(dc, 0.1741696500898471362, 1e-12, "iauAtoc13", "R/dc", status); + viv(j, 0, "iauAtoc13", "R/j", status); + + ob1 = -0.09247619879782006106; + ob2 = 0.1717653435758265198; + j = iauAtoc13 ( "H", ob1, ob2, utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + &rc, &dc); + vvd(rc, 2.709956744659734086, 1e-12, "iauAtoc13", "H/rc", status); + vvd(dc, 0.1741696500898471362, 1e-12, "iauAtoc13", "H/dc", status); + viv(j, 0, "iauAtoc13", "H/j", status); + + ob1 = 0.09233952224794989993; + ob2 = 1.407758704513722461; + j = iauAtoc13 ( "A", ob1, ob2, utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + &rc, &dc); + vvd(rc, 2.709956744659734086, 1e-12, "iauAtoc13", "A/rc", status); + vvd(dc, 0.1741696500898471366, 1e-12, "iauAtoc13", "A/dc", status); + viv(j, 0, "iauAtoc13", "A/j", status); + +} + +static void t_atoi13(int *status) +/* +** - - - - - - - - - +** t _ a t o i 1 3 +** - - - - - - - - - +** +** Test iauAtoi13 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauAtoi13, vvd, viv +** +** This revision: 2021 January 5 +*/ +{ + double utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tc, rh, wl, + ob1, ob2, ri, di; + int j; + + + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + + ob1 = 2.710085107986886201; + ob2 = 0.1717653435758265198; + j = iauAtoi13 ( "R", ob1, ob2, utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + &ri, &di); + vvd(ri, 2.710121574447540810, 1e-12, "iauAtoi13", "R/ri", status); + vvd(di, 0.1729371839116608778, 1e-12, "iauAtoi13", "R/di", status); + viv(j, 0, "iauAtoi13", "R/J", status); + + ob1 = -0.09247619879782006106; + ob2 = 0.1717653435758265198; + j = iauAtoi13 ( "H", ob1, ob2, utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + &ri, &di); + vvd(ri, 2.710121574448138676, 1e-12, "iauAtoi13", "H/ri", status); + vvd(di, 0.1729371839116608778, 1e-12, "iauAtoi13", "H/di", status); + viv(j, 0, "iauAtoi13", "H/J", status); + + ob1 = 0.09233952224794989993; + ob2 = 1.407758704513722461; + j = iauAtoi13 ( "A", ob1, ob2, utc1, utc2, dut1, + elong, phi, hm, xp, yp, phpa, tc, rh, wl, + &ri, &di); + vvd(ri, 2.710121574448138676, 1e-12, "iauAtoi13", "A/ri", status); + vvd(di, 0.1729371839116608781, 1e-12, "iauAtoi13", "A/di", status); + viv(j, 0, "iauAtoi13", "A/J", status); + +} + +static void t_atoiq(int *status) +/* +** - - - - - - - - +** t _ a t o i q +** - - - - - - - - +* +** Test iauAtoiq function. +* +** Returned: +** status int FALSE = success, TRUE = fail +* +** Called: iauApio13, iauAtoiq, vvd +* +** This revision: 2021 January 5 +*/ +{ + double utc1, utc2, dut1, elong, phi, hm, xp, yp, phpa, tc, rh, wl, + ob1, ob2, ri, di; + iauASTROM astrom; + + + utc1 = 2456384.5; + utc2 = 0.969254051; + dut1 = 0.1550675; + elong = -0.527800806; + phi = -1.2345856; + hm = 2738.0; + xp = 2.47230737e-7; + yp = 1.82640464e-6; + phpa = 731.0; + tc = 12.8; + rh = 0.59; + wl = 0.55; + (void) iauApio13(utc1, utc2, dut1, elong, phi, hm, xp, yp, + phpa, tc, rh, wl, &astrom); + + ob1 = 2.710085107986886201; + ob2 = 0.1717653435758265198; + iauAtoiq("R", ob1, ob2, &astrom, &ri, &di); + vvd(ri, 2.710121574447540810, 1e-12, + "iauAtoiq", "R/ri", status); + vvd(di, 0.17293718391166087785, 1e-12, + "iauAtoiq", "R/di", status); + + ob1 = -0.09247619879782006106; + ob2 = 0.1717653435758265198; + iauAtoiq("H", ob1, ob2, &astrom, &ri, &di); + vvd(ri, 2.710121574448138676, 1e-12, + "iauAtoiq", "H/ri", status); + vvd(di, 0.1729371839116608778, 1e-12, + "iauAtoiq", "H/di", status); + + ob1 = 0.09233952224794989993; + ob2 = 1.407758704513722461; + iauAtoiq("A", ob1, ob2, &astrom, &ri, &di); + vvd(ri, 2.710121574448138676, 1e-12, + "iauAtoiq", "A/ri", status); + vvd(di, 0.1729371839116608781, 1e-12, + "iauAtoiq", "A/di", status); + +} + +static void t_bi00(int *status) +/* +** - - - - - - - +** t _ b i 0 0 +** - - - - - - - +** +** Test iauBi00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauBi00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsibi, depsbi, dra; + + iauBi00(&dpsibi, &depsbi, &dra); + + vvd(dpsibi, -0.2025309152835086613e-6, 1e-12, + "iauBi00", "dpsibi", status); + vvd(depsbi, -0.3306041454222147847e-7, 1e-12, + "iauBi00", "depsbi", status); + vvd(dra, -0.7078279744199225506e-7, 1e-12, + "iauBi00", "dra", status); +} + +static void t_bp00(int *status) +/* +** - - - - - - - +** t _ b p 0 0 +** - - - - - - - +** +** Test iauBp00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauBp00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rb[3][3], rp[3][3], rbp[3][3]; + + + iauBp00(2400000.5, 50123.9999, rb, rp, rbp); + + vvd(rb[0][0], 0.9999999999999942498, 1e-12, + "iauBp00", "rb11", status); + vvd(rb[0][1], -0.7078279744199196626e-7, 1e-16, + "iauBp00", "rb12", status); + vvd(rb[0][2], 0.8056217146976134152e-7, 1e-16, + "iauBp00", "rb13", status); + vvd(rb[1][0], 0.7078279477857337206e-7, 1e-16, + "iauBp00", "rb21", status); + vvd(rb[1][1], 0.9999999999999969484, 1e-12, + "iauBp00", "rb22", status); + vvd(rb[1][2], 0.3306041454222136517e-7, 1e-16, + "iauBp00", "rb23", status); + vvd(rb[2][0], -0.8056217380986972157e-7, 1e-16, + "iauBp00", "rb31", status); + vvd(rb[2][1], -0.3306040883980552500e-7, 1e-16, + "iauBp00", "rb32", status); + vvd(rb[2][2], 0.9999999999999962084, 1e-12, + "iauBp00", "rb33", status); + + vvd(rp[0][0], 0.9999995504864048241, 1e-12, + "iauBp00", "rp11", status); + vvd(rp[0][1], 0.8696113836207084411e-3, 1e-14, + "iauBp00", "rp12", status); + vvd(rp[0][2], 0.3778928813389333402e-3, 1e-14, + "iauBp00", "rp13", status); + vvd(rp[1][0], -0.8696113818227265968e-3, 1e-14, + "iauBp00", "rp21", status); + vvd(rp[1][1], 0.9999996218879365258, 1e-12, + "iauBp00", "rp22", status); + vvd(rp[1][2], -0.1690679263009242066e-6, 1e-14, + "iauBp00", "rp23", status); + vvd(rp[2][0], -0.3778928854764695214e-3, 1e-14, + "iauBp00", "rp31", status); + vvd(rp[2][1], -0.1595521004195286491e-6, 1e-14, + "iauBp00", "rp32", status); + vvd(rp[2][2], 0.9999999285984682756, 1e-12, + "iauBp00", "rp33", status); + + vvd(rbp[0][0], 0.9999995505175087260, 1e-12, + "iauBp00", "rbp11", status); + vvd(rbp[0][1], 0.8695405883617884705e-3, 1e-14, + "iauBp00", "rbp12", status); + vvd(rbp[0][2], 0.3779734722239007105e-3, 1e-14, + "iauBp00", "rbp13", status); + vvd(rbp[1][0], -0.8695405990410863719e-3, 1e-14, + "iauBp00", "rbp21", status); + vvd(rbp[1][1], 0.9999996219494925900, 1e-12, + "iauBp00", "rbp22", status); + vvd(rbp[1][2], -0.1360775820404982209e-6, 1e-14, + "iauBp00", "rbp23", status); + vvd(rbp[2][0], -0.3779734476558184991e-3, 1e-14, + "iauBp00", "rbp31", status); + vvd(rbp[2][1], -0.1925857585832024058e-6, 1e-14, + "iauBp00", "rbp32", status); + vvd(rbp[2][2], 0.9999999285680153377, 1e-12, + "iauBp00", "rbp33", status); +} + +static void t_bp06(int *status) +/* +** - - - - - - - +** t _ b p 0 6 +** - - - - - - - +** +** Test iauBp06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauBp06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rb[3][3], rp[3][3], rbp[3][3]; + + + iauBp06(2400000.5, 50123.9999, rb, rp, rbp); + + vvd(rb[0][0], 0.9999999999999942497, 1e-12, + "iauBp06", "rb11", status); + vvd(rb[0][1], -0.7078368960971557145e-7, 1e-14, + "iauBp06", "rb12", status); + vvd(rb[0][2], 0.8056213977613185606e-7, 1e-14, + "iauBp06", "rb13", status); + vvd(rb[1][0], 0.7078368694637674333e-7, 1e-14, + "iauBp06", "rb21", status); + vvd(rb[1][1], 0.9999999999999969484, 1e-12, + "iauBp06", "rb22", status); + vvd(rb[1][2], 0.3305943742989134124e-7, 1e-14, + "iauBp06", "rb23", status); + vvd(rb[2][0], -0.8056214211620056792e-7, 1e-14, + "iauBp06", "rb31", status); + vvd(rb[2][1], -0.3305943172740586950e-7, 1e-14, + "iauBp06", "rb32", status); + vvd(rb[2][2], 0.9999999999999962084, 1e-12, + "iauBp06", "rb33", status); + + vvd(rp[0][0], 0.9999995504864960278, 1e-12, + "iauBp06", "rp11", status); + vvd(rp[0][1], 0.8696112578855404832e-3, 1e-14, + "iauBp06", "rp12", status); + vvd(rp[0][2], 0.3778929293341390127e-3, 1e-14, + "iauBp06", "rp13", status); + vvd(rp[1][0], -0.8696112560510186244e-3, 1e-14, + "iauBp06", "rp21", status); + vvd(rp[1][1], 0.9999996218880458820, 1e-12, + "iauBp06", "rp22", status); + vvd(rp[1][2], -0.1691646168941896285e-6, 1e-14, + "iauBp06", "rp23", status); + vvd(rp[2][0], -0.3778929335557603418e-3, 1e-14, + "iauBp06", "rp31", status); + vvd(rp[2][1], -0.1594554040786495076e-6, 1e-14, + "iauBp06", "rp32", status); + vvd(rp[2][2], 0.9999999285984501222, 1e-12, + "iauBp06", "rp33", status); + + vvd(rbp[0][0], 0.9999995505176007047, 1e-12, + "iauBp06", "rbp11", status); + vvd(rbp[0][1], 0.8695404617348208406e-3, 1e-14, + "iauBp06", "rbp12", status); + vvd(rbp[0][2], 0.3779735201865589104e-3, 1e-14, + "iauBp06", "rbp13", status); + vvd(rbp[1][0], -0.8695404723772031414e-3, 1e-14, + "iauBp06", "rbp21", status); + vvd(rbp[1][1], 0.9999996219496027161, 1e-12, + "iauBp06", "rbp22", status); + vvd(rbp[1][2], -0.1361752497080270143e-6, 1e-14, + "iauBp06", "rbp23", status); + vvd(rbp[2][0], -0.3779734957034089490e-3, 1e-14, + "iauBp06", "rbp31", status); + vvd(rbp[2][1], -0.1924880847894457113e-6, 1e-14, + "iauBp06", "rbp32", status); + vvd(rbp[2][2], 0.9999999285679971958, 1e-12, + "iauBp06", "rbp33", status); +} + +static void t_bpn2xy(int *status) +/* +** - - - - - - - - - +** t _ b p n 2 x y +** - - - - - - - - - +** +** Test iauBpn2xy function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauBpn2xy, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbpn[3][3], x, y; + + + rbpn[0][0] = 9.999962358680738e-1; + rbpn[0][1] = -2.516417057665452e-3; + rbpn[0][2] = -1.093569785342370e-3; + + rbpn[1][0] = 2.516462370370876e-3; + rbpn[1][1] = 9.999968329010883e-1; + rbpn[1][2] = 4.006159587358310e-5; + + rbpn[2][0] = 1.093465510215479e-3; + rbpn[2][1] = -4.281337229063151e-5; + rbpn[2][2] = 9.999994012499173e-1; + + iauBpn2xy(rbpn, &x, &y); + + vvd(x, 1.093465510215479e-3, 1e-12, "iauBpn2xy", "x", status); + vvd(y, -4.281337229063151e-5, 1e-12, "iauBpn2xy", "y", status); + +} + +static void t_c2i00a(int *status) +/* +** - - - - - - - - - +** t _ c 2 i 0 0 a +** - - - - - - - - - +** +** Test iauC2i00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2i00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rc2i[3][3]; + + + iauC2i00a(2400000.5, 53736.0, rc2i); + + vvd(rc2i[0][0], 0.9999998323037165557, 1e-12, + "iauC2i00a", "11", status); + vvd(rc2i[0][1], 0.5581526348992140183e-9, 1e-12, + "iauC2i00a", "12", status); + vvd(rc2i[0][2], -0.5791308477073443415e-3, 1e-12, + "iauC2i00a", "13", status); + + vvd(rc2i[1][0], -0.2384266227870752452e-7, 1e-12, + "iauC2i00a", "21", status); + vvd(rc2i[1][1], 0.9999999991917405258, 1e-12, + "iauC2i00a", "22", status); + vvd(rc2i[1][2], -0.4020594955028209745e-4, 1e-12, + "iauC2i00a", "23", status); + + vvd(rc2i[2][0], 0.5791308472168152904e-3, 1e-12, + "iauC2i00a", "31", status); + vvd(rc2i[2][1], 0.4020595661591500259e-4, 1e-12, + "iauC2i00a", "32", status); + vvd(rc2i[2][2], 0.9999998314954572304, 1e-12, + "iauC2i00a", "33", status); + +} + +static void t_c2i00b(int *status) +/* +** - - - - - - - - - +** t _ c 2 i 0 0 b +** - - - - - - - - - +** +** Test iauC2i00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2i00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rc2i[3][3]; + + + iauC2i00b(2400000.5, 53736.0, rc2i); + + vvd(rc2i[0][0], 0.9999998323040954356, 1e-12, + "iauC2i00b", "11", status); + vvd(rc2i[0][1], 0.5581526349131823372e-9, 1e-12, + "iauC2i00b", "12", status); + vvd(rc2i[0][2], -0.5791301934855394005e-3, 1e-12, + "iauC2i00b", "13", status); + + vvd(rc2i[1][0], -0.2384239285499175543e-7, 1e-12, + "iauC2i00b", "21", status); + vvd(rc2i[1][1], 0.9999999991917574043, 1e-12, + "iauC2i00b", "22", status); + vvd(rc2i[1][2], -0.4020552974819030066e-4, 1e-12, + "iauC2i00b", "23", status); + + vvd(rc2i[2][0], 0.5791301929950208873e-3, 1e-12, + "iauC2i00b", "31", status); + vvd(rc2i[2][1], 0.4020553681373720832e-4, 1e-12, + "iauC2i00b", "32", status); + vvd(rc2i[2][2], 0.9999998314958529887, 1e-12, + "iauC2i00b", "33", status); + +} + +static void t_c2i06a(int *status) +/* +** - - - - - - - - - +** t _ c 2 i 0 6 a +** - - - - - - - - - +** +** Test iauC2i06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2i06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rc2i[3][3]; + + + iauC2i06a(2400000.5, 53736.0, rc2i); + + vvd(rc2i[0][0], 0.9999998323037159379, 1e-12, + "iauC2i06a", "11", status); + vvd(rc2i[0][1], 0.5581121329587613787e-9, 1e-12, + "iauC2i06a", "12", status); + vvd(rc2i[0][2], -0.5791308487740529749e-3, 1e-12, + "iauC2i06a", "13", status); + + vvd(rc2i[1][0], -0.2384253169452306581e-7, 1e-12, + "iauC2i06a", "21", status); + vvd(rc2i[1][1], 0.9999999991917467827, 1e-12, + "iauC2i06a", "22", status); + vvd(rc2i[1][2], -0.4020579392895682558e-4, 1e-12, + "iauC2i06a", "23", status); + + vvd(rc2i[2][0], 0.5791308482835292617e-3, 1e-12, + "iauC2i06a", "31", status); + vvd(rc2i[2][1], 0.4020580099454020310e-4, 1e-12, + "iauC2i06a", "32", status); + vvd(rc2i[2][2], 0.9999998314954628695, 1e-12, + "iauC2i06a", "33", status); + +} + +static void t_c2ibpn(int *status) +/* +** - - - - - - - - - +** t _ c 2 i b p n +** - - - - - - - - - +** +** Test iauC2ibpn function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2ibpn, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbpn[3][3], rc2i[3][3]; + + + rbpn[0][0] = 9.999962358680738e-1; + rbpn[0][1] = -2.516417057665452e-3; + rbpn[0][2] = -1.093569785342370e-3; + + rbpn[1][0] = 2.516462370370876e-3; + rbpn[1][1] = 9.999968329010883e-1; + rbpn[1][2] = 4.006159587358310e-5; + + rbpn[2][0] = 1.093465510215479e-3; + rbpn[2][1] = -4.281337229063151e-5; + rbpn[2][2] = 9.999994012499173e-1; + + iauC2ibpn(2400000.5, 50123.9999, rbpn, rc2i); + + vvd(rc2i[0][0], 0.9999994021664089977, 1e-12, + "iauC2ibpn", "11", status); + vvd(rc2i[0][1], -0.3869195948017503664e-8, 1e-12, + "iauC2ibpn", "12", status); + vvd(rc2i[0][2], -0.1093465511383285076e-2, 1e-12, + "iauC2ibpn", "13", status); + + vvd(rc2i[1][0], 0.5068413965715446111e-7, 1e-12, + "iauC2ibpn", "21", status); + vvd(rc2i[1][1], 0.9999999990835075686, 1e-12, + "iauC2ibpn", "22", status); + vvd(rc2i[1][2], 0.4281334246452708915e-4, 1e-12, + "iauC2ibpn", "23", status); + + vvd(rc2i[2][0], 0.1093465510215479000e-2, 1e-12, + "iauC2ibpn", "31", status); + vvd(rc2i[2][1], -0.4281337229063151000e-4, 1e-12, + "iauC2ibpn", "32", status); + vvd(rc2i[2][2], 0.9999994012499173103, 1e-12, + "iauC2ibpn", "33", status); + +} + +static void t_c2ixy(int *status) +/* +** - - - - - - - - +** t _ c 2 i x y +** - - - - - - - - +** +** Test iauC2ixy function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2ixy, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y, rc2i[3][3]; + + + x = 0.5791308486706011000e-3; + y = 0.4020579816732961219e-4; + + iauC2ixy(2400000.5, 53736, x, y, rc2i); + + vvd(rc2i[0][0], 0.9999998323037157138, 1e-12, + "iauC2ixy", "11", status); + vvd(rc2i[0][1], 0.5581526349032241205e-9, 1e-12, + "iauC2ixy", "12", status); + vvd(rc2i[0][2], -0.5791308491611263745e-3, 1e-12, + "iauC2ixy", "13", status); + + vvd(rc2i[1][0], -0.2384257057469842953e-7, 1e-12, + "iauC2ixy", "21", status); + vvd(rc2i[1][1], 0.9999999991917468964, 1e-12, + "iauC2ixy", "22", status); + vvd(rc2i[1][2], -0.4020579110172324363e-4, 1e-12, + "iauC2ixy", "23", status); + + vvd(rc2i[2][0], 0.5791308486706011000e-3, 1e-12, + "iauC2ixy", "31", status); + vvd(rc2i[2][1], 0.4020579816732961219e-4, 1e-12, + "iauC2ixy", "32", status); + vvd(rc2i[2][2], 0.9999998314954627590, 1e-12, + "iauC2ixy", "33", status); + +} + +static void t_c2ixys(int *status) +/* +** - - - - - - - - - +** t _ c 2 i x y s +** - - - - - - - - - +** +** Test iauC2ixys function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2ixys, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y, s, rc2i[3][3]; + + + x = 0.5791308486706011000e-3; + y = 0.4020579816732961219e-4; + s = -0.1220040848472271978e-7; + + iauC2ixys(x, y, s, rc2i); + + vvd(rc2i[0][0], 0.9999998323037157138, 1e-12, + "iauC2ixys", "11", status); + vvd(rc2i[0][1], 0.5581984869168499149e-9, 1e-12, + "iauC2ixys", "12", status); + vvd(rc2i[0][2], -0.5791308491611282180e-3, 1e-12, + "iauC2ixys", "13", status); + + vvd(rc2i[1][0], -0.2384261642670440317e-7, 1e-12, + "iauC2ixys", "21", status); + vvd(rc2i[1][1], 0.9999999991917468964, 1e-12, + "iauC2ixys", "22", status); + vvd(rc2i[1][2], -0.4020579110169668931e-4, 1e-12, + "iauC2ixys", "23", status); + + vvd(rc2i[2][0], 0.5791308486706011000e-3, 1e-12, + "iauC2ixys", "31", status); + vvd(rc2i[2][1], 0.4020579816732961219e-4, 1e-12, + "iauC2ixys", "32", status); + vvd(rc2i[2][2], 0.9999998314954627590, 1e-12, + "iauC2ixys", "33", status); + +} + +static void t_c2s(int *status) +/* +** - - - - - - +** t _ c 2 s +** - - - - - - +** +** Test iauC2s function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2s, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3], theta, phi; + + + p[0] = 100.0; + p[1] = -50.0; + p[2] = 25.0; + + iauC2s(p, &theta, &phi); + + vvd(theta, -0.4636476090008061162, 1e-14, "iauC2s", "theta", status); + vvd(phi, 0.2199879773954594463, 1e-14, "iauC2s", "phi", status); + +} + +static void t_c2t00a(int *status) +/* +** - - - - - - - - - +** t _ c 2 t 0 0 a +** - - - - - - - - - +** +** Test iauC2t00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2t00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double tta, ttb, uta, utb, xp, yp, rc2t[3][3]; + + + tta = 2400000.5; + uta = 2400000.5; + ttb = 53736.0; + utb = 53736.0; + xp = 2.55060238e-7; + yp = 1.860359247e-6; + + iauC2t00a(tta, ttb, uta, utb, xp, yp, rc2t); + + vvd(rc2t[0][0], -0.1810332128307182668, 1e-12, + "iauC2t00a", "11", status); + vvd(rc2t[0][1], 0.9834769806938457836, 1e-12, + "iauC2t00a", "12", status); + vvd(rc2t[0][2], 0.6555535638688341725e-4, 1e-12, + "iauC2t00a", "13", status); + + vvd(rc2t[1][0], -0.9834768134135984552, 1e-12, + "iauC2t00a", "21", status); + vvd(rc2t[1][1], -0.1810332203649520727, 1e-12, + "iauC2t00a", "22", status); + vvd(rc2t[1][2], 0.5749801116141056317e-3, 1e-12, + "iauC2t00a", "23", status); + + vvd(rc2t[2][0], 0.5773474014081406921e-3, 1e-12, + "iauC2t00a", "31", status); + vvd(rc2t[2][1], 0.3961832391770163647e-4, 1e-12, + "iauC2t00a", "32", status); + vvd(rc2t[2][2], 0.9999998325501692289, 1e-12, + "iauC2t00a", "33", status); + +} + +static void t_c2t00b(int *status) +/* +** - - - - - - - - - +** t _ c 2 t 0 0 b +** - - - - - - - - - +** +** Test iauC2t00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2t00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double tta, ttb, uta, utb, xp, yp, rc2t[3][3]; + + + tta = 2400000.5; + uta = 2400000.5; + ttb = 53736.0; + utb = 53736.0; + xp = 2.55060238e-7; + yp = 1.860359247e-6; + + iauC2t00b(tta, ttb, uta, utb, xp, yp, rc2t); + + vvd(rc2t[0][0], -0.1810332128439678965, 1e-12, + "iauC2t00b", "11", status); + vvd(rc2t[0][1], 0.9834769806913872359, 1e-12, + "iauC2t00b", "12", status); + vvd(rc2t[0][2], 0.6555565082458415611e-4, 1e-12, + "iauC2t00b", "13", status); + + vvd(rc2t[1][0], -0.9834768134115435923, 1e-12, + "iauC2t00b", "21", status); + vvd(rc2t[1][1], -0.1810332203784001946, 1e-12, + "iauC2t00b", "22", status); + vvd(rc2t[1][2], 0.5749793922030017230e-3, 1e-12, + "iauC2t00b", "23", status); + + vvd(rc2t[2][0], 0.5773467471863534901e-3, 1e-12, + "iauC2t00b", "31", status); + vvd(rc2t[2][1], 0.3961790411549945020e-4, 1e-12, + "iauC2t00b", "32", status); + vvd(rc2t[2][2], 0.9999998325505635738, 1e-12, + "iauC2t00b", "33", status); + +} + +static void t_c2t06a(int *status) +/* +** - - - - - - - - - +** t _ c 2 t 0 6 a +** - - - - - - - - - +** +** Test iauC2t06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2t06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double tta, ttb, uta, utb, xp, yp, rc2t[3][3]; + + + tta = 2400000.5; + uta = 2400000.5; + ttb = 53736.0; + utb = 53736.0; + xp = 2.55060238e-7; + yp = 1.860359247e-6; + + iauC2t06a(tta, ttb, uta, utb, xp, yp, rc2t); + + vvd(rc2t[0][0], -0.1810332128305897282, 1e-12, + "iauC2t06a", "11", status); + vvd(rc2t[0][1], 0.9834769806938592296, 1e-12, + "iauC2t06a", "12", status); + vvd(rc2t[0][2], 0.6555550962998436505e-4, 1e-12, + "iauC2t06a", "13", status); + + vvd(rc2t[1][0], -0.9834768134136214897, 1e-12, + "iauC2t06a", "21", status); + vvd(rc2t[1][1], -0.1810332203649130832, 1e-12, + "iauC2t06a", "22", status); + vvd(rc2t[1][2], 0.5749800844905594110e-3, 1e-12, + "iauC2t06a", "23", status); + + vvd(rc2t[2][0], 0.5773474024748545878e-3, 1e-12, + "iauC2t06a", "31", status); + vvd(rc2t[2][1], 0.3961816829632690581e-4, 1e-12, + "iauC2t06a", "32", status); + vvd(rc2t[2][2], 0.9999998325501747785, 1e-12, + "iauC2t06a", "33", status); + +} + +static void t_c2tcio(int *status) +/* +** - - - - - - - - - +** t _ c 2 t c i o +** - - - - - - - - - +** +** Test iauC2tcio function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2tcio, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rc2i[3][3], era, rpom[3][3], rc2t[3][3]; + + + rc2i[0][0] = 0.9999998323037164738; + rc2i[0][1] = 0.5581526271714303683e-9; + rc2i[0][2] = -0.5791308477073443903e-3; + + rc2i[1][0] = -0.2384266227524722273e-7; + rc2i[1][1] = 0.9999999991917404296; + rc2i[1][2] = -0.4020594955030704125e-4; + + rc2i[2][0] = 0.5791308472168153320e-3; + rc2i[2][1] = 0.4020595661593994396e-4; + rc2i[2][2] = 0.9999998314954572365; + + era = 1.75283325530307; + + rpom[0][0] = 0.9999999999999674705; + rpom[0][1] = -0.1367174580728847031e-10; + rpom[0][2] = 0.2550602379999972723e-6; + + rpom[1][0] = 0.1414624947957029721e-10; + rpom[1][1] = 0.9999999999982694954; + rpom[1][2] = -0.1860359246998866338e-5; + + rpom[2][0] = -0.2550602379741215275e-6; + rpom[2][1] = 0.1860359247002413923e-5; + rpom[2][2] = 0.9999999999982369658; + + + iauC2tcio(rc2i, era, rpom, rc2t); + + vvd(rc2t[0][0], -0.1810332128307110439, 1e-12, + "iauC2tcio", "11", status); + vvd(rc2t[0][1], 0.9834769806938470149, 1e-12, + "iauC2tcio", "12", status); + vvd(rc2t[0][2], 0.6555535638685466874e-4, 1e-12, + "iauC2tcio", "13", status); + + vvd(rc2t[1][0], -0.9834768134135996657, 1e-12, + "iauC2tcio", "21", status); + vvd(rc2t[1][1], -0.1810332203649448367, 1e-12, + "iauC2tcio", "22", status); + vvd(rc2t[1][2], 0.5749801116141106528e-3, 1e-12, + "iauC2tcio", "23", status); + + vvd(rc2t[2][0], 0.5773474014081407076e-3, 1e-12, + "iauC2tcio", "31", status); + vvd(rc2t[2][1], 0.3961832391772658944e-4, 1e-12, + "iauC2tcio", "32", status); + vvd(rc2t[2][2], 0.9999998325501691969, 1e-12, + "iauC2tcio", "33", status); + +} + +static void t_c2teqx(int *status) +/* +** - - - - - - - - - +** t _ c 2 t e q x +** - - - - - - - - - +** +** Test iauC2teqx function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2teqx, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbpn[3][3], gst, rpom[3][3], rc2t[3][3]; + + + rbpn[0][0] = 0.9999989440476103608; + rbpn[0][1] = -0.1332881761240011518e-2; + rbpn[0][2] = -0.5790767434730085097e-3; + + rbpn[1][0] = 0.1332858254308954453e-2; + rbpn[1][1] = 0.9999991109044505944; + rbpn[1][2] = -0.4097782710401555759e-4; + + rbpn[2][0] = 0.5791308472168153320e-3; + rbpn[2][1] = 0.4020595661593994396e-4; + rbpn[2][2] = 0.9999998314954572365; + + gst = 1.754166138040730516; + + rpom[0][0] = 0.9999999999999674705; + rpom[0][1] = -0.1367174580728847031e-10; + rpom[0][2] = 0.2550602379999972723e-6; + + rpom[1][0] = 0.1414624947957029721e-10; + rpom[1][1] = 0.9999999999982694954; + rpom[1][2] = -0.1860359246998866338e-5; + + rpom[2][0] = -0.2550602379741215275e-6; + rpom[2][1] = 0.1860359247002413923e-5; + rpom[2][2] = 0.9999999999982369658; + + iauC2teqx(rbpn, gst, rpom, rc2t); + + vvd(rc2t[0][0], -0.1810332128528685730, 1e-12, + "iauC2teqx", "11", status); + vvd(rc2t[0][1], 0.9834769806897685071, 1e-12, + "iauC2teqx", "12", status); + vvd(rc2t[0][2], 0.6555535639982634449e-4, 1e-12, + "iauC2teqx", "13", status); + + vvd(rc2t[1][0], -0.9834768134095211257, 1e-12, + "iauC2teqx", "21", status); + vvd(rc2t[1][1], -0.1810332203871023800, 1e-12, + "iauC2teqx", "22", status); + vvd(rc2t[1][2], 0.5749801116126438962e-3, 1e-12, + "iauC2teqx", "23", status); + + vvd(rc2t[2][0], 0.5773474014081539467e-3, 1e-12, + "iauC2teqx", "31", status); + vvd(rc2t[2][1], 0.3961832391768640871e-4, 1e-12, + "iauC2teqx", "32", status); + vvd(rc2t[2][2], 0.9999998325501691969, 1e-12, + "iauC2teqx", "33", status); + +} + +static void t_c2tpe(int *status) +/* +** - - - - - - - - +** t _ c 2 t p e +** - - - - - - - - +** +** Test iauC2tpe function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2tpe, vvd +** +** This revision: 2013 August 7 +*/ +{ + double tta, ttb, uta, utb, dpsi, deps, xp, yp, rc2t[3][3]; + + + tta = 2400000.5; + uta = 2400000.5; + ttb = 53736.0; + utb = 53736.0; + deps = 0.4090789763356509900; + dpsi = -0.9630909107115582393e-5; + xp = 2.55060238e-7; + yp = 1.860359247e-6; + + iauC2tpe(tta, ttb, uta, utb, dpsi, deps, xp, yp, rc2t); + + vvd(rc2t[0][0], -0.1813677995763029394, 1e-12, + "iauC2tpe", "11", status); + vvd(rc2t[0][1], 0.9023482206891683275, 1e-12, + "iauC2tpe", "12", status); + vvd(rc2t[0][2], -0.3909902938641085751, 1e-12, + "iauC2tpe", "13", status); + + vvd(rc2t[1][0], -0.9834147641476804807, 1e-12, + "iauC2tpe", "21", status); + vvd(rc2t[1][1], -0.1659883635434995121, 1e-12, + "iauC2tpe", "22", status); + vvd(rc2t[1][2], 0.7309763898042819705e-1, 1e-12, + "iauC2tpe", "23", status); + + vvd(rc2t[2][0], 0.1059685430673215247e-2, 1e-12, + "iauC2tpe", "31", status); + vvd(rc2t[2][1], 0.3977631855605078674, 1e-12, + "iauC2tpe", "32", status); + vvd(rc2t[2][2], 0.9174875068792735362, 1e-12, + "iauC2tpe", "33", status); + +} + +static void t_c2txy(int *status) +/* +** - - - - - - - - +** t _ c 2 t x y +** - - - - - - - - +** +** Test iauC2txy function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauC2txy, vvd +** +** This revision: 2013 August 7 +*/ +{ + double tta, ttb, uta, utb, x, y, xp, yp, rc2t[3][3]; + + + tta = 2400000.5; + uta = 2400000.5; + ttb = 53736.0; + utb = 53736.0; + x = 0.5791308486706011000e-3; + y = 0.4020579816732961219e-4; + xp = 2.55060238e-7; + yp = 1.860359247e-6; + + iauC2txy(tta, ttb, uta, utb, x, y, xp, yp, rc2t); + + vvd(rc2t[0][0], -0.1810332128306279253, 1e-12, + "iauC2txy", "11", status); + vvd(rc2t[0][1], 0.9834769806938520084, 1e-12, + "iauC2txy", "12", status); + vvd(rc2t[0][2], 0.6555551248057665829e-4, 1e-12, + "iauC2txy", "13", status); + + vvd(rc2t[1][0], -0.9834768134136142314, 1e-12, + "iauC2txy", "21", status); + vvd(rc2t[1][1], -0.1810332203649529312, 1e-12, + "iauC2txy", "22", status); + vvd(rc2t[1][2], 0.5749800843594139912e-3, 1e-12, + "iauC2txy", "23", status); + + vvd(rc2t[2][0], 0.5773474028619264494e-3, 1e-12, + "iauC2txy", "31", status); + vvd(rc2t[2][1], 0.3961816546911624260e-4, 1e-12, + "iauC2txy", "32", status); + vvd(rc2t[2][2], 0.9999998325501746670, 1e-12, + "iauC2txy", "33", status); + +} + +static void t_cal2jd(int *status) +/* +** - - - - - - - - - +** t _ c a l 2 j d +** - - - - - - - - - +** +** Test iauCal2jd function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauCal2jd, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + int j; + double djm0, djm; + + + j = iauCal2jd(2003, 06, 01, &djm0, &djm); + + vvd(djm0, 2400000.5, 0.0, "iauCal2jd", "djm0", status); + vvd(djm, 52791.0, 0.0, "iauCal2jd", "djm", status); + + viv(j, 0, "iauCal2jd", "j", status); + +} + +static void t_cp(int *status) +/* +** - - - - - +** t _ c p +** - - - - - +** +** Test iauCp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauCp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3], c[3]; + + + p[0] = 0.3; + p[1] = 1.2; + p[2] = -2.5; + + iauCp(p, c); + + vvd(c[0], 0.3, 0.0, "iauCp", "1", status); + vvd(c[1], 1.2, 0.0, "iauCp", "2", status); + vvd(c[2], -2.5, 0.0, "iauCp", "3", status); +} + +static void t_cpv(int *status) +/* +** - - - - - - +** t _ c p v +** - - - - - - +** +** Test iauCpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauCpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double pv[2][3], c[2][3]; + + + pv[0][0] = 0.3; + pv[0][1] = 1.2; + pv[0][2] = -2.5; + + pv[1][0] = -0.5; + pv[1][1] = 3.1; + pv[1][2] = 0.9; + + iauCpv(pv, c); + + vvd(c[0][0], 0.3, 0.0, "iauCpv", "p1", status); + vvd(c[0][1], 1.2, 0.0, "iauCpv", "p2", status); + vvd(c[0][2], -2.5, 0.0, "iauCpv", "p3", status); + + vvd(c[1][0], -0.5, 0.0, "iauCpv", "v1", status); + vvd(c[1][1], 3.1, 0.0, "iauCpv", "v2", status); + vvd(c[1][2], 0.9, 0.0, "iauCpv", "v3", status); + +} + +static void t_cr(int *status) +/* +** - - - - - +** t _ c r +** - - - - - +** +** Test iauCr function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauCr, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3], c[3][3]; + + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + iauCr(r, c); + + vvd(c[0][0], 2.0, 0.0, "iauCr", "11", status); + vvd(c[0][1], 3.0, 0.0, "iauCr", "12", status); + vvd(c[0][2], 2.0, 0.0, "iauCr", "13", status); + + vvd(c[1][0], 3.0, 0.0, "iauCr", "21", status); + vvd(c[1][1], 2.0, 0.0, "iauCr", "22", status); + vvd(c[1][2], 3.0, 0.0, "iauCr", "23", status); + + vvd(c[2][0], 3.0, 0.0, "iauCr", "31", status); + vvd(c[2][1], 4.0, 0.0, "iauCr", "32", status); + vvd(c[2][2], 5.0, 0.0, "iauCr", "33", status); +} + +static void t_d2dtf(int *status ) +/* +** - - - - - - - - +** t _ d 2 d t f +** - - - - - - - - +** +** Test iauD2dtf function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauD2dtf, viv +** +** This revision: 2013 August 7 +*/ +{ + int j, iy, im, id, ihmsf[4]; + + + j = iauD2dtf("UTC", 5, 2400000.5, 49533.99999, &iy, &im, &id, ihmsf); + + viv(iy, 1994, "iauD2dtf", "y", status); + viv(im, 6, "iauD2dtf", "mo", status); + viv(id, 30, "iauD2dtf", "d", status); + viv(ihmsf[0], 23, "iauD2dtf", "h", status); + viv(ihmsf[1], 59, "iauD2dtf", "m", status); + viv(ihmsf[2], 60, "iauD2dtf", "s", status); + viv(ihmsf[3], 13599, "iauD2dtf", "f", status); + viv(j, 0, "iauD2dtf", "j", status); + +} + +static void t_d2tf(int *status) +/* +** - - - - - - - +** t _ d 2 t f +** - - - - - - - +** +** Test iauD2tf function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauD2tf, viv, vvd +** +** This revision: 2013 August 7 +*/ +{ + int ihmsf[4]; + char s; + + + iauD2tf(4, -0.987654321, &s, ihmsf); + + viv((int)s, '-', "iauD2tf", "s", status); + + viv(ihmsf[0], 23, "iauD2tf", "0", status); + viv(ihmsf[1], 42, "iauD2tf", "1", status); + viv(ihmsf[2], 13, "iauD2tf", "2", status); + viv(ihmsf[3], 3333, "iauD2tf", "3", status); + +} + +static void t_dat(int *status) +/* +** - - - - - - +** t _ d a t +** - - - - - - +** +** Test iauDat function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauDat, vvd, viv +** +** This revision: 2016 July 11 +*/ +{ + int j; + double deltat; + + + j = iauDat(2003, 6, 1, 0.0, &deltat); + + vvd(deltat, 32.0, 0.0, "iauDat", "d1", status); + viv(j, 0, "iauDat", "j1", status); + + j = iauDat(2008, 1, 17, 0.0, &deltat); + + vvd(deltat, 33.0, 0.0, "iauDat", "d2", status); + viv(j, 0, "iauDat", "j2", status); + + j = iauDat(2017, 9, 1, 0.0, &deltat); + + vvd(deltat, 37.0, 0.0, "iauDat", "d3", status); + viv(j, 0, "iauDat", "j3", status); + +} + +static void t_dtdb(int *status) +/* +** - - - - - - - +** t _ d t d b +** - - - - - - - +** +** Test iauDtdb function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauDtdb, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dtdb; + + + dtdb = iauDtdb(2448939.5, 0.123, 0.76543, 5.0123, 5525.242, 3190.0); + + vvd(dtdb, -0.1280368005936998991e-2, 1e-15, "iauDtdb", "", status); + +} + +static void t_dtf2d(int *status) +/* +** - - - - - - - - +** t _ d t f 2 d +** - - - - - - - - +** +** Test iauDtf2d function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauDtf2d, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double u1, u2; + int j; + + + j = iauDtf2d("UTC", 1994, 6, 30, 23, 59, 60.13599, &u1, &u2); + + vvd(u1+u2, 2449534.49999, 1e-6, "iauDtf2d", "u", status); + viv(j, 0, "iauDtf2d", "j", status); + +} + +static void t_eceq06(int *status) +/* +** - - - - - +** t _ e c e q 0 6 +** - - - - - +** +** Test iauEceq06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEceq06, vvd +** +** This revision: 2016 March 12 +*/ +{ + double date1, date2, dl, db, dr, dd; + + + date1 = 2456165.5; + date2 = 0.401182685; + dl = 5.1; + db = -0.9; + + iauEceq06(date1, date2, dl, db, &dr, &dd); + + vvd(dr, 5.533459733613627767, 1e-14, "iauEceq06", "dr", status); + vvd(dd, -1.246542932554480576, 1e-14, "iauEceq06", "dd", status); + +} + +static void t_ecm06(int *status) +/* +** - - - - - - - - +** t _ e c m 0 6 +** - - - - - - - - +** +** Test iauEcm06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEcm06, vvd +** +** This revision: 2016 March 12 +*/ +{ + double date1, date2, rm[3][3]; + + + date1 = 2456165.5; + date2 = 0.401182685; + + iauEcm06(date1, date2, rm); + + vvd(rm[0][0], 0.9999952427708701137, 1e-14, + "iauEcm06", "rm11", status); + vvd(rm[0][1], -0.2829062057663042347e-2, 1e-14, + "iauEcm06", "rm12", status); + vvd(rm[0][2], -0.1229163741100017629e-2, 1e-14, + "iauEcm06", "rm13", status); + vvd(rm[1][0], 0.3084546876908653562e-2, 1e-14, + "iauEcm06", "rm21", status); + vvd(rm[1][1], 0.9174891871550392514, 1e-14, + "iauEcm06", "rm22", status); + vvd(rm[1][2], 0.3977487611849338124, 1e-14, + "iauEcm06", "rm23", status); + vvd(rm[2][0], 0.2488512951527405928e-5, 1e-14, + "iauEcm06", "rm31", status); + vvd(rm[2][1], -0.3977506604161195467, 1e-14, + "iauEcm06", "rm32", status); + vvd(rm[2][2], 0.9174935488232863071, 1e-14, + "iauEcm06", "rm33", status); + +} + +static void t_ee00(int *status) +/* +** - - - - - - - +** t _ e e 0 0 +** - - - - - - - +** +** Test iauEe00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEe00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double epsa, dpsi, ee; + + + epsa = 0.4090789763356509900; + dpsi = -0.9630909107115582393e-5; + + ee = iauEe00(2400000.5, 53736.0, epsa, dpsi); + + vvd(ee, -0.8834193235367965479e-5, 1e-18, "iauEe00", "", status); + +} + +static void t_ee00a(int *status) +/* +** - - - - - - - - +** t _ e e 0 0 a +** - - - - - - - - +** +** Test iauEe00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEe00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double ee; + + + ee = iauEe00a(2400000.5, 53736.0); + + vvd(ee, -0.8834192459222588227e-5, 1e-18, "iauEe00a", "", status); + +} + +static void t_ee00b(int *status) +/* +** - - - - - - - - +** t _ e e 0 0 b +** - - - - - - - - +** +** Test iauEe00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEe00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double ee; + + + ee = iauEe00b(2400000.5, 53736.0); + + vvd(ee, -0.8835700060003032831e-5, 1e-18, "iauEe00b", "", status); + +} + +static void t_ee06a(int *status) +/* +** - - - - - - - - +** t _ e e 0 6 a +** - - - - - - - - +** +** Test iauEe06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEe06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double ee; + + + ee = iauEe06a(2400000.5, 53736.0); + + vvd(ee, -0.8834195072043790156e-5, 1e-15, "iauEe06a", "", status); +} + +static void t_eect00(int *status) +/* +** - - - - - - - - - +** t _ e e c t 0 0 +** - - - - - - - - - +** +** Test iauEect00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEect00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double eect; + + + eect = iauEect00(2400000.5, 53736.0); + + vvd(eect, 0.2046085004885125264e-8, 1e-20, "iauEect00", "", status); + +} + +static void t_eform(int *status) +/* +** - - - - - - - - +** t _ e f o r m +** - - - - - - - - +** +** Test iauEform function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEform, viv, vvd +** +** This revision: 2016 March 12 +*/ +{ + int j; + double a, f; + + j = iauEform(0, &a, &f); + + viv(j, -1, "iauEform", "j0", status); + + j = iauEform(WGS84, &a, &f); + + viv(j, 0, "iauEform", "j1", status); + vvd(a, 6378137.0, 1e-10, "iauEform", "a1", status); + vvd(f, 0.3352810664747480720e-2, 1e-18, "iauEform", "f1", status); + + j = iauEform(GRS80, &a, &f); + + viv(j, 0, "iauEform", "j2", status); + vvd(a, 6378137.0, 1e-10, "iauEform", "a2", status); + vvd(f, 0.3352810681182318935e-2, 1e-18, "iauEform", "f2", status); + + j = iauEform(WGS72, &a, &f); + + viv(j, 0, "iauEform", "j2", status); + vvd(a, 6378135.0, 1e-10, "iauEform", "a3", status); + vvd(f, 0.3352779454167504862e-2, 1e-18, "iauEform", "f3", status); + + j = iauEform(4, &a, &f); + viv(j, -1, "iauEform", "j3", status); +} + +static void t_eo06a(int *status) +/* +** - - - - - - - - +** t _ e o 0 6 a +** - - - - - - - - +** +** Test iauEo06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEo06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double eo; + + + eo = iauEo06a(2400000.5, 53736.0); + + vvd(eo, -0.1332882371941833644e-2, 1e-15, "iauEo06a", "", status); + +} + +static void t_eors(int *status) +/* +** - - - - - - - +** t _ e o r s +** - - - - - - - +** +** Test iauEors function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEors, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rnpb[3][3], s, eo; + + + rnpb[0][0] = 0.9999989440476103608; + rnpb[0][1] = -0.1332881761240011518e-2; + rnpb[0][2] = -0.5790767434730085097e-3; + + rnpb[1][0] = 0.1332858254308954453e-2; + rnpb[1][1] = 0.9999991109044505944; + rnpb[1][2] = -0.4097782710401555759e-4; + + rnpb[2][0] = 0.5791308472168153320e-3; + rnpb[2][1] = 0.4020595661593994396e-4; + rnpb[2][2] = 0.9999998314954572365; + + s = -0.1220040848472271978e-7; + + eo = iauEors(rnpb, s); + + vvd(eo, -0.1332882715130744606e-2, 1e-14, "iauEors", "", status); + +} + +static void t_epb(int *status) +/* +** - - - - - - +** t _ e p b +** - - - - - - +** +** Test iauEpb function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEpb, vvd +** +** This revision: 2013 August 7 +*/ +{ + double epb; + + + epb = iauEpb(2415019.8135, 30103.18648); + + vvd(epb, 1982.418424159278580, 1e-12, "iauEpb", "", status); + +} + +static void t_epb2jd(int *status) +/* +** - - - - - - - - - +** t _ e p b 2 j d +** - - - - - - - - - +** +** Test iauEpb2jd function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEpb2jd, vvd +** +** This revision: 2013 August 7 +*/ +{ + double epb, djm0, djm; + + + epb = 1957.3; + + iauEpb2jd(epb, &djm0, &djm); + + vvd(djm0, 2400000.5, 1e-9, "iauEpb2jd", "djm0", status); + vvd(djm, 35948.1915101513, 1e-9, "iauEpb2jd", "mjd", status); + +} + +static void t_epj(int *status) +/* +** - - - - - - +** t _ e p j +** - - - - - - +** +** Test iauEpj function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEpj, vvd +** +** This revision: 2013 August 7 +*/ +{ + double epj; + + + epj = iauEpj(2451545, -7392.5); + + vvd(epj, 1979.760438056125941, 1e-12, "iauEpj", "", status); + +} + +static void t_epj2jd(int *status) +/* +** - - - - - - - - - +** t _ e p j 2 j d +** - - - - - - - - - +** +** Test iauEpj2jd function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEpj2jd, vvd +** +** This revision: 2013 August 7 +*/ +{ + double epj, djm0, djm; + + + epj = 1996.8; + + iauEpj2jd(epj, &djm0, &djm); + + vvd(djm0, 2400000.5, 1e-9, "iauEpj2jd", "djm0", status); + vvd(djm, 50375.7, 1e-9, "iauEpj2jd", "mjd", status); + +} + +static void t_epv00(int *status) +/* +** - - - - - - - - +** t _ e p v 0 0 +** - - - - - - - - +** +** Test iauEpv00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEpv00, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double pvh[2][3], pvb[2][3]; + int j; + + + j = iauEpv00(2400000.5, 53411.52501161, pvh, pvb); + + vvd(pvh[0][0], -0.7757238809297706813, 1e-14, + "iauEpv00", "ph(x)", status); + vvd(pvh[0][1], 0.5598052241363340596, 1e-14, + "iauEpv00", "ph(y)", status); + vvd(pvh[0][2], 0.2426998466481686993, 1e-14, + "iauEpv00", "ph(z)", status); + + vvd(pvh[1][0], -0.1091891824147313846e-1, 1e-15, + "iauEpv00", "vh(x)", status); + vvd(pvh[1][1], -0.1247187268440845008e-1, 1e-15, + "iauEpv00", "vh(y)", status); + vvd(pvh[1][2], -0.5407569418065039061e-2, 1e-15, + "iauEpv00", "vh(z)", status); + + vvd(pvb[0][0], -0.7714104440491111971, 1e-14, + "iauEpv00", "pb(x)", status); + vvd(pvb[0][1], 0.5598412061824171323, 1e-14, + "iauEpv00", "pb(y)", status); + vvd(pvb[0][2], 0.2425996277722452400, 1e-14, + "iauEpv00", "pb(z)", status); + + vvd(pvb[1][0], -0.1091874268116823295e-1, 1e-15, + "iauEpv00", "vb(x)", status); + vvd(pvb[1][1], -0.1246525461732861538e-1, 1e-15, + "iauEpv00", "vb(y)", status); + vvd(pvb[1][2], -0.5404773180966231279e-2, 1e-15, + "iauEpv00", "vb(z)", status); + + viv(j, 0, "iauEpv00", "j", status); + +} + +static void t_eqec06(int *status) +/* +** - - - - - - - - - +** t _ e q e c 0 6 +** - - - - - - - - - +** +** Test iauEqec06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEqec06, vvd +** +** This revision: 2016 March 12 +*/ +{ + double date1, date2, dr, dd, dl, db; + + + date1 = 1234.5; + date2 = 2440000.5; + dr = 1.234; + dd = 0.987; + + iauEqec06(date1, date2, dr, dd, &dl, &db); + + vvd(dl, 1.342509918994654619, 1e-14, "iauEqec06", "dl", status); + vvd(db, 0.5926215259704608132, 1e-14, "iauEqec06", "db", status); + +} + +static void t_eqeq94(int *status) +/* +** - - - - - - - - - +** t _ e q e q 9 4 +** - - - - - - - - - +** +** Test iauEqeq94 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEqeq94, vvd +** +** This revision: 2013 August 7 +*/ +{ + double eqeq; + + + eqeq = iauEqeq94(2400000.5, 41234.0); + + vvd(eqeq, 0.5357758254609256894e-4, 1e-17, "iauEqeq94", "", status); + +} + +static void t_era00(int *status) +/* +** - - - - - - - - +** t _ e r a 0 0 +** - - - - - - - - +** +** Test iauEra00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauEra00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double era00; + + + era00 = iauEra00(2400000.5, 54388.0); + + vvd(era00, 0.4022837240028158102, 1e-12, "iauEra00", "", status); + +} + +static void t_fad03(int *status) +/* +** - - - - - - - - +** t _ f a d 0 3 +** - - - - - - - - +** +** Test iauFad03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFad03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFad03(0.80), 1.946709205396925672, 1e-12, + "iauFad03", "", status); +} + +static void t_fae03(int *status) +/* +** - - - - - - - - +** t _ f a e 0 3 +** - - - - - - - - +** +** Test iauFae03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFae03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFae03(0.80), 1.744713738913081846, 1e-12, + "iauFae03", "", status); +} + +static void t_faf03(int *status) +/* +** - - - - - - - - +** t _ f a f 0 3 +** - - - - - - - - +** +** Test iauFaf03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFaf03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFaf03(0.80), 0.2597711366745499518, 1e-12, + "iauFaf03", "", status); +} + +static void t_faju03(int *status) +/* +** - - - - - - - - - +** t _ f a j u 0 3 +** - - - - - - - - - +** +** Test iauFaju03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFaju03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFaju03(0.80), 5.275711665202481138, 1e-12, + "iauFaju03", "", status); +} + +static void t_fal03(int *status) +/* +** - - - - - - - - +** t _ f a l 0 3 +** - - - - - - - - +** +** Test iauFal03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFal03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFal03(0.80), 5.132369751108684150, 1e-12, + "iauFal03", "", status); +} + +static void t_falp03(int *status) +/* +** - - - - - - - - - +** t _ f a l p 0 3 +** - - - - - - - - - +** +** Test iauFalp03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFalp03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFalp03(0.80), 6.226797973505507345, 1e-12, + "iauFalp03", "", status); +} + +static void t_fama03(int *status) +/* +** - - - - - - - - - +** t _ f a m a 0 3 +** - - - - - - - - - +** +** Test iauFama03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFama03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFama03(0.80), 3.275506840277781492, 1e-12, + "iauFama03", "", status); +} + +static void t_fame03(int *status) +/* +** - - - - - - - - - +** t _ f a m e 0 3 +** - - - - - - - - - +** +** Test iauFame03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFame03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFame03(0.80), 5.417338184297289661, 1e-12, + "iauFame03", "", status); +} + +static void t_fane03(int *status) +/* +** - - - - - - - - - +** t _ f a n e 0 3 +** - - - - - - - - - +** +** Test iauFane03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFane03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFane03(0.80), 2.079343830860413523, 1e-12, + "iauFane03", "", status); +} + +static void t_faom03(int *status) +/* +** - - - - - - - - - +** t _ f a o m 0 3 +** - - - - - - - - - +** +** Test iauFaom03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFaom03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFaom03(0.80), -5.973618440951302183, 1e-12, + "iauFaom03", "", status); +} + +static void t_fapa03(int *status) +/* +** - - - - - - - - - +** t _ f a p a 0 3 +** - - - - - - - - - +** +** Test iauFapa03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFapa03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFapa03(0.80), 0.1950884762240000000e-1, 1e-12, + "iauFapa03", "", status); +} + +static void t_fasa03(int *status) +/* +** - - - - - - - - - +** t _ f a s a 0 3 +** - - - - - - - - - +** +** Test iauFasa03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFasa03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFasa03(0.80), 5.371574539440827046, 1e-12, + "iauFasa03", "", status); +} + +static void t_faur03(int *status) +/* +** - - - - - - - - - +** t _ f a u r 0 3 +** - - - - - - - - - +** +** Test iauFaur03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFaur03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFaur03(0.80), 5.180636450180413523, 1e-12, + "iauFaur03", "", status); +} + +static void t_fave03(int *status) +/* +** - - - - - - - - - +** t _ f a v e 0 3 +** - - - - - - - - - +** +** Test iauFave03 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFave03, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauFave03(0.80), 3.424900460533758000, 1e-12, + "iauFave03", "", status); +} + +static void t_fk425(int *status) +/* +** - - - - - - - - +** t _ f k 4 2 5 +** - - - - - - - - +** +** Test iauFk425 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFk425, vvd +** +** This revision: 2018 December 6 +*/ +{ + double r1950, d1950, dr1950, dd1950, p1950, v1950, + r2000, d2000, dr2000, dd2000, p2000, v2000; + + + r1950 = 0.07626899753879587532; + d1950 = -1.137405378399605780; + dr1950 = 0.1973749217849087460e-4; + dd1950 = 0.5659714913272723189e-5; + p1950 = 0.134; + v1950 = 8.7; + + iauFk425(r1950, d1950, dr1950, dd1950, p1950, v1950, + &r2000, &d2000, &dr2000, &dd2000, &p2000, &v2000); + + vvd(r2000, 0.08757989933556446040, 1e-14, + "iauFk425", "r2000", status); + vvd(d2000, -1.132279113042091895, 1e-12, + "iauFk425", "d2000", status); + vvd(dr2000, 0.1953670614474396139e-4, 1e-17, + "iauFk425", "dr2000", status); + vvd(dd2000, 0.5637686678659640164e-5, 1e-18, + "iauFk425", "dd2000", status); + vvd(p2000, 0.1339919950582767871, 1e-13, "iauFk425", "p2000", status); + vvd(v2000, 8.736999669183529069, 1e-12, "iauFk425", "v2000", status); + +} + +static void t_fk45z(int *status) +/* +** - - - - - - - - +** t _ f k 4 5 z +** - - - - - - - - +** +** Test iauFk45z function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFk45z, vvd +** +** This revision: 2018 December 6 +*/ +{ + double r1950, d1950, bepoch, r2000, d2000; + + + r1950 = 0.01602284975382960982; + d1950 = -0.1164347929099906024; + bepoch = 1954.677617625256806; + + iauFk45z(r1950, d1950, bepoch, &r2000, &d2000); + + vvd(r2000, 0.02719295911606862303, 1e-15, + "iauFk45z", "r2000", status); + vvd(d2000, -0.1115766001565926892, 1e-13, + "iauFk45z", "d2000", status); + +} + +static void t_fk524(int *status) +/* +** - - - - - - - - +** t _ f k 5 2 4 +** - - - - - - - - +** +** Test iauFk524 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFk524, vvd +** +** This revision: 2018 December 6 +*/ +{ + double r2000, d2000, dr2000, dd2000, p2000, v2000, + r1950, d1950, dr1950, dd1950, p1950, v1950; + + + r2000 = 0.8723503576487275595; + d2000 = -0.7517076365138887672; + dr2000 = 0.2019447755430472323e-4; + dd2000 = 0.3541563940505160433e-5; + p2000 = 0.1559; + v2000 = 86.87; + + iauFk524(r2000, d2000, dr2000, dd2000, p2000, v2000, + &r1950, &d1950, &dr1950,&dd1950, &p1950, &v1950); + + vvd(r1950, 0.8636359659799603487, 1e-13, + "iauFk524", "r1950", status); + vvd(d1950, -0.7550281733160843059, 1e-13, + "iauFk524", "d1950", status); + vvd(dr1950, 0.2023628192747172486e-4, 1e-17, + "iauFk524", "dr1950", status); + vvd(dd1950, 0.3624459754935334718e-5, 1e-18, + "iauFk524", "dd1950", status); + vvd(p1950, 0.1560079963299390241, 1e-13, + "iauFk524", "p1950", status); + vvd(v1950, 86.79606353469163751, 1e-11, "iauFk524", "v1950", status); + +} + +static void t_fk52h(int *status) +/* +** - - - - - - - - +** t _ f k 5 2 h +** - - - - - - - - +** +** Test iauFk52h function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFk52h, vvd +** +** This revision: 2021 January 5 +*/ +{ + double r5, d5, dr5, dd5, px5, rv5, rh, dh, drh, ddh, pxh, rvh; + + + r5 = 1.76779433; + d5 = -0.2917517103; + dr5 = -1.91851572e-7; + dd5 = -5.8468475e-6; + px5 = 0.379210; + rv5 = -7.6; + + iauFk52h(r5, d5, dr5, dd5, px5, rv5, + &rh, &dh, &drh, &ddh, &pxh, &rvh); + + vvd(rh, 1.767794226299947632, 1e-14, + "iauFk52h", "ra", status); + vvd(dh, -0.2917516070530391757, 1e-14, + "iauFk52h", "dec", status); + vvd(drh, -0.1961874125605721270e-6,1e-19, + "iauFk52h", "dr5", status); + vvd(ddh, -0.58459905176693911e-5, 1e-19, + "iauFk52h", "dd5", status); + vvd(pxh, 0.37921, 1e-14, + "iauFk52h", "px", status); + vvd(rvh, -7.6000000940000254, 1e-11, + "iauFk52h", "rv", status); + +} + +static void t_fk54z(int *status) +/* +** - - - - - - - - +** t _ f k 5 4 z +** - - - - - - - - +** +** Test iauFk54z function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFk54z, vvd +** +** This revision: 2018 December 6 +*/ +{ + double r2000, d2000, bepoch, r1950, d1950, dr1950, dd1950; + + + r2000 = 0.02719026625066316119; + d2000 = -0.1115815170738754813; + bepoch = 1954.677308160316374; + + iauFk54z(r2000, d2000, bepoch, &r1950, &d1950, &dr1950, &dd1950); + + vvd(r1950, 0.01602015588390065476, 1e-14, + "iauFk54z", "r1950", status); + vvd(d1950, -0.1164397101110765346, 1e-13, + "iauFk54z", "d1950", status); + vvd(dr1950, -0.1175712648471090704e-7, 1e-20, + "iauFk54z", "dr1950", status); + vvd(dd1950, 0.2108109051316431056e-7, 1e-20, + "iauFk54z", "dd1950", status); + +} + +static void t_fk5hip(int *status) +/* +** - - - - - - - - - +** t _ f k 5 h i p +** - - - - - - - - - +** +** Test iauFk5hip function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFk5hip, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r5h[3][3], s5h[3]; + + + iauFk5hip(r5h, s5h); + + vvd(r5h[0][0], 0.9999999999999928638, 1e-14, + "iauFk5hip", "11", status); + vvd(r5h[0][1], 0.1110223351022919694e-6, 1e-17, + "iauFk5hip", "12", status); + vvd(r5h[0][2], 0.4411803962536558154e-7, 1e-17, + "iauFk5hip", "13", status); + vvd(r5h[1][0], -0.1110223308458746430e-6, 1e-17, + "iauFk5hip", "21", status); + vvd(r5h[1][1], 0.9999999999999891830, 1e-14, + "iauFk5hip", "22", status); + vvd(r5h[1][2], -0.9647792498984142358e-7, 1e-17, + "iauFk5hip", "23", status); + vvd(r5h[2][0], -0.4411805033656962252e-7, 1e-17, + "iauFk5hip", "31", status); + vvd(r5h[2][1], 0.9647792009175314354e-7, 1e-17, + "iauFk5hip", "32", status); + vvd(r5h[2][2], 0.9999999999999943728, 1e-14, + "iauFk5hip", "33", status); + vvd(s5h[0], -0.1454441043328607981e-8, 1e-17, + "iauFk5hip", "s1", status); + vvd(s5h[1], 0.2908882086657215962e-8, 1e-17, + "iauFk5hip", "s2", status); + vvd(s5h[2], 0.3393695767766751955e-8, 1e-17, + "iauFk5hip", "s3", status); + +} + +static void t_fk5hz(int *status) +/* +** - - - - - - - - +** t _ f k 5 h z +** - - - - - - - - +** +** Test iauFk5hz function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFk5hz, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r5, d5, rh, dh; + + + r5 = 1.76779433; + d5 = -0.2917517103; + + iauFk5hz(r5, d5, 2400000.5, 54479.0, &rh, &dh); + + vvd(rh, 1.767794191464423978, 1e-12, "iauFk5hz", "ra", status); + vvd(dh, -0.2917516001679884419, 1e-12, "iauFk5hz", "dec", status); + +} + +static void t_fw2m(int *status) +/* +** - - - - - - - +** t _ f w 2 m +** - - - - - - - +** +** Test iauFw2m function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFw2m, vvd +** +** This revision: 2013 August 7 +*/ +{ + double gamb, phib, psi, eps, r[3][3]; + + + gamb = -0.2243387670997992368e-5; + phib = 0.4091014602391312982; + psi = -0.9501954178013015092e-3; + eps = 0.4091014316587367472; + + iauFw2m(gamb, phib, psi, eps, r); + + vvd(r[0][0], 0.9999995505176007047, 1e-12, + "iauFw2m", "11", status); + vvd(r[0][1], 0.8695404617348192957e-3, 1e-12, + "iauFw2m", "12", status); + vvd(r[0][2], 0.3779735201865582571e-3, 1e-12, + "iauFw2m", "13", status); + + vvd(r[1][0], -0.8695404723772016038e-3, 1e-12, + "iauFw2m", "21", status); + vvd(r[1][1], 0.9999996219496027161, 1e-12, + "iauFw2m", "22", status); + vvd(r[1][2], -0.1361752496887100026e-6, 1e-12, + "iauFw2m", "23", status); + + vvd(r[2][0], -0.3779734957034082790e-3, 1e-12, + "iauFw2m", "31", status); + vvd(r[2][1], -0.1924880848087615651e-6, 1e-12, + "iauFw2m", "32", status); + vvd(r[2][2], 0.9999999285679971958, 1e-12, + "iauFw2m", "33", status); + +} + +static void t_fw2xy(int *status) +/* +** - - - - - - - - +** t _ f w 2 x y +** - - - - - - - - +** +** Test iauFw2xy function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauFw2xy, vvd +** +** This revision: 2013 August 7 +*/ +{ + double gamb, phib, psi, eps, x, y; + + + gamb = -0.2243387670997992368e-5; + phib = 0.4091014602391312982; + psi = -0.9501954178013015092e-3; + eps = 0.4091014316587367472; + + iauFw2xy(gamb, phib, psi, eps, &x, &y); + + vvd(x, -0.3779734957034082790e-3, 1e-14, "iauFw2xy", "x", status); + vvd(y, -0.1924880848087615651e-6, 1e-14, "iauFw2xy", "y", status); + +} + +static void t_g2icrs(int *status) +/* +** - - - - - - - - - +** t _ g 2 i c r s +** - - - - - - - - - +** +** Test iauG2icrs function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauG2icrs, vvd +** +** This revision: 2015 January 30 +*/ +{ + double dl, db, dr, dd; + + + dl = 5.5850536063818546461558105; + db = -0.7853981633974483096156608; + iauG2icrs (dl, db, &dr, &dd); + vvd(dr, 5.9338074302227188048671, 1e-14, "iauG2icrs", "R", status); + vvd(dd, -1.1784870613579944551541, 1e-14, "iauG2icrs", "D", status); + } + +static void t_gc2gd(int *status) +/* +** - - - - - - - - +** t _ g c 2 g d +** - - - - - - - - +** +** Test iauGc2gd function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGc2gd, viv, vvd +** +** This revision: 2016 March 12 +*/ +{ + int j; + double xyz[] = {2e6, 3e6, 5.244e6}; + double e, p, h; + + j = iauGc2gd(0, xyz, &e, &p, &h); + + viv(j, -1, "iauGc2gd", "j0", status); + + j = iauGc2gd(WGS84, xyz, &e, &p, &h); + + viv(j, 0, "iauGc2gd", "j1", status); + vvd(e, 0.9827937232473290680, 1e-14, "iauGc2gd", "e1", status); + vvd(p, 0.97160184819075459, 1e-14, "iauGc2gd", "p1", status); + vvd(h, 331.4172461426059892, 1e-8, "iauGc2gd", "h1", status); + + j = iauGc2gd(GRS80, xyz, &e, &p, &h); + + viv(j, 0, "iauGc2gd", "j2", status); + vvd(e, 0.9827937232473290680, 1e-14, "iauGc2gd", "e2", status); + vvd(p, 0.97160184820607853, 1e-14, "iauGc2gd", "p2", status); + vvd(h, 331.41731754844348, 1e-8, "iauGc2gd", "h2", status); + + j = iauGc2gd(WGS72, xyz, &e, &p, &h); + + viv(j, 0, "iauGc2gd", "j3", status); + vvd(e, 0.9827937232473290680, 1e-14, "iauGc2gd", "e3", status); + vvd(p, 0.9716018181101511937, 1e-14, "iauGc2gd", "p3", status); + vvd(h, 333.2770726130318123, 1e-8, "iauGc2gd", "h3", status); + + j = iauGc2gd(4, xyz, &e, &p, &h); + + viv(j, -1, "iauGc2gd", "j4", status); +} + +static void t_gc2gde(int *status) +/* +** - - - - - - - - - +** t _ g c 2 g d e +** - - - - - - - - - +** +** Test iauGc2gde function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGc2gde, viv, vvd +** +** This revision: 2016 March 12 +*/ +{ + int j; + double a = 6378136.0, f = 0.0033528; + double xyz[] = {2e6, 3e6, 5.244e6}; + double e, p, h; + + j = iauGc2gde(a, f, xyz, &e, &p, &h); + + viv(j, 0, "iauGc2gde", "j", status); + vvd(e, 0.9827937232473290680, 1e-14, "iauGc2gde", "e", status); + vvd(p, 0.9716018377570411532, 1e-14, "iauGc2gde", "p", status); + vvd(h, 332.36862495764397, 1e-8, "iauGc2gde", "h", status); +} + +static void t_gd2gc(int *status) +/* +** - - - - - - - - +** t _ g d 2 g c +** - - - - - - - - +** +** Test iauGd2gc function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGd2gc, viv, vvd +** +** This revision: 2016 March 12 +*/ +{ + int j; + double e = 3.1, p = -0.5, h = 2500.0; + double xyz[3]; + + j = iauGd2gc(0, e, p, h, xyz); + + viv(j, -1, "iauGd2gc", "j0", status); + + j = iauGd2gc(WGS84, e, p, h, xyz); + + viv(j, 0, "iauGd2gc", "j1", status); + vvd(xyz[0], -5599000.5577049947, 1e-7, "iauGd2gc", "1/1", status); + vvd(xyz[1], 233011.67223479203, 1e-7, "iauGd2gc", "2/1", status); + vvd(xyz[2], -3040909.4706983363, 1e-7, "iauGd2gc", "3/1", status); + + j = iauGd2gc(GRS80, e, p, h, xyz); + + viv(j, 0, "iauGd2gc", "j2", status); + vvd(xyz[0], -5599000.5577260984, 1e-7, "iauGd2gc", "1/2", status); + vvd(xyz[1], 233011.6722356702949, 1e-7, "iauGd2gc", "2/2", status); + vvd(xyz[2], -3040909.4706095476, 1e-7, "iauGd2gc", "3/2", status); + + j = iauGd2gc(WGS72, e, p, h, xyz); + + viv(j, 0, "iauGd2gc", "j3", status); + vvd(xyz[0], -5598998.7626301490, 1e-7, "iauGd2gc", "1/3", status); + vvd(xyz[1], 233011.5975297822211, 1e-7, "iauGd2gc", "2/3", status); + vvd(xyz[2], -3040908.6861467111, 1e-7, "iauGd2gc", "3/3", status); + + j = iauGd2gc(4, e, p, h, xyz); + + viv(j, -1, "iauGd2gc", "j4", status); +} + +static void t_gd2gce(int *status) +/* +** - - - - - - - - - +** t _ g d 2 g c e +** - - - - - - - - - +** +** Test iauGd2gce function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGd2gce, viv, vvd +** +** This revision: 2016 March 12 +*/ +{ + int j; + double a = 6378136.0, f = 0.0033528; + double e = 3.1, p = -0.5, h = 2500.0; + double xyz[3]; + + j = iauGd2gce(a, f, e, p, h, xyz); + + viv(j, 0, "iauGd2gce", "j", status); + vvd(xyz[0], -5598999.6665116328, 1e-7, "iauGd2gce", "1", status); + vvd(xyz[1], 233011.6351463057189, 1e-7, "iauGd2gce", "2", status); + vvd(xyz[2], -3040909.0517314132, 1e-7, "iauGd2gce", "3", status); +} + +static void t_gmst00(int *status) +/* +** - - - - - - - - - +** t _ g m s t 0 0 +** - - - - - - - - - +** +** Test iauGmst00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGmst00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta; + + + theta = iauGmst00(2400000.5, 53736.0, 2400000.5, 53736.0); + + vvd(theta, 1.754174972210740592, 1e-12, "iauGmst00", "", status); + +} + +static void t_gmst06(int *status) +/* +** - - - - - - - - - +** t _ g m s t 0 6 +** - - - - - - - - - +** +** Test iauGmst06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGmst06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta; + + + theta = iauGmst06(2400000.5, 53736.0, 2400000.5, 53736.0); + + vvd(theta, 1.754174971870091203, 1e-12, "iauGmst06", "", status); + +} + +static void t_gmst82(int *status) +/* +** - - - - - - - - - +** t _ g m s t 8 2 +** - - - - - - - - - +** +** Test iauGmst82 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGmst82, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta; + + + theta = iauGmst82(2400000.5, 53736.0); + + vvd(theta, 1.754174981860675096, 1e-12, "iauGmst82", "", status); + +} + +static void t_gst00a(int *status) +/* +** - - - - - - - - - +** t _ g s t 0 0 a +** - - - - - - - - - +** +** Test iauGst00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGst00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta; + + + theta = iauGst00a(2400000.5, 53736.0, 2400000.5, 53736.0); + + vvd(theta, 1.754166138018281369, 1e-12, "iauGst00a", "", status); + +} + +static void t_gst00b(int *status) +/* +** - - - - - - - - - +** t _ g s t 0 0 b +** - - - - - - - - - +** +** Test iauGst00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGst00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta; + + + theta = iauGst00b(2400000.5, 53736.0); + + vvd(theta, 1.754166136510680589, 1e-12, "iauGst00b", "", status); + +} + +static void t_gst06(int *status) +/* +** - - - - - - - - +** t _ g s t 0 6 +** - - - - - - - - +** +** Test iauGst06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGst06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rnpb[3][3], theta; + + + rnpb[0][0] = 0.9999989440476103608; + rnpb[0][1] = -0.1332881761240011518e-2; + rnpb[0][2] = -0.5790767434730085097e-3; + + rnpb[1][0] = 0.1332858254308954453e-2; + rnpb[1][1] = 0.9999991109044505944; + rnpb[1][2] = -0.4097782710401555759e-4; + + rnpb[2][0] = 0.5791308472168153320e-3; + rnpb[2][1] = 0.4020595661593994396e-4; + rnpb[2][2] = 0.9999998314954572365; + + theta = iauGst06(2400000.5, 53736.0, 2400000.5, 53736.0, rnpb); + + vvd(theta, 1.754166138018167568, 1e-12, "iauGst06", "", status); + +} + +static void t_gst06a(int *status) +/* +** - - - - - - - - - +** t _ g s t 0 6 a +** - - - - - - - - - +** +** Test iauGst06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGst06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta; + + + theta = iauGst06a(2400000.5, 53736.0, 2400000.5, 53736.0); + + vvd(theta, 1.754166137675019159, 1e-12, "iauGst06a", "", status); + +} + +static void t_gst94(int *status) +/* +** - - - - - - - - +** t _ g s t 9 4 +** - - - - - - - - +** +** Test iauGst94 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauGst94, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta; + + + theta = iauGst94(2400000.5, 53736.0); + + vvd(theta, 1.754166136020645203, 1e-12, "iauGst94", "", status); + +} + +static void t_icrs2g(int *status) +/* +** - - - - - - - - - +** t _ i c r s 2 g +** - - - - - - - - - +** +** Test iauIcrs2g function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauIcrs2g, vvd +** +** This revision: 2015 January 30 +*/ +{ + double dr, dd, dl, db; + + dr = 5.9338074302227188048671087; + dd = -1.1784870613579944551540570; + iauIcrs2g (dr, dd, &dl, &db); + vvd(dl, 5.5850536063818546461558, 1e-14, "iauIcrs2g", "L", status); + vvd(db, -0.7853981633974483096157, 1e-14, "iauIcrs2g", "B", status); + } + +static void t_h2fk5(int *status) +/* +** - - - - - - - - +** t _ h 2 f k 5 +** - - - - - - - - +** +** Test iauH2fk5 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauH2fk5, vvd +** +** This revision: 2017 January 3 +*/ +{ + double rh, dh, drh, ddh, pxh, rvh, r5, d5, dr5, dd5, px5, rv5; + + + rh = 1.767794352; + dh = -0.2917512594; + drh = -2.76413026e-6; + ddh = -5.92994449e-6; + pxh = 0.379210; + rvh = -7.6; + + iauH2fk5(rh, dh, drh, ddh, pxh, rvh, + &r5, &d5, &dr5, &dd5, &px5, &rv5); + + vvd(r5, 1.767794455700065506, 1e-13, + "iauH2fk5", "ra", status); + vvd(d5, -0.2917513626469638890, 1e-13, + "iauH2fk5", "dec", status); + vvd(dr5, -0.27597945024511204e-5, 1e-18, + "iauH2fk5", "dr5", status); + vvd(dd5, -0.59308014093262838e-5, 1e-18, + "iauH2fk5", "dd5", status); + vvd(px5, 0.37921, 1e-13, + "iauH2fk5", "px", status); + vvd(rv5, -7.6000001309071126, 1e-11, + "iauH2fk5", "rv", status); + +} + +static void t_hd2ae(int *status) +/* +** - - - - - - - - +** t _ h d 2 a e +** - - - - - - - - +** +** Test iauHd2ae function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauHd2ae and vvd +** +** This revision: 2017 October 21 +*/ +{ + double h, d, p, a, e; + + + h = 1.1; + d = 1.2; + p = 0.3; + + iauHd2ae(h, d, p, &a, &e); + + vvd(a, 5.916889243730066194, 1e-13, "iauHd2ae", "a", status); + vvd(e, 0.4472186304990486228, 1e-14, "iauHd2ae", "e", status); + +} + +static void t_hd2pa(int *status) +/* +** - - - - - - - - +** t _ h d 2 p a +** - - - - - - - - +** +** Test iauHd2pa function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauHd2pa and vvd +** +** This revision: 2017 October 21 +*/ +{ + double h, d, p, q; + + + h = 1.1; + d = 1.2; + p = 0.3; + + q = iauHd2pa(h, d, p); + + vvd(q, 1.906227428001995580, 1e-13, "iauHd2pa", "q", status); + +} + +static void t_hfk5z(int *status) +/* +** - - - - - - - - +** t _ h f k 5 z +** - - - - - - - - +** +** Test iauHfk5z function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauHfk5z, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rh, dh, r5, d5, dr5, dd5; + + + + rh = 1.767794352; + dh = -0.2917512594; + + iauHfk5z(rh, dh, 2400000.5, 54479.0, &r5, &d5, &dr5, &dd5); + + vvd(r5, 1.767794490535581026, 1e-13, + "iauHfk5z", "ra", status); + vvd(d5, -0.2917513695320114258, 1e-14, + "iauHfk5z", "dec", status); + vvd(dr5, 0.4335890983539243029e-8, 1e-22, + "iauHfk5z", "dr5", status); + vvd(dd5, -0.8569648841237745902e-9, 1e-23, + "iauHfk5z", "dd5", status); + +} + +static void t_ir(int *status) +/* +** - - - - - +** t _ i r +** - - - - - +** +** Test iauIr function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauIr, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3]; + + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + iauIr(r); + + vvd(r[0][0], 1.0, 0.0, "iauIr", "11", status); + vvd(r[0][1], 0.0, 0.0, "iauIr", "12", status); + vvd(r[0][2], 0.0, 0.0, "iauIr", "13", status); + + vvd(r[1][0], 0.0, 0.0, "iauIr", "21", status); + vvd(r[1][1], 1.0, 0.0, "iauIr", "22", status); + vvd(r[1][2], 0.0, 0.0, "iauIr", "23", status); + + vvd(r[2][0], 0.0, 0.0, "iauIr", "31", status); + vvd(r[2][1], 0.0, 0.0, "iauIr", "32", status); + vvd(r[2][2], 1.0, 0.0, "iauIr", "33", status); + +} + +static void t_jd2cal(int *status) +/* +** - - - - - - - - - +** t _ j d 2 c a l +** - - - - - - - - - +** +** Test iauJd2cal function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauJd2cal, viv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dj1, dj2, fd; + int iy, im, id, j; + + + dj1 = 2400000.5; + dj2 = 50123.9999; + + j = iauJd2cal(dj1, dj2, &iy, &im, &id, &fd); + + viv(iy, 1996, "iauJd2cal", "y", status); + viv(im, 2, "iauJd2cal", "m", status); + viv(id, 10, "iauJd2cal", "d", status); + vvd(fd, 0.9999, 1e-7, "iauJd2cal", "fd", status); + viv(j, 0, "iauJd2cal", "j", status); + +} + +static void t_jdcalf(int *status) +/* +** - - - - - - - - - +** t _ j d c a l f +** - - - - - - - - - +** +** Test iauJdcalf function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauJdcalf, viv +** +** This revision: 2013 August 7 +*/ +{ + double dj1, dj2; + int iydmf[4], j; + + + dj1 = 2400000.5; + dj2 = 50123.9999; + + j = iauJdcalf(4, dj1, dj2, iydmf); + + viv(iydmf[0], 1996, "iauJdcalf", "y", status); + viv(iydmf[1], 2, "iauJdcalf", "m", status); + viv(iydmf[2], 10, "iauJdcalf", "d", status); + viv(iydmf[3], 9999, "iauJdcalf", "f", status); + + viv(j, 0, "iauJdcalf", "j", status); + +} + +static void t_ld(int *status) +/* +** - - - - - +** t _ l d +** - - - - - +** +** Test iauLd function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLd, vvd +* +** This revision: 2013 October 2 +*/ +{ + double bm, p[3], q[3], e[3], em, dlim, p1[3]; + + + bm = 0.00028574; + p[0] = -0.763276255; + p[1] = -0.608633767; + p[2] = -0.216735543; + q[0] = -0.763276255; + q[1] = -0.608633767; + q[2] = -0.216735543; + e[0] = 0.76700421; + e[1] = 0.605629598; + e[2] = 0.211937094; + em = 8.91276983; + dlim = 3e-10; + + iauLd(bm, p, q, e, em, dlim, p1); + + vvd(p1[0], -0.7632762548968159627, 1e-12, + "iauLd", "1", status); + vvd(p1[1], -0.6086337670823762701, 1e-12, + "iauLd", "2", status); + vvd(p1[2], -0.2167355431320546947, 1e-12, + "iauLd", "3", status); + +} + +static void t_ldn(int *status) +/* +** - - - - - - +** t _ l d n +** - - - - - - +** +** Test iauLdn function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLdn, vvd +** +** This revision: 2013 October 2 +*/ +{ + int n; + iauLDBODY b[3]; + double ob[3], sc[3], sn[3]; + + + n = 3; + b[0].bm = 0.00028574; + b[0].dl = 3e-10; + b[0].pv[0][0] = -7.81014427; + b[0].pv[0][1] = -5.60956681; + b[0].pv[0][2] = -1.98079819; + b[0].pv[1][0] = 0.0030723249; + b[0].pv[1][1] = -0.00406995477; + b[0].pv[1][2] = -0.00181335842; + b[1].bm = 0.00095435; + b[1].dl = 3e-9; + b[1].pv[0][0] = 0.738098796; + b[1].pv[0][1] = 4.63658692; + b[1].pv[0][2] = 1.9693136; + b[1].pv[1][0] = -0.00755816922; + b[1].pv[1][1] = 0.00126913722; + b[1].pv[1][2] = 0.000727999001; + b[2].bm = 1.0; + b[2].dl = 6e-6; + b[2].pv[0][0] = -0.000712174377; + b[2].pv[0][1] = -0.00230478303; + b[2].pv[0][2] = -0.00105865966; + b[2].pv[1][0] = 6.29235213e-6; + b[2].pv[1][1] = -3.30888387e-7; + b[2].pv[1][2] = -2.96486623e-7; + ob[0] = -0.974170437; + ob[1] = -0.2115201; + ob[2] = -0.0917583114; + sc[0] = -0.763276255; + sc[1] = -0.608633767; + sc[2] = -0.216735543; + + iauLdn(n, b, ob, sc, sn); + + vvd(sn[0], -0.7632762579693333866, 1e-12, + "iauLdn", "1", status); + vvd(sn[1], -0.6086337636093002660, 1e-12, + "iauLdn", "2", status); + vvd(sn[2], -0.2167355420646328159, 1e-12, + "iauLdn", "3", status); + +} + +static void t_ldsun(int *status) +/* +** - - - - - - - - +** t _ l d s u n +** - - - - - - - - +** +** Test iauLdsun function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLdsun, vvd +** +** This revision: 2013 October 2 +*/ +{ + double p[3], e[3], em, p1[3]; + + + p[0] = -0.763276255; + p[1] = -0.608633767; + p[2] = -0.216735543; + e[0] = -0.973644023; + e[1] = -0.20925523; + e[2] = -0.0907169552; + em = 0.999809214; + + iauLdsun(p, e, em, p1); + + vvd(p1[0], -0.7632762580731413169, 1e-12, + "iauLdsun", "1", status); + vvd(p1[1], -0.6086337635262647900, 1e-12, + "iauLdsun", "2", status); + vvd(p1[2], -0.2167355419322321302, 1e-12, + "iauLdsun", "3", status); + +} + +static void t_lteceq(int *status) +/* +** - - - - - - - - - +** t _ l t e c e q +** - - - - - - - - - +** +** Test iauLteceq function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLteceq, vvd +** +** This revision: 2016 March 12 +*/ +{ + double epj, dl, db, dr, dd; + + + epj = 2500.0; + dl = 1.5; + db = 0.6; + + iauLteceq(epj, dl, db, &dr, &dd); + + vvd(dr, 1.275156021861921167, 1e-14, "iauLteceq", "dr", status); + vvd(dd, 0.9966573543519204791, 1e-14, "iauLteceq", "dd", status); + +} + +static void t_ltecm(int *status) +/* +** - - - - - - - - +** t _ l t e c m +** - - - - - - - - +** +** Test iauLtecm function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLtecm, vvd +** +** This revision: 2016 March 12 +*/ +{ + double epj, rm[3][3]; + + + epj = -3000.0; + + iauLtecm(epj, rm); + + vvd(rm[0][0], 0.3564105644859788825, 1e-14, + "iauLtecm", "rm11", status); + vvd(rm[0][1], 0.8530575738617682284, 1e-14, + "iauLtecm", "rm12", status); + vvd(rm[0][2], 0.3811355207795060435, 1e-14, + "iauLtecm", "rm13", status); + vvd(rm[1][0], -0.9343283469640709942, 1e-14, + "iauLtecm", "rm21", status); + vvd(rm[1][1], 0.3247830597681745976, 1e-14, + "iauLtecm", "rm22", status); + vvd(rm[1][2], 0.1467872751535940865, 1e-14, + "iauLtecm", "rm23", status); + vvd(rm[2][0], 0.1431636191201167793e-2, 1e-14, + "iauLtecm", "rm31", status); + vvd(rm[2][1], -0.4084222566960599342, 1e-14, + "iauLtecm", "rm32", status); + vvd(rm[2][2], 0.9127919865189030899, 1e-14, + "iauLtecm", "rm33", status); + +} + +static void t_lteqec(int *status) +/* +** - - - - - - - - - +** t _ l t e q e c +** - - - - - - - - - +** +** Test iauLteqec function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLteqec, vvd +** +** This revision: 2016 March 12 +*/ +{ + double epj, dr, dd, dl, db; + + + epj = -1500.0; + dr = 1.234; + dd = 0.987; + + iauLteqec(epj, dr, dd, &dl, &db); + + vvd(dl, 0.5039483649047114859, 1e-14, "iauLteqec", "dl", status); + vvd(db, 0.5848534459726224882, 1e-14, "iauLteqec", "db", status); + +} + +static void t_ltp(int *status) +/* +** - - - - - - +** t _ l t p +** - - - - - - +** +** Test iauLtp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLtp, vvd +** +** This revision: 2016 March 12 +*/ +{ + double epj, rp[3][3]; + + + epj = 1666.666; + + iauLtp(epj, rp); + + vvd(rp[0][0], 0.9967044141159213819, 1e-14, + "iauLtp", "rp11", status); + vvd(rp[0][1], 0.7437801893193210840e-1, 1e-14, + "iauLtp", "rp12", status); + vvd(rp[0][2], 0.3237624409345603401e-1, 1e-14, + "iauLtp", "rp13", status); + vvd(rp[1][0], -0.7437802731819618167e-1, 1e-14, + "iauLtp", "rp21", status); + vvd(rp[1][1], 0.9972293894454533070, 1e-14, + "iauLtp", "rp22", status); + vvd(rp[1][2], -0.1205768842723593346e-2, 1e-14, + "iauLtp", "rp23", status); + vvd(rp[2][0], -0.3237622482766575399e-1, 1e-14, + "iauLtp", "rp31", status); + vvd(rp[2][1], -0.1206286039697609008e-2, 1e-14, + "iauLtp", "rp32", status); + vvd(rp[2][2], 0.9994750246704010914, 1e-14, + "iauLtp", "rp33", status); + +} + +static void t_ltpb(int *status) +/* +** - - - - - - - +** t _ l t p b +** - - - - - - - +** +** Test iauLtpb function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLtpb, vvd +** +** This revision: 2016 March 12 +*/ +{ + double epj, rpb[3][3]; + + + epj = 1666.666; + + iauLtpb(epj, rpb); + + vvd(rpb[0][0], 0.9967044167723271851, 1e-14, + "iauLtpb", "rpb11", status); + vvd(rpb[0][1], 0.7437794731203340345e-1, 1e-14, + "iauLtpb", "rpb12", status); + vvd(rpb[0][2], 0.3237632684841625547e-1, 1e-14, + "iauLtpb", "rpb13", status); + vvd(rpb[1][0], -0.7437795663437177152e-1, 1e-14, + "iauLtpb", "rpb21", status); + vvd(rpb[1][1], 0.9972293947500013666, 1e-14, + "iauLtpb", "rpb22", status); + vvd(rpb[1][2], -0.1205741865911243235e-2, 1e-14, + "iauLtpb", "rpb23", status); + vvd(rpb[2][0], -0.3237630543224664992e-1, 1e-14, + "iauLtpb", "rpb31", status); + vvd(rpb[2][1], -0.1206316791076485295e-2, 1e-14, + "iauLtpb", "rpb32", status); + vvd(rpb[2][2], 0.9994750220222438819, 1e-14, + "iauLtpb", "rpb33", status); + +} + +static void t_ltpecl(int *status) +/* +** - - - - - - - - - +** t _ l t p e c l +** - - - - - - - - - +** +** Test iauLtpecl function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLtpecl, vvd +** +** This revision: 2016 March 12 +*/ +{ + double epj, vec[3]; + + + epj = -1500.0; + + iauLtpecl(epj, vec); + + vvd(vec[0], 0.4768625676477096525e-3, 1e-14, + "iauLtpecl", "vec1", status); + vvd(vec[1], -0.4052259533091875112, 1e-14, + "iauLtpecl", "vec2", status); + vvd(vec[2], 0.9142164401096448012, 1e-14, + "iauLtpecl", "vec3", status); + +} + +static void t_ltpequ(int *status) +/* +** - - - - - - - - - +** t _ l t p e q u +** - - - - - - - - - +** +** Test iauLtpequ function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauLtpequ, vvd +** +** This revision: 2016 March 12 +*/ +{ + double epj, veq[3]; + + + epj = -2500.0; + + iauLtpequ(epj, veq); + + vvd(veq[0], -0.3586652560237326659, 1e-14, + "iauLtpequ", "veq1", status); + vvd(veq[1], -0.1996978910771128475, 1e-14, + "iauLtpequ", "veq2", status); + vvd(veq[2], 0.9118552442250819624, 1e-14, + "iauLtpequ", "veq3", status); + +} + +static void t_moon98(int *status) +/* +** - - - - - - - - - +** t _ m o o n 9 8 +** - - - - - - - - - +** +** Test iauMoon98 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauMoon98, vvd, viv +** +** This revision: 2021 April 12 +*/ +{ + double pv[2][3]; + + + iauMoon98(2400000.5, 43999.9, pv); + + vvd(pv[0][0], -0.2601295959971044180e-2, 1e-11, + "iauMoon98", "x 4", status); + vvd(pv[0][1], 0.6139750944302742189e-3, 1e-11, + "iauMoon98", "y 4", status); + vvd(pv[0][2], 0.2640794528229828909e-3, 1e-11, + "iauMoon98", "z 4", status); + + vvd(pv[1][0], -0.1244321506649895021e-3, 1e-11, + "iauMoon98", "xd 4", status); + vvd(pv[1][1], -0.5219076942678119398e-3, 1e-11, + "iauMoon98", "yd 4", status); + vvd(pv[1][2], -0.1716132214378462047e-3, 1e-11, + "iauMoon98", "zd 4", status); + +} + +static void t_num00a(int *status) +/* +** - - - - - - - - - +** t _ n u m 0 0 a +** - - - - - - - - - +** +** Test iauNum00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNum00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rmatn[3][3]; + + + iauNum00a(2400000.5, 53736.0, rmatn); + + vvd(rmatn[0][0], 0.9999999999536227949, 1e-12, + "iauNum00a", "11", status); + vvd(rmatn[0][1], 0.8836238544090873336e-5, 1e-12, + "iauNum00a", "12", status); + vvd(rmatn[0][2], 0.3830835237722400669e-5, 1e-12, + "iauNum00a", "13", status); + + vvd(rmatn[1][0], -0.8836082880798569274e-5, 1e-12, + "iauNum00a", "21", status); + vvd(rmatn[1][1], 0.9999999991354655028, 1e-12, + "iauNum00a", "22", status); + vvd(rmatn[1][2], -0.4063240865362499850e-4, 1e-12, + "iauNum00a", "23", status); + + vvd(rmatn[2][0], -0.3831194272065995866e-5, 1e-12, + "iauNum00a", "31", status); + vvd(rmatn[2][1], 0.4063237480216291775e-4, 1e-12, + "iauNum00a", "32", status); + vvd(rmatn[2][2], 0.9999999991671660338, 1e-12, + "iauNum00a", "33", status); + +} + +static void t_num00b(int *status) +/* +** - - - - - - - - - +** t _ n u m 0 0 b +** - - - - - - - - - +** +** Test iauNum00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNum00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rmatn[3][3]; + + iauNum00b(2400000.5, 53736, rmatn); + + vvd(rmatn[0][0], 0.9999999999536069682, 1e-12, + "iauNum00b", "11", status); + vvd(rmatn[0][1], 0.8837746144871248011e-5, 1e-12, + "iauNum00b", "12", status); + vvd(rmatn[0][2], 0.3831488838252202945e-5, 1e-12, + "iauNum00b", "13", status); + + vvd(rmatn[1][0], -0.8837590456632304720e-5, 1e-12, + "iauNum00b", "21", status); + vvd(rmatn[1][1], 0.9999999991354692733, 1e-12, + "iauNum00b", "22", status); + vvd(rmatn[1][2], -0.4063198798559591654e-4, 1e-12, + "iauNum00b", "23", status); + + vvd(rmatn[2][0], -0.3831847930134941271e-5, 1e-12, + "iauNum00b", "31", status); + vvd(rmatn[2][1], 0.4063195412258168380e-4, 1e-12, + "iauNum00b", "32", status); + vvd(rmatn[2][2], 0.9999999991671806225, 1e-12, + "iauNum00b", "33", status); + +} + +static void t_num06a(int *status) +/* +** - - - - - - - - - +** t _ n u m 0 6 a +** - - - - - - - - - +** +** Test iauNum06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNum06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rmatn[3][3]; + + iauNum06a(2400000.5, 53736, rmatn); + + vvd(rmatn[0][0], 0.9999999999536227668, 1e-12, + "iauNum06a", "11", status); + vvd(rmatn[0][1], 0.8836241998111535233e-5, 1e-12, + "iauNum06a", "12", status); + vvd(rmatn[0][2], 0.3830834608415287707e-5, 1e-12, + "iauNum06a", "13", status); + + vvd(rmatn[1][0], -0.8836086334870740138e-5, 1e-12, + "iauNum06a", "21", status); + vvd(rmatn[1][1], 0.9999999991354657474, 1e-12, + "iauNum06a", "22", status); + vvd(rmatn[1][2], -0.4063240188248455065e-4, 1e-12, + "iauNum06a", "23", status); + + vvd(rmatn[2][0], -0.3831193642839398128e-5, 1e-12, + "iauNum06a", "31", status); + vvd(rmatn[2][1], 0.4063236803101479770e-4, 1e-12, + "iauNum06a", "32", status); + vvd(rmatn[2][2], 0.9999999991671663114, 1e-12, + "iauNum06a", "33", status); + +} + +static void t_numat(int *status) +/* +** - - - - - - - - +** t _ n u m a t +** - - - - - - - - +** +** Test iauNumat function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNumat, vvd +** +** This revision: 2013 August 7 +*/ +{ + double epsa, dpsi, deps, rmatn[3][3]; + + + epsa = 0.4090789763356509900; + dpsi = -0.9630909107115582393e-5; + deps = 0.4063239174001678826e-4; + + iauNumat(epsa, dpsi, deps, rmatn); + + vvd(rmatn[0][0], 0.9999999999536227949, 1e-12, + "iauNumat", "11", status); + vvd(rmatn[0][1], 0.8836239320236250577e-5, 1e-12, + "iauNumat", "12", status); + vvd(rmatn[0][2], 0.3830833447458251908e-5, 1e-12, + "iauNumat", "13", status); + + vvd(rmatn[1][0], -0.8836083657016688588e-5, 1e-12, + "iauNumat", "21", status); + vvd(rmatn[1][1], 0.9999999991354654959, 1e-12, + "iauNumat", "22", status); + vvd(rmatn[1][2], -0.4063240865361857698e-4, 1e-12, + "iauNumat", "23", status); + + vvd(rmatn[2][0], -0.3831192481833385226e-5, 1e-12, + "iauNumat", "31", status); + vvd(rmatn[2][1], 0.4063237480216934159e-4, 1e-12, + "iauNumat", "32", status); + vvd(rmatn[2][2], 0.9999999991671660407, 1e-12, + "iauNumat", "33", status); + +} + +static void t_nut00a(int *status) +/* +** - - - - - - - - - +** t _ n u t 0 0 a +** - - - - - - - - - +** +** Test iauNut00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNut00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps; + + + iauNut00a(2400000.5, 53736.0, &dpsi, &deps); + + vvd(dpsi, -0.9630909107115518431e-5, 1e-13, + "iauNut00a", "dpsi", status); + vvd(deps, 0.4063239174001678710e-4, 1e-13, + "iauNut00a", "deps", status); + +} + +static void t_nut00b(int *status) +/* +** - - - - - - - - - +** t _ n u t 0 0 b +** - - - - - - - - - +** +** Test iauNut00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNut00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps; + + + iauNut00b(2400000.5, 53736.0, &dpsi, &deps); + + vvd(dpsi, -0.9632552291148362783e-5, 1e-13, + "iauNut00b", "dpsi", status); + vvd(deps, 0.4063197106621159367e-4, 1e-13, + "iauNut00b", "deps", status); + +} + +static void t_nut06a(int *status) +/* +** - - - - - - - - - +** t _ n u t 0 6 a +** - - - - - - - - - +** +** Test iauNut06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNut06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps; + + + iauNut06a(2400000.5, 53736.0, &dpsi, &deps); + + vvd(dpsi, -0.9630912025820308797e-5, 1e-13, + "iauNut06a", "dpsi", status); + vvd(deps, 0.4063238496887249798e-4, 1e-13, + "iauNut06a", "deps", status); + +} + +static void t_nut80(int *status) +/* +** - - - - - - - - +** t _ n u t 8 0 +** - - - - - - - - +** +** Test iauNut80 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNut80, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps; + + + iauNut80(2400000.5, 53736.0, &dpsi, &deps); + + vvd(dpsi, -0.9643658353226563966e-5, 1e-13, + "iauNut80", "dpsi", status); + vvd(deps, 0.4060051006879713322e-4, 1e-13, + "iauNut80", "deps", status); + +} + +static void t_nutm80(int *status) +/* +** - - - - - - - - - +** t _ n u t m 8 0 +** - - - - - - - - - +** +** Test iauNutm80 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauNutm80, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rmatn[3][3]; + + + iauNutm80(2400000.5, 53736.0, rmatn); + + vvd(rmatn[0][0], 0.9999999999534999268, 1e-12, + "iauNutm80", "11", status); + vvd(rmatn[0][1], 0.8847935789636432161e-5, 1e-12, + "iauNutm80", "12", status); + vvd(rmatn[0][2], 0.3835906502164019142e-5, 1e-12, + "iauNutm80", "13", status); + + vvd(rmatn[1][0], -0.8847780042583435924e-5, 1e-12, + "iauNutm80", "21", status); + vvd(rmatn[1][1], 0.9999999991366569963, 1e-12, + "iauNutm80", "22", status); + vvd(rmatn[1][2], -0.4060052702727130809e-4, 1e-12, + "iauNutm80", "23", status); + + vvd(rmatn[2][0], -0.3836265729708478796e-5, 1e-12, + "iauNutm80", "31", status); + vvd(rmatn[2][1], 0.4060049308612638555e-4, 1e-12, + "iauNutm80", "32", status); + vvd(rmatn[2][2], 0.9999999991684415129, 1e-12, + "iauNutm80", "33", status); + +} + +static void t_obl06(int *status) +/* +** - - - - - - - - +** t _ o b l 0 6 +** - - - - - - - - +** +** Test iauObl06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauObl06, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauObl06(2400000.5, 54388.0), 0.4090749229387258204, 1e-14, + "iauObl06", "", status); +} + +static void t_obl80(int *status) +/* +** - - - - - - - - +** t _ o b l 8 0 +** - - - - - - - - +** +** Test iauObl80 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauObl80, vvd +** +** This revision: 2013 August 7 +*/ +{ + double eps0; + + + eps0 = iauObl80(2400000.5, 54388.0); + + vvd(eps0, 0.4090751347643816218, 1e-14, "iauObl80", "", status); + +} + +static void t_p06e(int *status) +/* +** - - - - - - - +** t _ p 0 6 e +** - - - - - - - +** +** Test iauP06e function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauP06e, vvd +** +** This revision: 2020 May 30 +*/ +{ + double eps0, psia, oma, bpa, bqa, pia, bpia, + epsa, chia, za, zetaa, thetaa, pa, gam, phi, psi; + + + iauP06e(2400000.5, 52541.0, &eps0, &psia, &oma, &bpa, + &bqa, &pia, &bpia, &epsa, &chia, &za, + &zetaa, &thetaa, &pa, &gam, &phi, &psi); + + vvd(eps0, 0.4090926006005828715, 1e-14, + "iauP06e", "eps0", status); + vvd(psia, 0.6664369630191613431e-3, 1e-14, + "iauP06e", "psia", status); + vvd(oma , 0.4090925973783255982, 1e-14, + "iauP06e", "oma", status); + vvd(bpa, 0.5561149371265209445e-6, 1e-14, + "iauP06e", "bpa", status); + vvd(bqa, -0.6191517193290621270e-5, 1e-14, + "iauP06e", "bqa", status); + vvd(pia, 0.6216441751884382923e-5, 1e-14, + "iauP06e", "pia", status); + vvd(bpia, 3.052014180023779882, 1e-14, + "iauP06e", "bpia", status); + vvd(epsa, 0.4090864054922431688, 1e-14, + "iauP06e", "epsa", status); + vvd(chia, 0.1387703379530915364e-5, 1e-14, + "iauP06e", "chia", status); + vvd(za, 0.2921789846651790546e-3, 1e-14, + "iauP06e", "za", status); + vvd(zetaa, 0.3178773290332009310e-3, 1e-14, + "iauP06e", "zetaa", status); + vvd(thetaa, 0.2650932701657497181e-3, 1e-14, + "iauP06e", "thetaa", status); + vvd(pa, 0.6651637681381016288e-3, 1e-14, + "iauP06e", "pa", status); + vvd(gam, 0.1398077115963754987e-5, 1e-14, + "iauP06e", "gam", status); + vvd(phi, 0.4090864090837462602, 1e-14, + "iauP06e", "phi", status); + vvd(psi, 0.6664464807480920325e-3, 1e-14, + "iauP06e", "psi", status); + +} + +static void t_p2pv(int *status) +/* +** - - - - - - - +** t _ p 2 p v +** - - - - - - - +** +** Test iauP2pv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauP2pv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3], pv[2][3]; + + + p[0] = 0.25; + p[1] = 1.2; + p[2] = 3.0; + + pv[0][0] = 0.3; + pv[0][1] = 1.2; + pv[0][2] = -2.5; + + pv[1][0] = -0.5; + pv[1][1] = 3.1; + pv[1][2] = 0.9; + + iauP2pv(p, pv); + + vvd(pv[0][0], 0.25, 0.0, "iauP2pv", "p1", status); + vvd(pv[0][1], 1.2, 0.0, "iauP2pv", "p2", status); + vvd(pv[0][2], 3.0, 0.0, "iauP2pv", "p3", status); + + vvd(pv[1][0], 0.0, 0.0, "iauP2pv", "v1", status); + vvd(pv[1][1], 0.0, 0.0, "iauP2pv", "v2", status); + vvd(pv[1][2], 0.0, 0.0, "iauP2pv", "v3", status); + +} + +static void t_p2s(int *status) +/* +** - - - - - - +** t _ p 2 s +** - - - - - - +** +** Test iauP2s function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauP2s, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3], theta, phi, r; + + + p[0] = 100.0; + p[1] = -50.0; + p[2] = 25.0; + + iauP2s(p, &theta, &phi, &r); + + vvd(theta, -0.4636476090008061162, 1e-12, "iauP2s", "theta", status); + vvd(phi, 0.2199879773954594463, 1e-12, "iauP2s", "phi", status); + vvd(r, 114.5643923738960002, 1e-9, "iauP2s", "r", status); + +} + +static void t_pap(int *status) +/* +** - - - - - - +** t _ p a p +** - - - - - - +** +** Test iauPap function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPap, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3], b[3], theta; + + + a[0] = 1.0; + a[1] = 0.1; + a[2] = 0.2; + + b[0] = -3.0; + b[1] = 1e-3; + b[2] = 0.2; + + theta = iauPap(a, b); + + vvd(theta, 0.3671514267841113674, 1e-12, "iauPap", "", status); + +} + +static void t_pas(int *status) +/* +** - - - - - - +** t _ p a s +** - - - - - - +** +** Test iauPas function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPas, vvd +** +** This revision: 2013 August 7 +*/ +{ + double al, ap, bl, bp, theta; + + + al = 1.0; + ap = 0.1; + bl = 0.2; + bp = -1.0; + + theta = iauPas(al, ap, bl, bp); + + vvd(theta, -2.724544922932270424, 1e-12, "iauPas", "", status); + +} + +static void t_pb06(int *status) +/* +** - - - - - - - +** t _ p b 0 6 +** - - - - - - - +** +** Test iauPb06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPb06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double bzeta, bz, btheta; + + + iauPb06(2400000.5, 50123.9999, &bzeta, &bz, &btheta); + + vvd(bzeta, -0.5092634016326478238e-3, 1e-12, + "iauPb06", "bzeta", status); + vvd(bz, -0.3602772060566044413e-3, 1e-12, + "iauPb06", "bz", status); + vvd(btheta, -0.3779735537167811177e-3, 1e-12, + "iauPb06", "btheta", status); + +} + +static void t_pdp(int *status) +/* +** - - - - - - +** t _ p d p +** - - - - - - +** +** Test iauPdp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPdp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3], b[3], adb; + + + a[0] = 2.0; + a[1] = 2.0; + a[2] = 3.0; + + b[0] = 1.0; + b[1] = 3.0; + b[2] = 4.0; + + adb = iauPdp(a, b); + + vvd(adb, 20, 1e-12, "iauPdp", "", status); + +} + +static void t_pfw06(int *status) +/* +** - - - - - - - - +** t _ p f w 0 6 +** - - - - - - - - +** +** Test iauPfw06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPfw06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double gamb, phib, psib, epsa; + + + iauPfw06(2400000.5, 50123.9999, &gamb, &phib, &psib, &epsa); + + vvd(gamb, -0.2243387670997995690e-5, 1e-16, + "iauPfw06", "gamb", status); + vvd(phib, 0.4091014602391312808, 1e-12, + "iauPfw06", "phib", status); + vvd(psib, -0.9501954178013031895e-3, 1e-14, + "iauPfw06", "psib", status); + vvd(epsa, 0.4091014316587367491, 1e-12, + "iauPfw06", "epsa", status); + +} + +static void t_plan94(int *status) +/* +** - - - - - - - - - +** t _ p l a n 9 4 +** - - - - - - - - - +** +** Test iauPlan94 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPlan94, vvd, viv +** +** This revision: 2013 October 2 +*/ +{ + double pv[2][3]; + int j; + + + j = iauPlan94(2400000.5, 1e6, 0, pv); + + vvd(pv[0][0], 0.0, 0.0, "iauPlan94", "x 1", status); + vvd(pv[0][1], 0.0, 0.0, "iauPlan94", "y 1", status); + vvd(pv[0][2], 0.0, 0.0, "iauPlan94", "z 1", status); + + vvd(pv[1][0], 0.0, 0.0, "iauPlan94", "xd 1", status); + vvd(pv[1][1], 0.0, 0.0, "iauPlan94", "yd 1", status); + vvd(pv[1][2], 0.0, 0.0, "iauPlan94", "zd 1", status); + + viv(j, -1, "iauPlan94", "j 1", status); + + j = iauPlan94(2400000.5, 1e6, 10, pv); + + viv(j, -1, "iauPlan94", "j 2", status); + + j = iauPlan94(2400000.5, -320000, 3, pv); + + vvd(pv[0][0], 0.9308038666832975759, 1e-11, + "iauPlan94", "x 3", status); + vvd(pv[0][1], 0.3258319040261346000, 1e-11, + "iauPlan94", "y 3", status); + vvd(pv[0][2], 0.1422794544481140560, 1e-11, + "iauPlan94", "z 3", status); + + vvd(pv[1][0], -0.6429458958255170006e-2, 1e-11, + "iauPlan94", "xd 3", status); + vvd(pv[1][1], 0.1468570657704237764e-1, 1e-11, + "iauPlan94", "yd 3", status); + vvd(pv[1][2], 0.6406996426270981189e-2, 1e-11, + "iauPlan94", "zd 3", status); + + viv(j, 1, "iauPlan94", "j 3", status); + + j = iauPlan94(2400000.5, 43999.9, 1, pv); + + vvd(pv[0][0], 0.2945293959257430832, 1e-11, + "iauPlan94", "x 4", status); + vvd(pv[0][1], -0.2452204176601049596, 1e-11, + "iauPlan94", "y 4", status); + vvd(pv[0][2], -0.1615427700571978153, 1e-11, + "iauPlan94", "z 4", status); + + vvd(pv[1][0], 0.1413867871404614441e-1, 1e-11, + "iauPlan94", "xd 4", status); + vvd(pv[1][1], 0.1946548301104706582e-1, 1e-11, + "iauPlan94", "yd 4", status); + vvd(pv[1][2], 0.8929809783898904786e-2, 1e-11, + "iauPlan94", "zd 4", status); + + viv(j, 0, "iauPlan94", "j 4", status); + +} + +static void t_pmat00(int *status) +/* +** - - - - - - - - - +** t _ p m a t 0 0 +** - - - - - - - - - +** +** Test iauPmat00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPmat00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbp[3][3]; + + + iauPmat00(2400000.5, 50123.9999, rbp); + + vvd(rbp[0][0], 0.9999995505175087260, 1e-12, + "iauPmat00", "11", status); + vvd(rbp[0][1], 0.8695405883617884705e-3, 1e-14, + "iauPmat00", "12", status); + vvd(rbp[0][2], 0.3779734722239007105e-3, 1e-14, + "iauPmat00", "13", status); + + vvd(rbp[1][0], -0.8695405990410863719e-3, 1e-14, + "iauPmat00", "21", status); + vvd(rbp[1][1], 0.9999996219494925900, 1e-12, + "iauPmat00", "22", status); + vvd(rbp[1][2], -0.1360775820404982209e-6, 1e-14, + "iauPmat00", "23", status); + + vvd(rbp[2][0], -0.3779734476558184991e-3, 1e-14, + "iauPmat00", "31", status); + vvd(rbp[2][1], -0.1925857585832024058e-6, 1e-14, + "iauPmat00", "32", status); + vvd(rbp[2][2], 0.9999999285680153377, 1e-12, + "iauPmat00", "33", status); + +} + +static void t_pmat06(int *status) +/* +** - - - - - - - - - +** t _ p m a t 0 6 +** - - - - - - - - - +** +** Test iauPmat06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPmat06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbp[3][3]; + + + iauPmat06(2400000.5, 50123.9999, rbp); + + vvd(rbp[0][0], 0.9999995505176007047, 1e-12, + "iauPmat06", "11", status); + vvd(rbp[0][1], 0.8695404617348208406e-3, 1e-14, + "iauPmat06", "12", status); + vvd(rbp[0][2], 0.3779735201865589104e-3, 1e-14, + "iauPmat06", "13", status); + + vvd(rbp[1][0], -0.8695404723772031414e-3, 1e-14, + "iauPmat06", "21", status); + vvd(rbp[1][1], 0.9999996219496027161, 1e-12, + "iauPmat06", "22", status); + vvd(rbp[1][2], -0.1361752497080270143e-6, 1e-14, + "iauPmat06", "23", status); + + vvd(rbp[2][0], -0.3779734957034089490e-3, 1e-14, + "iauPmat06", "31", status); + vvd(rbp[2][1], -0.1924880847894457113e-6, 1e-14, + "iauPmat06", "32", status); + vvd(rbp[2][2], 0.9999999285679971958, 1e-12, + "iauPmat06", "33", status); + +} + +static void t_pmat76(int *status) +/* +** - - - - - - - - - +** t _ p m a t 7 6 +** - - - - - - - - - +** +** Test iauPmat76 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPmat76, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rmatp[3][3]; + + + iauPmat76(2400000.5, 50123.9999, rmatp); + + vvd(rmatp[0][0], 0.9999995504328350733, 1e-12, + "iauPmat76", "11", status); + vvd(rmatp[0][1], 0.8696632209480960785e-3, 1e-14, + "iauPmat76", "12", status); + vvd(rmatp[0][2], 0.3779153474959888345e-3, 1e-14, + "iauPmat76", "13", status); + + vvd(rmatp[1][0], -0.8696632209485112192e-3, 1e-14, + "iauPmat76", "21", status); + vvd(rmatp[1][1], 0.9999996218428560614, 1e-12, + "iauPmat76", "22", status); + vvd(rmatp[1][2], -0.1643284776111886407e-6, 1e-14, + "iauPmat76", "23", status); + + vvd(rmatp[2][0], -0.3779153474950335077e-3, 1e-14, + "iauPmat76", "31", status); + vvd(rmatp[2][1], -0.1643306746147366896e-6, 1e-14, + "iauPmat76", "32", status); + vvd(rmatp[2][2], 0.9999999285899790119, 1e-12, + "iauPmat76", "33", status); + +} + +static void t_pm(int *status) +/* +** - - - - - +** t _ p m +** - - - - - +** +** Test iauPm function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPm, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3], r; + + + p[0] = 0.3; + p[1] = 1.2; + p[2] = -2.5; + + r = iauPm(p); + + vvd(r, 2.789265136196270604, 1e-12, "iauPm", "", status); + +} + +static void t_pmp(int *status) +/* +** - - - - - - +** t _ p m p +** - - - - - - +** +** Test iauPmp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPmp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3], b[3], amb[3]; + + + a[0] = 2.0; + a[1] = 2.0; + a[2] = 3.0; + + b[0] = 1.0; + b[1] = 3.0; + b[2] = 4.0; + + iauPmp(a, b, amb); + + vvd(amb[0], 1.0, 1e-12, "iauPmp", "0", status); + vvd(amb[1], -1.0, 1e-12, "iauPmp", "1", status); + vvd(amb[2], -1.0, 1e-12, "iauPmp", "2", status); + +} + +static void t_pmpx(int *status) +/* +** - - - - - - - +** t _ p m p x +** - - - - - - - +** +** Test iauPmpx function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPmpx, vvd +** +** This revision: 2017 March 15 +*/ +{ + double rc, dc, pr, pd, px, rv, pmt, pob[3], pco[3]; + + + rc = 1.234; + dc = 0.789; + pr = 1e-5; + pd = -2e-5; + px = 1e-2; + rv = 10.0; + pmt = 8.75; + pob[0] = 0.9; + pob[1] = 0.4; + pob[2] = 0.1; + + iauPmpx(rc, dc, pr, pd, px, rv, pmt, pob, pco); + + vvd(pco[0], 0.2328137623960308438, 1e-12, + "iauPmpx", "1", status); + vvd(pco[1], 0.6651097085397855328, 1e-12, + "iauPmpx", "2", status); + vvd(pco[2], 0.7095257765896359837, 1e-12, + "iauPmpx", "3", status); + +} + +static void t_pmsafe(int *status) +/* +** - - - - - - - - - +** t _ p m s a f e +** - - - - - - - - - +** +** Test iauPmsafe function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPmsafe, vvd, viv +** +** This revision: 2017 March 15 +*/ +{ + int j; + double ra1, dec1, pmr1, pmd1, px1, rv1, ep1a, ep1b, ep2a, ep2b, + ra2, dec2, pmr2, pmd2, px2, rv2; + + + ra1 = 1.234; + dec1 = 0.789; + pmr1 = 1e-5; + pmd1 = -2e-5; + px1 = 1e-2; + rv1 = 10.0; + ep1a = 2400000.5; + ep1b = 48348.5625; + ep2a = 2400000.5; + ep2b = 51544.5; + + j = iauPmsafe(ra1, dec1, pmr1, pmd1, px1, rv1, + ep1a, ep1b, ep2a, ep2b, + &ra2, &dec2, &pmr2, &pmd2, &px2, &rv2); + + vvd(ra2, 1.234087484501017061, 1e-12, + "iauPmsafe", "ra2", status); + vvd(dec2, 0.7888249982450468567, 1e-12, + "iauPmsafe", "dec2", status); + vvd(pmr2, 0.9996457663586073988e-5, 1e-12, + "iauPmsafe", "pmr2", status); + vvd(pmd2, -0.2000040085106754565e-4, 1e-16, + "iauPmsafe", "pmd2", status); + vvd(px2, 0.9999997295356830666e-2, 1e-12, + "iauPmsafe", "px2", status); + vvd(rv2, 10.38468380293920069, 1e-10, + "iauPmsafe", "rv2", status); + viv ( j, 0, "iauPmsafe", "j", status); + +} + +static void t_pn(int *status) +/* +** - - - - - +** t _ p n +** - - - - - +** +** Test iauPn function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPn, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3], r, u[3]; + + + p[0] = 0.3; + p[1] = 1.2; + p[2] = -2.5; + + iauPn(p, &r, u); + + vvd(r, 2.789265136196270604, 1e-12, "iauPn", "r", status); + + vvd(u[0], 0.1075552109073112058, 1e-12, "iauPn", "u1", status); + vvd(u[1], 0.4302208436292448232, 1e-12, "iauPn", "u2", status); + vvd(u[2], -0.8962934242275933816, 1e-12, "iauPn", "u3", status); + +} + +static void t_pn00(int *status) +/* +** - - - - - - - +** t _ p n 0 0 +** - - - - - - - +** +** Test iauPn00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPn00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps, epsa, + rb[3][3], rp[3][3], rbp[3][3], rn[3][3], rbpn[3][3]; + + + dpsi = -0.9632552291149335877e-5; + deps = 0.4063197106621141414e-4; + + iauPn00(2400000.5, 53736.0, dpsi, deps, + &epsa, rb, rp, rbp, rn, rbpn); + + vvd(epsa, 0.4090791789404229916, 1e-12, "iauPn00", "epsa", status); + + vvd(rb[0][0], 0.9999999999999942498, 1e-12, + "iauPn00", "rb11", status); + vvd(rb[0][1], -0.7078279744199196626e-7, 1e-18, + "iauPn00", "rb12", status); + vvd(rb[0][2], 0.8056217146976134152e-7, 1e-18, + "iauPn00", "rb13", status); + + vvd(rb[1][0], 0.7078279477857337206e-7, 1e-18, + "iauPn00", "rb21", status); + vvd(rb[1][1], 0.9999999999999969484, 1e-12, + "iauPn00", "rb22", status); + vvd(rb[1][2], 0.3306041454222136517e-7, 1e-18, + "iauPn00", "rb23", status); + + vvd(rb[2][0], -0.8056217380986972157e-7, 1e-18, + "iauPn00", "rb31", status); + vvd(rb[2][1], -0.3306040883980552500e-7, 1e-18, + "iauPn00", "rb32", status); + vvd(rb[2][2], 0.9999999999999962084, 1e-12, + "iauPn00", "rb33", status); + + vvd(rp[0][0], 0.9999989300532289018, 1e-12, + "iauPn00", "rp11", status); + vvd(rp[0][1], -0.1341647226791824349e-2, 1e-14, + "iauPn00", "rp12", status); + vvd(rp[0][2], -0.5829880927190296547e-3, 1e-14, + "iauPn00", "rp13", status); + + vvd(rp[1][0], 0.1341647231069759008e-2, 1e-14, + "iauPn00", "rp21", status); + vvd(rp[1][1], 0.9999990999908750433, 1e-12, + "iauPn00", "rp22", status); + vvd(rp[1][2], -0.3837444441583715468e-6, 1e-14, + "iauPn00", "rp23", status); + + vvd(rp[2][0], 0.5829880828740957684e-3, 1e-14, + "iauPn00", "rp31", status); + vvd(rp[2][1], -0.3984203267708834759e-6, 1e-14, + "iauPn00", "rp32", status); + vvd(rp[2][2], 0.9999998300623538046, 1e-12, + "iauPn00", "rp33", status); + + vvd(rbp[0][0], 0.9999989300052243993, 1e-12, + "iauPn00", "rbp11", status); + vvd(rbp[0][1], -0.1341717990239703727e-2, 1e-14, + "iauPn00", "rbp12", status); + vvd(rbp[0][2], -0.5829075749891684053e-3, 1e-14, + "iauPn00", "rbp13", status); + + vvd(rbp[1][0], 0.1341718013831739992e-2, 1e-14, + "iauPn00", "rbp21", status); + vvd(rbp[1][1], 0.9999990998959191343, 1e-12, + "iauPn00", "rbp22", status); + vvd(rbp[1][2], -0.3505759733565421170e-6, 1e-14, + "iauPn00", "rbp23", status); + + vvd(rbp[2][0], 0.5829075206857717883e-3, 1e-14, + "iauPn00", "rbp31", status); + vvd(rbp[2][1], -0.4315219955198608970e-6, 1e-14, + "iauPn00", "rbp32", status); + vvd(rbp[2][2], 0.9999998301093036269, 1e-12, + "iauPn00", "rbp33", status); + + vvd(rn[0][0], 0.9999999999536069682, 1e-12, + "iauPn00", "rn11", status); + vvd(rn[0][1], 0.8837746144872140812e-5, 1e-16, + "iauPn00", "rn12", status); + vvd(rn[0][2], 0.3831488838252590008e-5, 1e-16, + "iauPn00", "rn13", status); + + vvd(rn[1][0], -0.8837590456633197506e-5, 1e-16, + "iauPn00", "rn21", status); + vvd(rn[1][1], 0.9999999991354692733, 1e-12, + "iauPn00", "rn22", status); + vvd(rn[1][2], -0.4063198798559573702e-4, 1e-16, + "iauPn00", "rn23", status); + + vvd(rn[2][0], -0.3831847930135328368e-5, 1e-16, + "iauPn00", "rn31", status); + vvd(rn[2][1], 0.4063195412258150427e-4, 1e-16, + "iauPn00", "rn32", status); + vvd(rn[2][2], 0.9999999991671806225, 1e-12, + "iauPn00", "rn33", status); + + vvd(rbpn[0][0], 0.9999989440499982806, 1e-12, + "iauPn00", "rbpn11", status); + vvd(rbpn[0][1], -0.1332880253640848301e-2, 1e-14, + "iauPn00", "rbpn12", status); + vvd(rbpn[0][2], -0.5790760898731087295e-3, 1e-14, + "iauPn00", "rbpn13", status); + + vvd(rbpn[1][0], 0.1332856746979948745e-2, 1e-14, + "iauPn00", "rbpn21", status); + vvd(rbpn[1][1], 0.9999991109064768883, 1e-12, + "iauPn00", "rbpn22", status); + vvd(rbpn[1][2], -0.4097740555723063806e-4, 1e-14, + "iauPn00", "rbpn23", status); + + vvd(rbpn[2][0], 0.5791301929950205000e-3, 1e-14, + "iauPn00", "rbpn31", status); + vvd(rbpn[2][1], 0.4020553681373702931e-4, 1e-14, + "iauPn00", "rbpn32", status); + vvd(rbpn[2][2], 0.9999998314958529887, 1e-12, + "iauPn00", "rbpn33", status); + +} + +static void t_pn00a(int *status) +/* +** - - - - - - - - +** t _ p n 0 0 a +** - - - - - - - - +** +** Test iauPn00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPn00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps, epsa, + rb[3][3], rp[3][3], rbp[3][3], rn[3][3], rbpn[3][3]; + + + iauPn00a(2400000.5, 53736.0, + &dpsi, &deps, &epsa, rb, rp, rbp, rn, rbpn); + + vvd(dpsi, -0.9630909107115518431e-5, 1e-12, + "iauPn00a", "dpsi", status); + vvd(deps, 0.4063239174001678710e-4, 1e-12, + "iauPn00a", "deps", status); + vvd(epsa, 0.4090791789404229916, 1e-12, "iauPn00a", "epsa", status); + + vvd(rb[0][0], 0.9999999999999942498, 1e-12, + "iauPn00a", "rb11", status); + vvd(rb[0][1], -0.7078279744199196626e-7, 1e-16, + "iauPn00a", "rb12", status); + vvd(rb[0][2], 0.8056217146976134152e-7, 1e-16, + "iauPn00a", "rb13", status); + + vvd(rb[1][0], 0.7078279477857337206e-7, 1e-16, + "iauPn00a", "rb21", status); + vvd(rb[1][1], 0.9999999999999969484, 1e-12, + "iauPn00a", "rb22", status); + vvd(rb[1][2], 0.3306041454222136517e-7, 1e-16, + "iauPn00a", "rb23", status); + + vvd(rb[2][0], -0.8056217380986972157e-7, 1e-16, + "iauPn00a", "rb31", status); + vvd(rb[2][1], -0.3306040883980552500e-7, 1e-16, + "iauPn00a", "rb32", status); + vvd(rb[2][2], 0.9999999999999962084, 1e-12, + "iauPn00a", "rb33", status); + + vvd(rp[0][0], 0.9999989300532289018, 1e-12, + "iauPn00a", "rp11", status); + vvd(rp[0][1], -0.1341647226791824349e-2, 1e-14, + "iauPn00a", "rp12", status); + vvd(rp[0][2], -0.5829880927190296547e-3, 1e-14, + "iauPn00a", "rp13", status); + + vvd(rp[1][0], 0.1341647231069759008e-2, 1e-14, + "iauPn00a", "rp21", status); + vvd(rp[1][1], 0.9999990999908750433, 1e-12, + "iauPn00a", "rp22", status); + vvd(rp[1][2], -0.3837444441583715468e-6, 1e-14, + "iauPn00a", "rp23", status); + + vvd(rp[2][0], 0.5829880828740957684e-3, 1e-14, + "iauPn00a", "rp31", status); + vvd(rp[2][1], -0.3984203267708834759e-6, 1e-14, + "iauPn00a", "rp32", status); + vvd(rp[2][2], 0.9999998300623538046, 1e-12, + "iauPn00a", "rp33", status); + + vvd(rbp[0][0], 0.9999989300052243993, 1e-12, + "iauPn00a", "rbp11", status); + vvd(rbp[0][1], -0.1341717990239703727e-2, 1e-14, + "iauPn00a", "rbp12", status); + vvd(rbp[0][2], -0.5829075749891684053e-3, 1e-14, + "iauPn00a", "rbp13", status); + + vvd(rbp[1][0], 0.1341718013831739992e-2, 1e-14, + "iauPn00a", "rbp21", status); + vvd(rbp[1][1], 0.9999990998959191343, 1e-12, + "iauPn00a", "rbp22", status); + vvd(rbp[1][2], -0.3505759733565421170e-6, 1e-14, + "iauPn00a", "rbp23", status); + + vvd(rbp[2][0], 0.5829075206857717883e-3, 1e-14, + "iauPn00a", "rbp31", status); + vvd(rbp[2][1], -0.4315219955198608970e-6, 1e-14, + "iauPn00a", "rbp32", status); + vvd(rbp[2][2], 0.9999998301093036269, 1e-12, + "iauPn00a", "rbp33", status); + + vvd(rn[0][0], 0.9999999999536227949, 1e-12, + "iauPn00a", "rn11", status); + vvd(rn[0][1], 0.8836238544090873336e-5, 1e-14, + "iauPn00a", "rn12", status); + vvd(rn[0][2], 0.3830835237722400669e-5, 1e-14, + "iauPn00a", "rn13", status); + + vvd(rn[1][0], -0.8836082880798569274e-5, 1e-14, + "iauPn00a", "rn21", status); + vvd(rn[1][1], 0.9999999991354655028, 1e-12, + "iauPn00a", "rn22", status); + vvd(rn[1][2], -0.4063240865362499850e-4, 1e-14, + "iauPn00a", "rn23", status); + + vvd(rn[2][0], -0.3831194272065995866e-5, 1e-14, + "iauPn00a", "rn31", status); + vvd(rn[2][1], 0.4063237480216291775e-4, 1e-14, + "iauPn00a", "rn32", status); + vvd(rn[2][2], 0.9999999991671660338, 1e-12, + "iauPn00a", "rn33", status); + + vvd(rbpn[0][0], 0.9999989440476103435, 1e-12, + "iauPn00a", "rbpn11", status); + vvd(rbpn[0][1], -0.1332881761240011763e-2, 1e-14, + "iauPn00a", "rbpn12", status); + vvd(rbpn[0][2], -0.5790767434730085751e-3, 1e-14, + "iauPn00a", "rbpn13", status); + + vvd(rbpn[1][0], 0.1332858254308954658e-2, 1e-14, + "iauPn00a", "rbpn21", status); + vvd(rbpn[1][1], 0.9999991109044505577, 1e-12, + "iauPn00a", "rbpn22", status); + vvd(rbpn[1][2], -0.4097782710396580452e-4, 1e-14, + "iauPn00a", "rbpn23", status); + + vvd(rbpn[2][0], 0.5791308472168152904e-3, 1e-14, + "iauPn00a", "rbpn31", status); + vvd(rbpn[2][1], 0.4020595661591500259e-4, 1e-14, + "iauPn00a", "rbpn32", status); + vvd(rbpn[2][2], 0.9999998314954572304, 1e-12, + "iauPn00a", "rbpn33", status); + +} + +static void t_pn00b(int *status) +/* +** - - - - - - - - +** t _ p n 0 0 b +** - - - - - - - - +** +** Test iauPn00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPn00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps, epsa, + rb[3][3], rp[3][3], rbp[3][3], rn[3][3], rbpn[3][3]; + + + iauPn00b(2400000.5, 53736.0, &dpsi, &deps, &epsa, + rb, rp, rbp, rn, rbpn); + + vvd(dpsi, -0.9632552291148362783e-5, 1e-12, + "iauPn00b", "dpsi", status); + vvd(deps, 0.4063197106621159367e-4, 1e-12, + "iauPn00b", "deps", status); + vvd(epsa, 0.4090791789404229916, 1e-12, "iauPn00b", "epsa", status); + + vvd(rb[0][0], 0.9999999999999942498, 1e-12, + "iauPn00b", "rb11", status); + vvd(rb[0][1], -0.7078279744199196626e-7, 1e-16, + "iauPn00b", "rb12", status); + vvd(rb[0][2], 0.8056217146976134152e-7, 1e-16, + "iauPn00b", "rb13", status); + + vvd(rb[1][0], 0.7078279477857337206e-7, 1e-16, + "iauPn00b", "rb21", status); + vvd(rb[1][1], 0.9999999999999969484, 1e-12, + "iauPn00b", "rb22", status); + vvd(rb[1][2], 0.3306041454222136517e-7, 1e-16, + "iauPn00b", "rb23", status); + + vvd(rb[2][0], -0.8056217380986972157e-7, 1e-16, + "iauPn00b", "rb31", status); + vvd(rb[2][1], -0.3306040883980552500e-7, 1e-16, + "iauPn00b", "rb32", status); + vvd(rb[2][2], 0.9999999999999962084, 1e-12, + "iauPn00b", "rb33", status); + + vvd(rp[0][0], 0.9999989300532289018, 1e-12, + "iauPn00b", "rp11", status); + vvd(rp[0][1], -0.1341647226791824349e-2, 1e-14, + "iauPn00b", "rp12", status); + vvd(rp[0][2], -0.5829880927190296547e-3, 1e-14, + "iauPn00b", "rp13", status); + + vvd(rp[1][0], 0.1341647231069759008e-2, 1e-14, + "iauPn00b", "rp21", status); + vvd(rp[1][1], 0.9999990999908750433, 1e-12, + "iauPn00b", "rp22", status); + vvd(rp[1][2], -0.3837444441583715468e-6, 1e-14, + "iauPn00b", "rp23", status); + + vvd(rp[2][0], 0.5829880828740957684e-3, 1e-14, + "iauPn00b", "rp31", status); + vvd(rp[2][1], -0.3984203267708834759e-6, 1e-14, + "iauPn00b", "rp32", status); + vvd(rp[2][2], 0.9999998300623538046, 1e-12, + "iauPn00b", "rp33", status); + + vvd(rbp[0][0], 0.9999989300052243993, 1e-12, + "iauPn00b", "rbp11", status); + vvd(rbp[0][1], -0.1341717990239703727e-2, 1e-14, + "iauPn00b", "rbp12", status); + vvd(rbp[0][2], -0.5829075749891684053e-3, 1e-14, + "iauPn00b", "rbp13", status); + + vvd(rbp[1][0], 0.1341718013831739992e-2, 1e-14, + "iauPn00b", "rbp21", status); + vvd(rbp[1][1], 0.9999990998959191343, 1e-12, + "iauPn00b", "rbp22", status); + vvd(rbp[1][2], -0.3505759733565421170e-6, 1e-14, + "iauPn00b", "rbp23", status); + + vvd(rbp[2][0], 0.5829075206857717883e-3, 1e-14, + "iauPn00b", "rbp31", status); + vvd(rbp[2][1], -0.4315219955198608970e-6, 1e-14, + "iauPn00b", "rbp32", status); + vvd(rbp[2][2], 0.9999998301093036269, 1e-12, + "iauPn00b", "rbp33", status); + + vvd(rn[0][0], 0.9999999999536069682, 1e-12, + "iauPn00b", "rn11", status); + vvd(rn[0][1], 0.8837746144871248011e-5, 1e-14, + "iauPn00b", "rn12", status); + vvd(rn[0][2], 0.3831488838252202945e-5, 1e-14, + "iauPn00b", "rn13", status); + + vvd(rn[1][0], -0.8837590456632304720e-5, 1e-14, + "iauPn00b", "rn21", status); + vvd(rn[1][1], 0.9999999991354692733, 1e-12, + "iauPn00b", "rn22", status); + vvd(rn[1][2], -0.4063198798559591654e-4, 1e-14, + "iauPn00b", "rn23", status); + + vvd(rn[2][0], -0.3831847930134941271e-5, 1e-14, + "iauPn00b", "rn31", status); + vvd(rn[2][1], 0.4063195412258168380e-4, 1e-14, + "iauPn00b", "rn32", status); + vvd(rn[2][2], 0.9999999991671806225, 1e-12, + "iauPn00b", "rn33", status); + + vvd(rbpn[0][0], 0.9999989440499982806, 1e-12, + "iauPn00b", "rbpn11", status); + vvd(rbpn[0][1], -0.1332880253640849194e-2, 1e-14, + "iauPn00b", "rbpn12", status); + vvd(rbpn[0][2], -0.5790760898731091166e-3, 1e-14, + "iauPn00b", "rbpn13", status); + + vvd(rbpn[1][0], 0.1332856746979949638e-2, 1e-14, + "iauPn00b", "rbpn21", status); + vvd(rbpn[1][1], 0.9999991109064768883, 1e-12, + "iauPn00b", "rbpn22", status); + vvd(rbpn[1][2], -0.4097740555723081811e-4, 1e-14, + "iauPn00b", "rbpn23", status); + + vvd(rbpn[2][0], 0.5791301929950208873e-3, 1e-14, + "iauPn00b", "rbpn31", status); + vvd(rbpn[2][1], 0.4020553681373720832e-4, 1e-14, + "iauPn00b", "rbpn32", status); + vvd(rbpn[2][2], 0.9999998314958529887, 1e-12, + "iauPn00b", "rbpn33", status); + +} + +static void t_pn06a(int *status) +/* +** - - - - - - - - +** t _ p n 0 6 a +** - - - - - - - - +** +** Test iauPn06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPn06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps, epsa; + double rb[3][3], rp[3][3], rbp[3][3], rn[3][3], rbpn[3][3]; + + + iauPn06a(2400000.5, 53736.0, &dpsi, &deps, &epsa, + rb, rp, rbp, rn, rbpn); + + vvd(dpsi, -0.9630912025820308797e-5, 1e-12, + "iauPn06a", "dpsi", status); + vvd(deps, 0.4063238496887249798e-4, 1e-12, + "iauPn06a", "deps", status); + vvd(epsa, 0.4090789763356509926, 1e-12, "iauPn06a", "epsa", status); + + vvd(rb[0][0], 0.9999999999999942497, 1e-12, + "iauPn06a", "rb11", status); + vvd(rb[0][1], -0.7078368960971557145e-7, 1e-14, + "iauPn06a", "rb12", status); + vvd(rb[0][2], 0.8056213977613185606e-7, 1e-14, + "iauPn06a", "rb13", status); + + vvd(rb[1][0], 0.7078368694637674333e-7, 1e-14, + "iauPn06a", "rb21", status); + vvd(rb[1][1], 0.9999999999999969484, 1e-12, + "iauPn06a", "rb22", status); + vvd(rb[1][2], 0.3305943742989134124e-7, 1e-14, + "iauPn06a", "rb23", status); + + vvd(rb[2][0], -0.8056214211620056792e-7, 1e-14, + "iauPn06a", "rb31", status); + vvd(rb[2][1], -0.3305943172740586950e-7, 1e-14, + "iauPn06a", "rb32", status); + vvd(rb[2][2], 0.9999999999999962084, 1e-12, + "iauPn06a", "rb33", status); + + vvd(rp[0][0], 0.9999989300536854831, 1e-12, + "iauPn06a", "rp11", status); + vvd(rp[0][1], -0.1341646886204443795e-2, 1e-14, + "iauPn06a", "rp12", status); + vvd(rp[0][2], -0.5829880933488627759e-3, 1e-14, + "iauPn06a", "rp13", status); + + vvd(rp[1][0], 0.1341646890569782183e-2, 1e-14, + "iauPn06a", "rp21", status); + vvd(rp[1][1], 0.9999990999913319321, 1e-12, + "iauPn06a", "rp22", status); + vvd(rp[1][2], -0.3835944216374477457e-6, 1e-14, + "iauPn06a", "rp23", status); + + vvd(rp[2][0], 0.5829880833027867368e-3, 1e-14, + "iauPn06a", "rp31", status); + vvd(rp[2][1], -0.3985701514686976112e-6, 1e-14, + "iauPn06a", "rp32", status); + vvd(rp[2][2], 0.9999998300623534950, 1e-12, + "iauPn06a", "rp33", status); + + vvd(rbp[0][0], 0.9999989300056797893, 1e-12, + "iauPn06a", "rbp11", status); + vvd(rbp[0][1], -0.1341717650545059598e-2, 1e-14, + "iauPn06a", "rbp12", status); + vvd(rbp[0][2], -0.5829075756493728856e-3, 1e-14, + "iauPn06a", "rbp13", status); + + vvd(rbp[1][0], 0.1341717674223918101e-2, 1e-14, + "iauPn06a", "rbp21", status); + vvd(rbp[1][1], 0.9999990998963748448, 1e-12, + "iauPn06a", "rbp22", status); + vvd(rbp[1][2], -0.3504269280170069029e-6, 1e-14, + "iauPn06a", "rbp23", status); + + vvd(rbp[2][0], 0.5829075211461454599e-3, 1e-14, + "iauPn06a", "rbp31", status); + vvd(rbp[2][1], -0.4316708436255949093e-6, 1e-14, + "iauPn06a", "rbp32", status); + vvd(rbp[2][2], 0.9999998301093032943, 1e-12, + "iauPn06a", "rbp33", status); + + vvd(rn[0][0], 0.9999999999536227668, 1e-12, + "iauPn06a", "rn11", status); + vvd(rn[0][1], 0.8836241998111535233e-5, 1e-14, + "iauPn06a", "rn12", status); + vvd(rn[0][2], 0.3830834608415287707e-5, 1e-14, + "iauPn06a", "rn13", status); + + vvd(rn[1][0], -0.8836086334870740138e-5, 1e-14, + "iauPn06a", "rn21", status); + vvd(rn[1][1], 0.9999999991354657474, 1e-12, + "iauPn06a", "rn22", status); + vvd(rn[1][2], -0.4063240188248455065e-4, 1e-14, + "iauPn06a", "rn23", status); + + vvd(rn[2][0], -0.3831193642839398128e-5, 1e-14, + "iauPn06a", "rn31", status); + vvd(rn[2][1], 0.4063236803101479770e-4, 1e-14, + "iauPn06a", "rn32", status); + vvd(rn[2][2], 0.9999999991671663114, 1e-12, + "iauPn06a", "rn33", status); + + vvd(rbpn[0][0], 0.9999989440480669738, 1e-12, + "iauPn06a", "rbpn11", status); + vvd(rbpn[0][1], -0.1332881418091915973e-2, 1e-14, + "iauPn06a", "rbpn12", status); + vvd(rbpn[0][2], -0.5790767447612042565e-3, 1e-14, + "iauPn06a", "rbpn13", status); + + vvd(rbpn[1][0], 0.1332857911250989133e-2, 1e-14, + "iauPn06a", "rbpn21", status); + vvd(rbpn[1][1], 0.9999991109049141908, 1e-12, + "iauPn06a", "rbpn22", status); + vvd(rbpn[1][2], -0.4097767128546784878e-4, 1e-14, + "iauPn06a", "rbpn23", status); + + vvd(rbpn[2][0], 0.5791308482835292617e-3, 1e-14, + "iauPn06a", "rbpn31", status); + vvd(rbpn[2][1], 0.4020580099454020310e-4, 1e-14, + "iauPn06a", "rbpn32", status); + vvd(rbpn[2][2], 0.9999998314954628695, 1e-12, + "iauPn06a", "rbpn33", status); + +} + +static void t_pn06(int *status) +/* +** - - - - - - - +** t _ p n 0 6 +** - - - - - - - +** +** Test iauPn06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPn06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsi, deps, epsa, + rb[3][3], rp[3][3], rbp[3][3], rn[3][3], rbpn[3][3]; + + + dpsi = -0.9632552291149335877e-5; + deps = 0.4063197106621141414e-4; + + iauPn06(2400000.5, 53736.0, dpsi, deps, + &epsa, rb, rp, rbp, rn, rbpn); + + vvd(epsa, 0.4090789763356509926, 1e-12, "iauPn06", "epsa", status); + + vvd(rb[0][0], 0.9999999999999942497, 1e-12, + "iauPn06", "rb11", status); + vvd(rb[0][1], -0.7078368960971557145e-7, 1e-14, + "iauPn06", "rb12", status); + vvd(rb[0][2], 0.8056213977613185606e-7, 1e-14, + "iauPn06", "rb13", status); + + vvd(rb[1][0], 0.7078368694637674333e-7, 1e-14, + "iauPn06", "rb21", status); + vvd(rb[1][1], 0.9999999999999969484, 1e-12, + "iauPn06", "rb22", status); + vvd(rb[1][2], 0.3305943742989134124e-7, 1e-14, + "iauPn06", "rb23", status); + + vvd(rb[2][0], -0.8056214211620056792e-7, 1e-14, + "iauPn06", "rb31", status); + vvd(rb[2][1], -0.3305943172740586950e-7, 1e-14, + "iauPn06", "rb32", status); + vvd(rb[2][2], 0.9999999999999962084, 1e-12, + "iauPn06", "rb33", status); + + vvd(rp[0][0], 0.9999989300536854831, 1e-12, + "iauPn06", "rp11", status); + vvd(rp[0][1], -0.1341646886204443795e-2, 1e-14, + "iauPn06", "rp12", status); + vvd(rp[0][2], -0.5829880933488627759e-3, 1e-14, + "iauPn06", "rp13", status); + + vvd(rp[1][0], 0.1341646890569782183e-2, 1e-14, + "iauPn06", "rp21", status); + vvd(rp[1][1], 0.9999990999913319321, 1e-12, + "iauPn06", "rp22", status); + vvd(rp[1][2], -0.3835944216374477457e-6, 1e-14, + "iauPn06", "rp23", status); + + vvd(rp[2][0], 0.5829880833027867368e-3, 1e-14, + "iauPn06", "rp31", status); + vvd(rp[2][1], -0.3985701514686976112e-6, 1e-14, + "iauPn06", "rp32", status); + vvd(rp[2][2], 0.9999998300623534950, 1e-12, + "iauPn06", "rp33", status); + + vvd(rbp[0][0], 0.9999989300056797893, 1e-12, + "iauPn06", "rbp11", status); + vvd(rbp[0][1], -0.1341717650545059598e-2, 1e-14, + "iauPn06", "rbp12", status); + vvd(rbp[0][2], -0.5829075756493728856e-3, 1e-14, + "iauPn06", "rbp13", status); + + vvd(rbp[1][0], 0.1341717674223918101e-2, 1e-14, + "iauPn06", "rbp21", status); + vvd(rbp[1][1], 0.9999990998963748448, 1e-12, + "iauPn06", "rbp22", status); + vvd(rbp[1][2], -0.3504269280170069029e-6, 1e-14, + "iauPn06", "rbp23", status); + + vvd(rbp[2][0], 0.5829075211461454599e-3, 1e-14, + "iauPn06", "rbp31", status); + vvd(rbp[2][1], -0.4316708436255949093e-6, 1e-14, + "iauPn06", "rbp32", status); + vvd(rbp[2][2], 0.9999998301093032943, 1e-12, + "iauPn06", "rbp33", status); + + vvd(rn[0][0], 0.9999999999536069682, 1e-12, + "iauPn06", "rn11", status); + vvd(rn[0][1], 0.8837746921149881914e-5, 1e-14, + "iauPn06", "rn12", status); + vvd(rn[0][2], 0.3831487047682968703e-5, 1e-14, + "iauPn06", "rn13", status); + + vvd(rn[1][0], -0.8837591232983692340e-5, 1e-14, + "iauPn06", "rn21", status); + vvd(rn[1][1], 0.9999999991354692664, 1e-12, + "iauPn06", "rn22", status); + vvd(rn[1][2], -0.4063198798558931215e-4, 1e-14, + "iauPn06", "rn23", status); + + vvd(rn[2][0], -0.3831846139597250235e-5, 1e-14, + "iauPn06", "rn31", status); + vvd(rn[2][1], 0.4063195412258792914e-4, 1e-14, + "iauPn06", "rn32", status); + vvd(rn[2][2], 0.9999999991671806293, 1e-12, + "iauPn06", "rn33", status); + + vvd(rbpn[0][0], 0.9999989440504506688, 1e-12, + "iauPn06", "rbpn11", status); + vvd(rbpn[0][1], -0.1332879913170492655e-2, 1e-14, + "iauPn06", "rbpn12", status); + vvd(rbpn[0][2], -0.5790760923225655753e-3, 1e-14, + "iauPn06", "rbpn13", status); + + vvd(rbpn[1][0], 0.1332856406595754748e-2, 1e-14, + "iauPn06", "rbpn21", status); + vvd(rbpn[1][1], 0.9999991109069366795, 1e-12, + "iauPn06", "rbpn22", status); + vvd(rbpn[1][2], -0.4097725651142641812e-4, 1e-14, + "iauPn06", "rbpn23", status); + + vvd(rbpn[2][0], 0.5791301952321296716e-3, 1e-14, + "iauPn06", "rbpn31", status); + vvd(rbpn[2][1], 0.4020538796195230577e-4, 1e-14, + "iauPn06", "rbpn32", status); + vvd(rbpn[2][2], 0.9999998314958576778, 1e-12, + "iauPn06", "rbpn33", status); + +} + +static void t_pnm00a(int *status) +/* +** - - - - - - - - - +** t _ p n m 0 0 a +** - - - - - - - - - +** +** Test iauPnm00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPnm00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbpn[3][3]; + + + iauPnm00a(2400000.5, 50123.9999, rbpn); + + vvd(rbpn[0][0], 0.9999995832793134257, 1e-12, + "iauPnm00a", "11", status); + vvd(rbpn[0][1], 0.8372384254137809439e-3, 1e-14, + "iauPnm00a", "12", status); + vvd(rbpn[0][2], 0.3639684306407150645e-3, 1e-14, + "iauPnm00a", "13", status); + + vvd(rbpn[1][0], -0.8372535226570394543e-3, 1e-14, + "iauPnm00a", "21", status); + vvd(rbpn[1][1], 0.9999996486491582471, 1e-12, + "iauPnm00a", "22", status); + vvd(rbpn[1][2], 0.4132915262664072381e-4, 1e-14, + "iauPnm00a", "23", status); + + vvd(rbpn[2][0], -0.3639337004054317729e-3, 1e-14, + "iauPnm00a", "31", status); + vvd(rbpn[2][1], -0.4163386925461775873e-4, 1e-14, + "iauPnm00a", "32", status); + vvd(rbpn[2][2], 0.9999999329094390695, 1e-12, + "iauPnm00a", "33", status); + +} + +static void t_pnm00b(int *status) +/* +** - - - - - - - - - +** t _ p n m 0 0 b +** - - - - - - - - - +** +** Test iauPnm00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPnm00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbpn[3][3]; + + + iauPnm00b(2400000.5, 50123.9999, rbpn); + + vvd(rbpn[0][0], 0.9999995832776208280, 1e-12, + "iauPnm00b", "11", status); + vvd(rbpn[0][1], 0.8372401264429654837e-3, 1e-14, + "iauPnm00b", "12", status); + vvd(rbpn[0][2], 0.3639691681450271771e-3, 1e-14, + "iauPnm00b", "13", status); + + vvd(rbpn[1][0], -0.8372552234147137424e-3, 1e-14, + "iauPnm00b", "21", status); + vvd(rbpn[1][1], 0.9999996486477686123, 1e-12, + "iauPnm00b", "22", status); + vvd(rbpn[1][2], 0.4132832190946052890e-4, 1e-14, + "iauPnm00b", "23", status); + + vvd(rbpn[2][0], -0.3639344385341866407e-3, 1e-14, + "iauPnm00b", "31", status); + vvd(rbpn[2][1], -0.4163303977421522785e-4, 1e-14, + "iauPnm00b", "32", status); + vvd(rbpn[2][2], 0.9999999329092049734, 1e-12, + "iauPnm00b", "33", status); + +} + +static void t_pnm06a(int *status) +/* +** - - - - - - - - - +** t _ p n m 0 6 a +** - - - - - - - - - +** +** Test iauPnm06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPnm06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rbpn[3][3]; + + + iauPnm06a(2400000.5, 50123.9999, rbpn); + + vvd(rbpn[0][0], 0.9999995832794205484, 1e-12, + "iauPnm06a", "11", status); + vvd(rbpn[0][1], 0.8372382772630962111e-3, 1e-14, + "iauPnm06a", "12", status); + vvd(rbpn[0][2], 0.3639684771140623099e-3, 1e-14, + "iauPnm06a", "13", status); + + vvd(rbpn[1][0], -0.8372533744743683605e-3, 1e-14, + "iauPnm06a", "21", status); + vvd(rbpn[1][1], 0.9999996486492861646, 1e-12, + "iauPnm06a", "22", status); + vvd(rbpn[1][2], 0.4132905944611019498e-4, 1e-14, + "iauPnm06a", "23", status); + + vvd(rbpn[2][0], -0.3639337469629464969e-3, 1e-14, + "iauPnm06a", "31", status); + vvd(rbpn[2][1], -0.4163377605910663999e-4, 1e-14, + "iauPnm06a", "32", status); + vvd(rbpn[2][2], 0.9999999329094260057, 1e-12, + "iauPnm06a", "33", status); + +} + +static void t_pnm80(int *status) +/* +** - - - - - - - - +** t _ p n m 8 0 +** - - - - - - - - +** +** Test iauPnm80 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPnm80, vvd +** +** This revision: 2013 August 7 +*/ +{ + double rmatpn[3][3]; + + + iauPnm80(2400000.5, 50123.9999, rmatpn); + + vvd(rmatpn[0][0], 0.9999995831934611169, 1e-12, + "iauPnm80", "11", status); + vvd(rmatpn[0][1], 0.8373654045728124011e-3, 1e-14, + "iauPnm80", "12", status); + vvd(rmatpn[0][2], 0.3639121916933106191e-3, 1e-14, + "iauPnm80", "13", status); + + vvd(rmatpn[1][0], -0.8373804896118301316e-3, 1e-14, + "iauPnm80", "21", status); + vvd(rmatpn[1][1], 0.9999996485439674092, 1e-12, + "iauPnm80", "22", status); + vvd(rmatpn[1][2], 0.4130202510421549752e-4, 1e-14, + "iauPnm80", "23", status); + + vvd(rmatpn[2][0], -0.3638774789072144473e-3, 1e-14, + "iauPnm80", "31", status); + vvd(rmatpn[2][1], -0.4160674085851722359e-4, 1e-14, + "iauPnm80", "32", status); + vvd(rmatpn[2][2], 0.9999999329310274805, 1e-12, + "iauPnm80", "33", status); + +} + +static void t_pom00(int *status) +/* +** - - - - - - - - +** t _ p o m 0 0 +** - - - - - - - - +** +** Test iauPom00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPom00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double xp, yp, sp, rpom[3][3]; + + + xp = 2.55060238e-7; + yp = 1.860359247e-6; + sp = -0.1367174580728891460e-10; + + iauPom00(xp, yp, sp, rpom); + + vvd(rpom[0][0], 0.9999999999999674721, 1e-12, + "iauPom00", "11", status); + vvd(rpom[0][1], -0.1367174580728846989e-10, 1e-16, + "iauPom00", "12", status); + vvd(rpom[0][2], 0.2550602379999972345e-6, 1e-16, + "iauPom00", "13", status); + + vvd(rpom[1][0], 0.1414624947957029801e-10, 1e-16, + "iauPom00", "21", status); + vvd(rpom[1][1], 0.9999999999982695317, 1e-12, + "iauPom00", "22", status); + vvd(rpom[1][2], -0.1860359246998866389e-5, 1e-16, + "iauPom00", "23", status); + + vvd(rpom[2][0], -0.2550602379741215021e-6, 1e-16, + "iauPom00", "31", status); + vvd(rpom[2][1], 0.1860359247002414021e-5, 1e-16, + "iauPom00", "32", status); + vvd(rpom[2][2], 0.9999999999982370039, 1e-12, + "iauPom00", "33", status); + +} + +static void t_ppp(int *status) +/* +** - - - - - - +** t _ p p p +** - - - - - - +** +** Test iauPpp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPpp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3], b[3], apb[3]; + + + a[0] = 2.0; + a[1] = 2.0; + a[2] = 3.0; + + b[0] = 1.0; + b[1] = 3.0; + b[2] = 4.0; + + iauPpp(a, b, apb); + + vvd(apb[0], 3.0, 1e-12, "iauPpp", "0", status); + vvd(apb[1], 5.0, 1e-12, "iauPpp", "1", status); + vvd(apb[2], 7.0, 1e-12, "iauPpp", "2", status); + +} + +static void t_ppsp(int *status) +/* +** - - - - - - - +** t _ p p s p +** - - - - - - - +** +** Test iauPpsp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPpsp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3], s, b[3], apsb[3]; + + + a[0] = 2.0; + a[1] = 2.0; + a[2] = 3.0; + + s = 5.0; + + b[0] = 1.0; + b[1] = 3.0; + b[2] = 4.0; + + iauPpsp(a, s, b, apsb); + + vvd(apsb[0], 7.0, 1e-12, "iauPpsp", "0", status); + vvd(apsb[1], 17.0, 1e-12, "iauPpsp", "1", status); + vvd(apsb[2], 23.0, 1e-12, "iauPpsp", "2", status); + +} + +static void t_pr00(int *status) +/* +** - - - - - - - +** t _ p r 0 0 +** - - - - - - - +** +** Test iauPr00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPr00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double dpsipr, depspr; + + iauPr00(2400000.5, 53736, &dpsipr, &depspr); + + vvd(dpsipr, -0.8716465172668347629e-7, 1e-22, + "iauPr00", "dpsipr", status); + vvd(depspr, -0.7342018386722813087e-8, 1e-22, + "iauPr00", "depspr", status); + +} + +static void t_prec76(int *status) +/* +** - - - - - - - - - +** t _ p r e c 7 6 +** - - - - - - - - - +** +** Test iauPrec76 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPrec76, vvd +** +** This revision: 2013 August 7 +*/ +{ + double ep01, ep02, ep11, ep12, zeta, z, theta; + + + ep01 = 2400000.5; + ep02 = 33282.0; + ep11 = 2400000.5; + ep12 = 51544.0; + + iauPrec76(ep01, ep02, ep11, ep12, &zeta, &z, &theta); + + vvd(zeta, 0.5588961642000161243e-2, 1e-12, + "iauPrec76", "zeta", status); + vvd(z, 0.5589922365870680624e-2, 1e-12, + "iauPrec76", "z", status); + vvd(theta, 0.4858945471687296760e-2, 1e-12, + "iauPrec76", "theta", status); + +} + +static void t_pv2p(int *status) +/* +** - - - - - - - +** t _ p v 2 p +** - - - - - - - +** +** Test iauPv2p function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPv2p, vvd +** +** This revision: 2013 August 7 +*/ +{ + double pv[2][3], p[3]; + + + pv[0][0] = 0.3; + pv[0][1] = 1.2; + pv[0][2] = -2.5; + + pv[1][0] = -0.5; + pv[1][1] = 3.1; + pv[1][2] = 0.9; + + iauPv2p(pv, p); + + vvd(p[0], 0.3, 0.0, "iauPv2p", "1", status); + vvd(p[1], 1.2, 0.0, "iauPv2p", "2", status); + vvd(p[2], -2.5, 0.0, "iauPv2p", "3", status); + +} + +static void t_pv2s(int *status) +/* +** - - - - - - - +** t _ p v 2 s +** - - - - - - - +** +** Test iauPv2s function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPv2s, vvd +** +** This revision: 2013 August 7 +*/ +{ + double pv[2][3], theta, phi, r, td, pd, rd; + + + pv[0][0] = -0.4514964673880165; + pv[0][1] = 0.03093394277342585; + pv[0][2] = 0.05594668105108779; + + pv[1][0] = 1.292270850663260e-5; + pv[1][1] = 2.652814182060692e-6; + pv[1][2] = 2.568431853930293e-6; + + iauPv2s(pv, &theta, &phi, &r, &td, &pd, &rd); + + vvd(theta, 3.073185307179586515, 1e-12, "iauPv2s", "theta", status); + vvd(phi, 0.1229999999999999992, 1e-12, "iauPv2s", "phi", status); + vvd(r, 0.4559999999999999757, 1e-12, "iauPv2s", "r", status); + vvd(td, -0.7800000000000000364e-5, 1e-16, "iauPv2s", "td", status); + vvd(pd, 0.9010000000000001639e-5, 1e-16, "iauPv2s", "pd", status); + vvd(rd, -0.1229999999999999832e-4, 1e-16, "iauPv2s", "rd", status); + +} + +static void t_pvdpv(int *status) +/* +** - - - - - - - - +** t _ p v d p v +** - - - - - - - - +** +** Test iauPvdpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvdpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[2][3], b[2][3], adb[2]; + + + a[0][0] = 2.0; + a[0][1] = 2.0; + a[0][2] = 3.0; + + a[1][0] = 6.0; + a[1][1] = 0.0; + a[1][2] = 4.0; + + b[0][0] = 1.0; + b[0][1] = 3.0; + b[0][2] = 4.0; + + b[1][0] = 0.0; + b[1][1] = 2.0; + b[1][2] = 8.0; + + iauPvdpv(a, b, adb); + + vvd(adb[0], 20.0, 1e-12, "iauPvdpv", "1", status); + vvd(adb[1], 50.0, 1e-12, "iauPvdpv", "2", status); + +} + +static void t_pvm(int *status) +/* +** - - - - - - +** t _ p v m +** - - - - - - +** +** Test iauPvm function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvm, vvd +** +** This revision: 2013 August 7 +*/ +{ + double pv[2][3], r, s; + + + pv[0][0] = 0.3; + pv[0][1] = 1.2; + pv[0][2] = -2.5; + + pv[1][0] = 0.45; + pv[1][1] = -0.25; + pv[1][2] = 1.1; + + iauPvm(pv, &r, &s); + + vvd(r, 2.789265136196270604, 1e-12, "iauPvm", "r", status); + vvd(s, 1.214495780149111922, 1e-12, "iauPvm", "s", status); + +} + +static void t_pvmpv(int *status) +/* +** - - - - - - - - +** t _ p v m p v +** - - - - - - - - +** +** Test iauPvmpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvmpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[2][3], b[2][3], amb[2][3]; + + + a[0][0] = 2.0; + a[0][1] = 2.0; + a[0][2] = 3.0; + + a[1][0] = 5.0; + a[1][1] = 6.0; + a[1][2] = 3.0; + + b[0][0] = 1.0; + b[0][1] = 3.0; + b[0][2] = 4.0; + + b[1][0] = 3.0; + b[1][1] = 2.0; + b[1][2] = 1.0; + + iauPvmpv(a, b, amb); + + vvd(amb[0][0], 1.0, 1e-12, "iauPvmpv", "11", status); + vvd(amb[0][1], -1.0, 1e-12, "iauPvmpv", "21", status); + vvd(amb[0][2], -1.0, 1e-12, "iauPvmpv", "31", status); + + vvd(amb[1][0], 2.0, 1e-12, "iauPvmpv", "12", status); + vvd(amb[1][1], 4.0, 1e-12, "iauPvmpv", "22", status); + vvd(amb[1][2], 2.0, 1e-12, "iauPvmpv", "32", status); + +} + +static void t_pvppv(int *status) +/* +** - - - - - - - - +** t _ p v p p v +** - - - - - - - - +** +** Test iauPvppv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvppv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[2][3], b[2][3], apb[2][3]; + + + a[0][0] = 2.0; + a[0][1] = 2.0; + a[0][2] = 3.0; + + a[1][0] = 5.0; + a[1][1] = 6.0; + a[1][2] = 3.0; + + b[0][0] = 1.0; + b[0][1] = 3.0; + b[0][2] = 4.0; + + b[1][0] = 3.0; + b[1][1] = 2.0; + b[1][2] = 1.0; + + iauPvppv(a, b, apb); + + vvd(apb[0][0], 3.0, 1e-12, "iauPvppv", "p1", status); + vvd(apb[0][1], 5.0, 1e-12, "iauPvppv", "p2", status); + vvd(apb[0][2], 7.0, 1e-12, "iauPvppv", "p3", status); + + vvd(apb[1][0], 8.0, 1e-12, "iauPvppv", "v1", status); + vvd(apb[1][1], 8.0, 1e-12, "iauPvppv", "v2", status); + vvd(apb[1][2], 4.0, 1e-12, "iauPvppv", "v3", status); + +} + +static void t_pvstar(int *status) +/* +** - - - - - - - - - +** t _ p v s t a r +** - - - - - - - - - +** +** Test iauPvstar function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvstar, vvd, viv +** +** This revision: 2017 March 15 +*/ +{ + double pv[2][3], ra, dec, pmr, pmd, px, rv; + int j; + + + pv[0][0] = 126668.5912743160601; + pv[0][1] = 2136.792716839935195; + pv[0][2] = -245251.2339876830091; + + pv[1][0] = -0.4051854035740712739e-2; + pv[1][1] = -0.6253919754866173866e-2; + pv[1][2] = 0.1189353719774107189e-1; + + j = iauPvstar(pv, &ra, &dec, &pmr, &pmd, &px, &rv); + + vvd(ra, 0.1686756e-1, 1e-12, "iauPvstar", "ra", status); + vvd(dec, -1.093989828, 1e-12, "iauPvstar", "dec", status); + vvd(pmr, -0.1783235160000472788e-4, 1e-16, "iauPvstar", "pmr", status); + vvd(pmd, 0.2336024047000619347e-5, 1e-16, "iauPvstar", "pmd", status); + vvd(px, 0.74723, 1e-12, "iauPvstar", "px", status); + vvd(rv, -21.60000010107306010, 1e-11, "iauPvstar", "rv", status); + + viv(j, 0, "iauPvstar", "j", status); + +} + +static void t_pvtob(int *status) +/* +** - - - - - - - - +** t _ p v t o b +** - - - - - - - - +** +** Test iauPvtob function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvtob, vvd +** +** This revision: 2013 October 2 +*/ +{ + double elong, phi, hm, xp, yp, sp, theta, pv[2][3]; + + + elong = 2.0; + phi = 0.5; + hm = 3000.0; + xp = 1e-6; + yp = -0.5e-6; + sp = 1e-8; + theta = 5.0; + + iauPvtob(elong, phi, hm, xp, yp, sp, theta, pv); + + vvd(pv[0][0], 4225081.367071159207, 1e-5, + "iauPvtob", "p(1)", status); + vvd(pv[0][1], 3681943.215856198144, 1e-5, + "iauPvtob", "p(2)", status); + vvd(pv[0][2], 3041149.399241260785, 1e-5, + "iauPvtob", "p(3)", status); + vvd(pv[1][0], -268.4915389365998787, 1e-9, + "iauPvtob", "v(1)", status); + vvd(pv[1][1], 308.0977983288903123, 1e-9, + "iauPvtob", "v(2)", status); + vvd(pv[1][2], 0, 0, + "iauPvtob", "v(3)", status); + +} + +static void t_pvu(int *status) +/* +** - - - - - - +** t _ p v u +** - - - - - - +** +** Test iauPvu function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvu, vvd +** +** This revision: 2021 January 5 +*/ +{ + double pv[2][3], upv[2][3]; + + + pv[0][0] = 126668.5912743160734; + pv[0][1] = 2136.792716839935565; + pv[0][2] = -245251.2339876830229; + + pv[1][0] = -0.4051854035740713039e-2; + pv[1][1] = -0.6253919754866175788e-2; + pv[1][2] = 0.1189353719774107615e-1; + + iauPvu(2920.0, pv, upv); + + vvd(upv[0][0], 126656.7598605317105, 1e-6, + "iauPvu", "p1", status); + vvd(upv[0][1], 2118.531271155726332, 1e-8, + "iauPvu", "p2", status); + vvd(upv[0][2], -245216.5048590656190, 1e-6, + "iauPvu", "p3", status); + + vvd(upv[1][0], -0.4051854035740713039e-2, 1e-12, + "iauPvu", "v1", status); + vvd(upv[1][1], -0.6253919754866175788e-2, 1e-12, + "iauPvu", "v2", status); + vvd(upv[1][2], 0.1189353719774107615e-1, 1e-12, + "iauPvu", "v3", status); + +} + +static void t_pvup(int *status) +/* +** - - - - - - - +** t _ p v u p +** - - - - - - - +** +** Test iauPvup function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvup, vvd +** +** This revision: 2021 January 5 +*/ +{ + double pv[2][3], p[3]; + + + pv[0][0] = 126668.5912743160734; + pv[0][1] = 2136.792716839935565; + pv[0][2] = -245251.2339876830229; + + pv[1][0] = -0.4051854035740713039e-2; + pv[1][1] = -0.6253919754866175788e-2; + pv[1][2] = 0.1189353719774107615e-1; + + iauPvup(2920.0, pv, p); + + vvd(p[0], 126656.7598605317105, 1e-6, "iauPvup", "1", status); + vvd(p[1], 2118.531271155726332, 1e-8, "iauPvup", "2", status); + vvd(p[2], -245216.5048590656190, 1e-6, "iauPvup", "3", status); + +} + +static void t_pvxpv(int *status) +/* +** - - - - - - - - +** t _ p v x p v +** - - - - - - - - +** +** Test iauPvxpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPvxpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[2][3], b[2][3], axb[2][3]; + + + a[0][0] = 2.0; + a[0][1] = 2.0; + a[0][2] = 3.0; + + a[1][0] = 6.0; + a[1][1] = 0.0; + a[1][2] = 4.0; + + b[0][0] = 1.0; + b[0][1] = 3.0; + b[0][2] = 4.0; + + b[1][0] = 0.0; + b[1][1] = 2.0; + b[1][2] = 8.0; + + iauPvxpv(a, b, axb); + + vvd(axb[0][0], -1.0, 1e-12, "iauPvxpv", "p1", status); + vvd(axb[0][1], -5.0, 1e-12, "iauPvxpv", "p2", status); + vvd(axb[0][2], 4.0, 1e-12, "iauPvxpv", "p3", status); + + vvd(axb[1][0], -2.0, 1e-12, "iauPvxpv", "v1", status); + vvd(axb[1][1], -36.0, 1e-12, "iauPvxpv", "v2", status); + vvd(axb[1][2], 22.0, 1e-12, "iauPvxpv", "v3", status); + +} + +static void t_pxp(int *status) +/* +** - - - - - - +** t _ p x p +** - - - - - - +** +** Test iauPxp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauPxp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3], b[3], axb[3]; + + + a[0] = 2.0; + a[1] = 2.0; + a[2] = 3.0; + + b[0] = 1.0; + b[1] = 3.0; + b[2] = 4.0; + + iauPxp(a, b, axb); + + vvd(axb[0], -1.0, 1e-12, "iauPxp", "1", status); + vvd(axb[1], -5.0, 1e-12, "iauPxp", "2", status); + vvd(axb[2], 4.0, 1e-12, "iauPxp", "3", status); + +} + +static void t_refco(int *status) +/* +** - - - - - - - - +** t _ r e f c o +** - - - - - - - - +** +** Test iauRefco function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRefco, vvd +** +** This revision: 2013 October 2 +*/ +{ + double phpa, tc, rh, wl, refa, refb; + + + phpa = 800.0; + tc = 10.0; + rh = 0.9; + wl = 0.4; + + iauRefco(phpa, tc, rh, wl, &refa, &refb); + + vvd(refa, 0.2264949956241415009e-3, 1e-15, + "iauRefco", "refa", status); + vvd(refb, -0.2598658261729343970e-6, 1e-18, + "iauRefco", "refb", status); + +} + +static void t_rm2v(int *status) +/* +** - - - - - - - +** t _ r m 2 v +** - - - - - - - +** +** Test iauRm2v function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRm2v, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3], w[3]; + + + r[0][0] = 0.00; + r[0][1] = -0.80; + r[0][2] = -0.60; + + r[1][0] = 0.80; + r[1][1] = -0.36; + r[1][2] = 0.48; + + r[2][0] = 0.60; + r[2][1] = 0.48; + r[2][2] = -0.64; + + iauRm2v(r, w); + + vvd(w[0], 0.0, 1e-12, "iauRm2v", "1", status); + vvd(w[1], 1.413716694115406957, 1e-12, "iauRm2v", "2", status); + vvd(w[2], -1.884955592153875943, 1e-12, "iauRm2v", "3", status); + +} + +static void t_rv2m(int *status) +/* +** - - - - - - - +** t _ r v 2 m +** - - - - - - - +** +** Test iauRv2m function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRv2m, vvd +** +** This revision: 2013 August 7 +*/ +{ + double w[3], r[3][3]; + + + w[0] = 0.0; + w[1] = 1.41371669; + w[2] = -1.88495559; + + iauRv2m(w, r); + + vvd(r[0][0], -0.7071067782221119905, 1e-14, "iauRv2m", "11", status); + vvd(r[0][1], -0.5656854276809129651, 1e-14, "iauRv2m", "12", status); + vvd(r[0][2], -0.4242640700104211225, 1e-14, "iauRv2m", "13", status); + + vvd(r[1][0], 0.5656854276809129651, 1e-14, "iauRv2m", "21", status); + vvd(r[1][1], -0.0925483394532274246, 1e-14, "iauRv2m", "22", status); + vvd(r[1][2], -0.8194112531408833269, 1e-14, "iauRv2m", "23", status); + + vvd(r[2][0], 0.4242640700104211225, 1e-14, "iauRv2m", "31", status); + vvd(r[2][1], -0.8194112531408833269, 1e-14, "iauRv2m", "32", status); + vvd(r[2][2], 0.3854415612311154341, 1e-14, "iauRv2m", "33", status); + +} + +static void t_rx(int *status) +/* +** - - - - - +** t _ r x +** - - - - - +** +** Test iauRx function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRx, vvd +** +** This revision: 2013 August 7 +*/ +{ + double phi, r[3][3]; + + + phi = 0.3456789; + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + iauRx(phi, r); + + vvd(r[0][0], 2.0, 0.0, "iauRx", "11", status); + vvd(r[0][1], 3.0, 0.0, "iauRx", "12", status); + vvd(r[0][2], 2.0, 0.0, "iauRx", "13", status); + + vvd(r[1][0], 3.839043388235612460, 1e-12, "iauRx", "21", status); + vvd(r[1][1], 3.237033249594111899, 1e-12, "iauRx", "22", status); + vvd(r[1][2], 4.516714379005982719, 1e-12, "iauRx", "23", status); + + vvd(r[2][0], 1.806030415924501684, 1e-12, "iauRx", "31", status); + vvd(r[2][1], 3.085711545336372503, 1e-12, "iauRx", "32", status); + vvd(r[2][2], 3.687721683977873065, 1e-12, "iauRx", "33", status); + +} + +static void t_rxp(int *status) +/* +** - - - - - - +** t _ r x p +** - - - - - - +** +** Test iauRxp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRxp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3], p[3], rp[3]; + + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + p[0] = 0.2; + p[1] = 1.5; + p[2] = 0.1; + + iauRxp(r, p, rp); + + vvd(rp[0], 5.1, 1e-12, "iauRxp", "1", status); + vvd(rp[1], 3.9, 1e-12, "iauRxp", "2", status); + vvd(rp[2], 7.1, 1e-12, "iauRxp", "3", status); + +} + +static void t_rxpv(int *status) +/* +** - - - - - - - +** t _ r x p v +** - - - - - - - +** +** Test iauRxpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRxpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3], pv[2][3], rpv[2][3]; + + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + pv[0][0] = 0.2; + pv[0][1] = 1.5; + pv[0][2] = 0.1; + + pv[1][0] = 1.5; + pv[1][1] = 0.2; + pv[1][2] = 0.1; + + iauRxpv(r, pv, rpv); + + vvd(rpv[0][0], 5.1, 1e-12, "iauRxpv", "11", status); + vvd(rpv[1][0], 3.8, 1e-12, "iauRxpv", "12", status); + + vvd(rpv[0][1], 3.9, 1e-12, "iauRxpv", "21", status); + vvd(rpv[1][1], 5.2, 1e-12, "iauRxpv", "22", status); + + vvd(rpv[0][2], 7.1, 1e-12, "iauRxpv", "31", status); + vvd(rpv[1][2], 5.8, 1e-12, "iauRxpv", "32", status); + +} + +static void t_rxr(int *status) +/* +** - - - - - - +** t _ r x r +** - - - - - - +** +** Test iauRxr function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRxr, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3][3], b[3][3], atb[3][3]; + + + a[0][0] = 2.0; + a[0][1] = 3.0; + a[0][2] = 2.0; + + a[1][0] = 3.0; + a[1][1] = 2.0; + a[1][2] = 3.0; + + a[2][0] = 3.0; + a[2][1] = 4.0; + a[2][2] = 5.0; + + b[0][0] = 1.0; + b[0][1] = 2.0; + b[0][2] = 2.0; + + b[1][0] = 4.0; + b[1][1] = 1.0; + b[1][2] = 1.0; + + b[2][0] = 3.0; + b[2][1] = 0.0; + b[2][2] = 1.0; + + iauRxr(a, b, atb); + + vvd(atb[0][0], 20.0, 1e-12, "iauRxr", "11", status); + vvd(atb[0][1], 7.0, 1e-12, "iauRxr", "12", status); + vvd(atb[0][2], 9.0, 1e-12, "iauRxr", "13", status); + + vvd(atb[1][0], 20.0, 1e-12, "iauRxr", "21", status); + vvd(atb[1][1], 8.0, 1e-12, "iauRxr", "22", status); + vvd(atb[1][2], 11.0, 1e-12, "iauRxr", "23", status); + + vvd(atb[2][0], 34.0, 1e-12, "iauRxr", "31", status); + vvd(atb[2][1], 10.0, 1e-12, "iauRxr", "32", status); + vvd(atb[2][2], 15.0, 1e-12, "iauRxr", "33", status); + +} + +static void t_ry(int *status) +/* +** - - - - - +** t _ r y +** - - - - - +** +** Test iauRy function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRy, vvd +** +** This revision: 2013 August 7 +*/ +{ + double theta, r[3][3]; + + + theta = 0.3456789; + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + iauRy(theta, r); + + vvd(r[0][0], 0.8651847818978159930, 1e-12, "iauRy", "11", status); + vvd(r[0][1], 1.467194920539316554, 1e-12, "iauRy", "12", status); + vvd(r[0][2], 0.1875137911274457342, 1e-12, "iauRy", "13", status); + + vvd(r[1][0], 3, 1e-12, "iauRy", "21", status); + vvd(r[1][1], 2, 1e-12, "iauRy", "22", status); + vvd(r[1][2], 3, 1e-12, "iauRy", "23", status); + + vvd(r[2][0], 3.500207892850427330, 1e-12, "iauRy", "31", status); + vvd(r[2][1], 4.779889022262298150, 1e-12, "iauRy", "32", status); + vvd(r[2][2], 5.381899160903798712, 1e-12, "iauRy", "33", status); + +} + +static void t_rz(int *status) +/* +** - - - - - +** t _ r z +** - - - - - +** +** Test iauRz function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauRz, vvd +** +** This revision: 2013 August 7 +*/ +{ + double psi, r[3][3]; + + + psi = 0.3456789; + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + iauRz(psi, r); + + vvd(r[0][0], 2.898197754208926769, 1e-12, "iauRz", "11", status); + vvd(r[0][1], 3.500207892850427330, 1e-12, "iauRz", "12", status); + vvd(r[0][2], 2.898197754208926769, 1e-12, "iauRz", "13", status); + + vvd(r[1][0], 2.144865911309686813, 1e-12, "iauRz", "21", status); + vvd(r[1][1], 0.865184781897815993, 1e-12, "iauRz", "22", status); + vvd(r[1][2], 2.144865911309686813, 1e-12, "iauRz", "23", status); + + vvd(r[2][0], 3.0, 1e-12, "iauRz", "31", status); + vvd(r[2][1], 4.0, 1e-12, "iauRz", "32", status); + vvd(r[2][2], 5.0, 1e-12, "iauRz", "33", status); + +} + +static void t_s00a(int *status) +/* +** - - - - - - - +** t _ s 0 0 a +** - - - - - - - +** +** Test iauS00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double s; + + + s = iauS00a(2400000.5, 52541.0); + + vvd(s, -0.1340684448919163584e-7, 1e-18, "iauS00a", "", status); + +} + +static void t_s00b(int *status) +/* +** - - - - - - - +** t _ s 0 0 b +** - - - - - - - +** +** Test iauS00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double s; + + + s = iauS00b(2400000.5, 52541.0); + + vvd(s, -0.1340695782951026584e-7, 1e-18, "iauS00b", "", status); + +} + +static void t_s00(int *status) +/* +** - - - - - - +** t _ s 0 0 +** - - - - - - +** +** Test iauS00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS00, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y, s; + + + x = 0.5791308486706011000e-3; + y = 0.4020579816732961219e-4; + + s = iauS00(2400000.5, 53736.0, x, y); + + vvd(s, -0.1220036263270905693e-7, 1e-18, "iauS00", "", status); + +} + +static void t_s06a(int *status) +/* +** - - - - - - - +** t _ s 0 6 a +** - - - - - - - +** +** Test iauS06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double s; + + + s = iauS06a(2400000.5, 52541.0); + + vvd(s, -0.1340680437291812383e-7, 1e-18, "iauS06a", "", status); + +} + +static void t_s06(int *status) +/* +** - - - - - - +** t _ s 0 6 +** - - - - - - +** +** Test iauS06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y, s; + + + x = 0.5791308486706011000e-3; + y = 0.4020579816732961219e-4; + + s = iauS06(2400000.5, 53736.0, x, y); + + vvd(s, -0.1220032213076463117e-7, 1e-18, "iauS06", "", status); + +} + +static void t_s2c(int *status) +/* +** - - - - - - +** t _ s 2 c +** - - - - - - +** +** Test iauS2c function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS2c, vvd +** +** This revision: 2013 August 7 +*/ +{ + double c[3]; + + + iauS2c(3.0123, -0.999, c); + + vvd(c[0], -0.5366267667260523906, 1e-12, "iauS2c", "1", status); + vvd(c[1], 0.0697711109765145365, 1e-12, "iauS2c", "2", status); + vvd(c[2], -0.8409302618566214041, 1e-12, "iauS2c", "3", status); + +} + +static void t_s2p(int *status) +/* +** - - - - - - +** t _ s 2 p +** - - - - - - +** +** Test iauS2p function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS2p, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3]; + + + iauS2p(-3.21, 0.123, 0.456, p); + + vvd(p[0], -0.4514964673880165228, 1e-12, "iauS2p", "x", status); + vvd(p[1], 0.0309339427734258688, 1e-12, "iauS2p", "y", status); + vvd(p[2], 0.0559466810510877933, 1e-12, "iauS2p", "z", status); + +} + +static void t_s2pv(int *status) +/* +** - - - - - - - +** t _ s 2 p v +** - - - - - - - +** +** Test iauS2pv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS2pv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double pv[2][3]; + + + iauS2pv(-3.21, 0.123, 0.456, -7.8e-6, 9.01e-6, -1.23e-5, pv); + + vvd(pv[0][0], -0.4514964673880165228, 1e-12, "iauS2pv", "x", status); + vvd(pv[0][1], 0.0309339427734258688, 1e-12, "iauS2pv", "y", status); + vvd(pv[0][2], 0.0559466810510877933, 1e-12, "iauS2pv", "z", status); + + vvd(pv[1][0], 0.1292270850663260170e-4, 1e-16, + "iauS2pv", "vx", status); + vvd(pv[1][1], 0.2652814182060691422e-5, 1e-16, + "iauS2pv", "vy", status); + vvd(pv[1][2], 0.2568431853930292259e-5, 1e-16, + "iauS2pv", "vz", status); + +} + +static void t_s2xpv(int *status) +/* +** - - - - - - - - +** t _ s 2 x p v +** - - - - - - - - +** +** Test iauS2xpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauS2xpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double s1, s2, pv[2][3], spv[2][3]; + + + s1 = 2.0; + s2 = 3.0; + + pv[0][0] = 0.3; + pv[0][1] = 1.2; + pv[0][2] = -2.5; + + pv[1][0] = 0.5; + pv[1][1] = 2.3; + pv[1][2] = -0.4; + + iauS2xpv(s1, s2, pv, spv); + + vvd(spv[0][0], 0.6, 1e-12, "iauS2xpv", "p1", status); + vvd(spv[0][1], 2.4, 1e-12, "iauS2xpv", "p2", status); + vvd(spv[0][2], -5.0, 1e-12, "iauS2xpv", "p3", status); + + vvd(spv[1][0], 1.5, 1e-12, "iauS2xpv", "v1", status); + vvd(spv[1][1], 6.9, 1e-12, "iauS2xpv", "v2", status); + vvd(spv[1][2], -1.2, 1e-12, "iauS2xpv", "v3", status); + +} + +static void t_sepp(int *status) +/* +** - - - - - - - +** t _ s e p p +** - - - - - - - +** +** Test iauSepp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauSepp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double a[3], b[3], s; + + + a[0] = 1.0; + a[1] = 0.1; + a[2] = 0.2; + + b[0] = -3.0; + b[1] = 1e-3; + b[2] = 0.2; + + s = iauSepp(a, b); + + vvd(s, 2.860391919024660768, 1e-12, "iauSepp", "", status); + +} + +static void t_seps(int *status) +/* +** - - - - - - - +** t _ s e p s +** - - - - - - - +** +** Test iauSeps function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauSeps, vvd +** +** This revision: 2013 August 7 +*/ +{ + double al, ap, bl, bp, s; + + + al = 1.0; + ap = 0.1; + + bl = 0.2; + bp = -3.0; + + s = iauSeps(al, ap, bl, bp); + + vvd(s, 2.346722016996998842, 1e-14, "iauSeps", "", status); + +} + +static void t_sp00(int *status) +/* +** - - - - - - - +** t _ s p 0 0 +** - - - - - - - +** +** Test iauSp00 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauSp00, vvd +** +** This revision: 2013 August 7 +*/ +{ + vvd(iauSp00(2400000.5, 52541.0), + -0.6216698469981019309e-11, 1e-12, "iauSp00", "", status); + +} + +static void t_starpm(int *status) +/* +** - - - - - - - - - +** t _ s t a r p m +** - - - - - - - - - +** +** Test iauStarpm function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauStarpm, vvd, viv +** +** This revision: 2017 March 15 +*/ +{ + double ra1, dec1, pmr1, pmd1, px1, rv1; + double ra2, dec2, pmr2, pmd2, px2, rv2; + int j; + + + ra1 = 0.01686756; + dec1 = -1.093989828; + pmr1 = -1.78323516e-5; + pmd1 = 2.336024047e-6; + px1 = 0.74723; + rv1 = -21.6; + + j = iauStarpm(ra1, dec1, pmr1, pmd1, px1, rv1, + 2400000.5, 50083.0, 2400000.5, 53736.0, + &ra2, &dec2, &pmr2, &pmd2, &px2, &rv2); + + vvd(ra2, 0.01668919069414256149, 1e-13, + "iauStarpm", "ra", status); + vvd(dec2, -1.093966454217127897, 1e-13, + "iauStarpm", "dec", status); + vvd(pmr2, -0.1783662682153176524e-4, 1e-17, + "iauStarpm", "pmr", status); + vvd(pmd2, 0.2338092915983989595e-5, 1e-17, + "iauStarpm", "pmd", status); + vvd(px2, 0.7473533835317719243, 1e-13, + "iauStarpm", "px", status); + vvd(rv2, -21.59905170476417175, 1e-11, + "iauStarpm", "rv", status); + + viv(j, 0, "iauStarpm", "j", status); + +} + +static void t_starpv(int *status) +/* +** - - - - - - - - - +** t _ s t a r p v +** - - - - - - - - - +** +** Test iauStarpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauStarpv, vvd, viv +** +** This revision: 2017 March 15 +*/ +{ + double ra, dec, pmr, pmd, px, rv, pv[2][3]; + int j; + + + ra = 0.01686756; + dec = -1.093989828; + pmr = -1.78323516e-5; + pmd = 2.336024047e-6; + px = 0.74723; + rv = -21.6; + + j = iauStarpv(ra, dec, pmr, pmd, px, rv, pv); + + vvd(pv[0][0], 126668.5912743160601, 1e-10, + "iauStarpv", "11", status); + vvd(pv[0][1], 2136.792716839935195, 1e-12, + "iauStarpv", "12", status); + vvd(pv[0][2], -245251.2339876830091, 1e-10, + "iauStarpv", "13", status); + + vvd(pv[1][0], -0.4051854008955659551e-2, 1e-13, + "iauStarpv", "21", status); + vvd(pv[1][1], -0.6253919754414777970e-2, 1e-15, + "iauStarpv", "22", status); + vvd(pv[1][2], 0.1189353714588109341e-1, 1e-13, + "iauStarpv", "23", status); + + viv(j, 0, "iauStarpv", "j", status); + +} + +static void t_sxp(int *status) +/* +** - - - - - - +** t _ s x p +** - - - - - - +** +** Test iauSxp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauSxp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double s, p[3], sp[3]; + + + s = 2.0; + + p[0] = 0.3; + p[1] = 1.2; + p[2] = -2.5; + + iauSxp(s, p, sp); + + vvd(sp[0], 0.6, 0.0, "iauSxp", "1", status); + vvd(sp[1], 2.4, 0.0, "iauSxp", "2", status); + vvd(sp[2], -5.0, 0.0, "iauSxp", "3", status); + +} + + +static void t_sxpv(int *status) +/* +** - - - - - - - +** t _ s x p v +** - - - - - - - +** +** Test iauSxpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauSxpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double s, pv[2][3], spv[2][3]; + + + s = 2.0; + + pv[0][0] = 0.3; + pv[0][1] = 1.2; + pv[0][2] = -2.5; + + pv[1][0] = 0.5; + pv[1][1] = 3.2; + pv[1][2] = -0.7; + + iauSxpv(s, pv, spv); + + vvd(spv[0][0], 0.6, 0.0, "iauSxpv", "p1", status); + vvd(spv[0][1], 2.4, 0.0, "iauSxpv", "p2", status); + vvd(spv[0][2], -5.0, 0.0, "iauSxpv", "p3", status); + + vvd(spv[1][0], 1.0, 0.0, "iauSxpv", "v1", status); + vvd(spv[1][1], 6.4, 0.0, "iauSxpv", "v2", status); + vvd(spv[1][2], -1.4, 0.0, "iauSxpv", "v3", status); + +} + +static void t_taitt(int *status) +/* +** - - - - - - - - +** t _ t a i t t +** - - - - - - - - +** +** Test iauTaitt function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTaitt, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double t1, t2; + int j; + + + j = iauTaitt(2453750.5, 0.892482639, &t1, &t2); + + vvd(t1, 2453750.5, 1e-6, "iauTaitt", "t1", status); + vvd(t2, 0.892855139, 1e-12, "iauTaitt", "t2", status); + viv(j, 0, "iauTaitt", "j", status); + +} + +static void t_taiut1(int *status) +/* +** - - - - - - - - - +** t _ t a i u t 1 +** - - - - - - - - - +** +** Test iauTaiut1 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTaiut1, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double u1, u2; + int j; + + + j = iauTaiut1(2453750.5, 0.892482639, -32.6659, &u1, &u2); + + vvd(u1, 2453750.5, 1e-6, "iauTaiut1", "u1", status); + vvd(u2, 0.8921045614537037037, 1e-12, "iauTaiut1", "u2", status); + viv(j, 0, "iauTaiut1", "j", status); + +} + +static void t_taiutc(int *status) +/* +** - - - - - - - - - +** t _ t a i u t c +** - - - - - - - - - +** +** Test iauTaiutc function. +** +** Returned: +** status LOGICAL TRUE = success, FALSE = fail +** +** Called: iauTaiutc, vvd, viv +** +** This revision: 2013 October 3 +*/ +{ + double u1, u2; + int j; + + + j = iauTaiutc(2453750.5, 0.892482639, &u1, &u2); + + vvd(u1, 2453750.5, 1e-6, "iauTaiutc", "u1", status); + vvd(u2, 0.8921006945555555556, 1e-12, "iauTaiutc", "u2", status); + viv(j, 0, "iauTaiutc", "j", status); + +} + +static void t_tcbtdb(int *status) +/* +** - - - - - - - - - +** t _ t c b t d b +** - - - - - - - - - +** +** Test iauTcbtdb function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTcbtdb, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double b1, b2; + int j; + + + j = iauTcbtdb(2453750.5, 0.893019599, &b1, &b2); + + vvd(b1, 2453750.5, 1e-6, "iauTcbtdb", "b1", status); + vvd(b2, 0.8928551362746343397, 1e-12, "iauTcbtdb", "b2", status); + viv(j, 0, "iauTcbtdb", "j", status); + +} + +static void t_tcgtt(int *status) +/* +** - - - - - - - - +** t _ t c g t t +** - - - - - - - - +** +** Test iauTcgtt function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTcgtt, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double t1, t2; + int j; + + + j = iauTcgtt(2453750.5, 0.892862531, &t1, &t2); + + vvd(t1, 2453750.5, 1e-6, "iauTcgtt", "t1", status); + vvd(t2, 0.8928551387488816828, 1e-12, "iauTcgtt", "t2", status); + viv(j, 0, "iauTcgtt", "j", status); + +} + +static void t_tdbtcb(int *status) +/* +** - - - - - - - - - +** t _ t d b t c b +** - - - - - - - - - +** +** Test iauTdbtcb function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTdbtcb, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double b1, b2; + int j; + + + j = iauTdbtcb(2453750.5, 0.892855137, &b1, &b2); + + vvd( b1, 2453750.5, 1e-6, "iauTdbtcb", "b1", status); + vvd( b2, 0.8930195997253656716, 1e-12, "iauTdbtcb", "b2", status); + viv(j, 0, "iauTdbtcb", "j", status); + +} + +static void t_tdbtt(int *status) +/* +** - - - - - - - - +** t _ t d b t t +** - - - - - - - - +** +** Test iauTdbtt function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTdbtt, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double t1, t2; + int j; + + + j = iauTdbtt(2453750.5, 0.892855137, -0.000201, &t1, &t2); + + vvd(t1, 2453750.5, 1e-6, "iauTdbtt", "t1", status); + vvd(t2, 0.8928551393263888889, 1e-12, "iauTdbtt", "t2", status); + viv(j, 0, "iauTdbtt", "j", status); + +} + +static void t_tf2a(int *status) +/* +** - - - - - - - +** t _ t f 2 a +** - - - - - - - +** +** Test iauTf2a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTf2a, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double a; + int j; + + + j = iauTf2a('+', 4, 58, 20.2, &a); + + vvd(a, 1.301739278189537429, 1e-12, "iauTf2a", "a", status); + viv(j, 0, "iauTf2a", "j", status); + +} + +static void t_tf2d(int *status) +/* +** - - - - - - - +** t _ t f 2 d +** - - - - - - - +** +** Test iauTf2d function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTf2d, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double d; + int j; + + + j = iauTf2d(' ', 23, 55, 10.9, &d); + + vvd(d, 0.9966539351851851852, 1e-12, "iauTf2d", "d", status); + viv(j, 0, "iauTf2d", "j", status); + +} + +static void t_tpors(int *status) +/* +** - - - - - - - - +** t _ t p o r s +** - - - - - - - - +** +** Test iauTpors function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTpors, vvd, viv +** +** This revision: 2017 October 21 +*/ +{ + double xi, eta, ra, dec, az1, bz1, az2, bz2; + int n; + + + xi = -0.03; + eta = 0.07; + ra = 1.3; + dec = 1.5; + + n = iauTpors(xi, eta, ra, dec, &az1, &bz1, &az2, &bz2); + + vvd(az1, 1.736621577783208748, 1e-13, "iauTpors", "az1", status); + vvd(bz1, 1.436736561844090323, 1e-13, "iauTpors", "bz1", status); + + vvd(az2, 4.004971075806584490, 1e-13, "iauTpors", "az2", status); + vvd(bz2, 1.565084088476417917, 1e-13, "iauTpors", "bz2", status); + + viv(n, 2, "iauTpors", "n", status); + +} + +static void t_tporv(int *status) +/* +** - - - - - - - - +** t _ t p o r v +** - - - - - - - - +** +** Test iauTporv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTporv, iauS2c, vvd, viv +** +** This revision: 2017 October 21 +*/ +{ + double xi, eta, ra, dec, v[3], vz1[3], vz2[3]; + int n; + + + xi = -0.03; + eta = 0.07; + ra = 1.3; + dec = 1.5; + iauS2c(ra, dec, v); + + n = iauTporv(xi, eta, v, vz1, vz2); + + vvd(vz1[0], -0.02206252822366888610, 1e-15, + "iauTporv", "x1", status); + vvd(vz1[1], 0.1318251060359645016, 1e-14, + "iauTporv", "y1", status); + vvd(vz1[2], 0.9910274397144543895, 1e-14, + "iauTporv", "z1", status); + + vvd(vz2[0], -0.003712211763801968173, 1e-16, + "iauTporv", "x2", status); + vvd(vz2[1], -0.004341519956299836813, 1e-16, + "iauTporv", "y2", status); + vvd(vz2[2], 0.9999836852110587012, 1e-14, + "iauTporv", "z2", status); + + viv(n, 2, "iauTporv", "n", status); + +} + +static void t_tpsts(int *status) +/* +** - - - - - - - - +** t _ t p s t s +** - - - - - - - - +** +** Test iauTpsts function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTpsts, vvd +** +** This revision: 2017 October 21 +*/ +{ + double xi, eta, raz, decz, ra, dec; + + + xi = -0.03; + eta = 0.07; + raz = 2.3; + decz = 1.5; + + iauTpsts(xi, eta, raz, decz, &ra, &dec); + + vvd(ra, 0.7596127167359629775, 1e-14, "iauTpsts", "ra", status); + vvd(dec, 1.540864645109263028, 1e-13, "iauTpsts", "dec", status); + +} + +static void t_tpstv(int *status) +/* +** - - - - - - - - +** t _ t p s t v +** - - - - - - - - +** +** Test iauTpstv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTpstv, iauS2c, vvd +** +** This revision: 2017 October 21 +*/ +{ + double xi, eta, raz, decz, vz[3], v[3]; + + + xi = -0.03; + eta = 0.07; + raz = 2.3; + decz = 1.5; + iauS2c(raz, decz, vz); + + iauTpstv(xi, eta, vz, v); + + vvd(v[0], 0.02170030454907376677, 1e-15, "iauTpstv", "x", status); + vvd(v[1], 0.02060909590535367447, 1e-15, "iauTpstv", "y", status); + vvd(v[2], 0.9995520806583523804, 1e-14, "iauTpstv", "z", status); + +} + +static void t_tpxes(int *status) +/* +** - - - - - - - - +** t _ t p x e s +** - - - - - - - - +** +** Test iauTpxes function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTpxes, vvd, viv +** +** This revision: 2017 October 21 +*/ +{ + double ra, dec, raz, decz, xi, eta; + int j; + + + ra = 1.3; + dec = 1.55; + raz = 2.3; + decz = 1.5; + + j = iauTpxes(ra, dec, raz, decz, &xi, &eta); + + vvd(xi, -0.01753200983236980595, 1e-15, "iauTpxes", "xi", status); + vvd(eta, 0.05962940005778712891, 1e-15, "iauTpxes", "eta", status); + + viv(j, 0, "iauTpxes", "j", status); + +} + +static void t_tpxev(int *status) +/* +** - - - - - - - - +** t _ t p x e v +** - - - - - - - - +** +** Test iauTpxev function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTpxev, iauS2c, vvd +** +** This revision: 2017 October 21 +*/ +{ + double ra, dec, raz, decz, v[3], vz[3], xi, eta; + int j; + + + ra = 1.3; + dec = 1.55; + raz = 2.3; + decz = 1.5; + iauS2c(ra, dec, v); + iauS2c(raz, decz, vz); + + j = iauTpxev(v, vz, &xi, &eta); + + vvd(xi, -0.01753200983236980595, 1e-15, "iauTpxev", "xi", status); + vvd(eta, 0.05962940005778712891, 1e-15, "iauTpxev", "eta", status); + + viv(j, 0, "iauTpxev", "j", status); + +} + +static void t_tr(int *status) +/* +** - - - - - +** t _ t r +** - - - - - +** +** Test iauTr function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTr, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3], rt[3][3]; + + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + iauTr(r, rt); + + vvd(rt[0][0], 2.0, 0.0, "iauTr", "11", status); + vvd(rt[0][1], 3.0, 0.0, "iauTr", "12", status); + vvd(rt[0][2], 3.0, 0.0, "iauTr", "13", status); + + vvd(rt[1][0], 3.0, 0.0, "iauTr", "21", status); + vvd(rt[1][1], 2.0, 0.0, "iauTr", "22", status); + vvd(rt[1][2], 4.0, 0.0, "iauTr", "23", status); + + vvd(rt[2][0], 2.0, 0.0, "iauTr", "31", status); + vvd(rt[2][1], 3.0, 0.0, "iauTr", "32", status); + vvd(rt[2][2], 5.0, 0.0, "iauTr", "33", status); + +} + +static void t_trxp(int *status) +/* +** - - - - - - - +** t _ t r x p +** - - - - - - - +** +** Test iauTrxp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTrxp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3], p[3], trp[3]; + + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + p[0] = 0.2; + p[1] = 1.5; + p[2] = 0.1; + + iauTrxp(r, p, trp); + + vvd(trp[0], 5.2, 1e-12, "iauTrxp", "1", status); + vvd(trp[1], 4.0, 1e-12, "iauTrxp", "2", status); + vvd(trp[2], 5.4, 1e-12, "iauTrxp", "3", status); + +} + +static void t_trxpv(int *status) +/* +** - - - - - - - - +** t _ t r x p v +** - - - - - - - - +** +** Test iauTrxpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTrxpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3], pv[2][3], trpv[2][3]; + + + r[0][0] = 2.0; + r[0][1] = 3.0; + r[0][2] = 2.0; + + r[1][0] = 3.0; + r[1][1] = 2.0; + r[1][2] = 3.0; + + r[2][0] = 3.0; + r[2][1] = 4.0; + r[2][2] = 5.0; + + pv[0][0] = 0.2; + pv[0][1] = 1.5; + pv[0][2] = 0.1; + + pv[1][0] = 1.5; + pv[1][1] = 0.2; + pv[1][2] = 0.1; + + iauTrxpv(r, pv, trpv); + + vvd(trpv[0][0], 5.2, 1e-12, "iauTrxpv", "p1", status); + vvd(trpv[0][1], 4.0, 1e-12, "iauTrxpv", "p1", status); + vvd(trpv[0][2], 5.4, 1e-12, "iauTrxpv", "p1", status); + + vvd(trpv[1][0], 3.9, 1e-12, "iauTrxpv", "v1", status); + vvd(trpv[1][1], 5.3, 1e-12, "iauTrxpv", "v2", status); + vvd(trpv[1][2], 4.1, 1e-12, "iauTrxpv", "v3", status); + +} + +static void t_tttai(int *status) +/* +** - - - - - - - - +** t _ t t t a i +** - - - - - - - - +** +** Test iauTttai function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTttai, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double a1, a2; + int j; + + + j = iauTttai(2453750.5, 0.892482639, &a1, &a2); + + vvd(a1, 2453750.5, 1e-6, "iauTttai", "a1", status); + vvd(a2, 0.892110139, 1e-12, "iauTttai", "a2", status); + viv(j, 0, "iauTttai", "j", status); + +} + +static void t_tttcg(int *status) +/* +** - - - - - - - - +** t _ t t t c g +** - - - - - - - - +** +** Test iauTttcg function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTttcg, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double g1, g2; + int j; + + + j = iauTttcg(2453750.5, 0.892482639, &g1, &g2); + + vvd( g1, 2453750.5, 1e-6, "iauTttcg", "g1", status); + vvd( g2, 0.8924900312508587113, 1e-12, "iauTttcg", "g2", status); + viv(j, 0, "iauTttcg", "j", status); + +} + +static void t_tttdb(int *status) +/* +** - - - - - - - - +** t _ t t t d b +** - - - - - - - - +** +** Test iauTttdb function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTttdb, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double b1, b2; + int j; + + + j = iauTttdb(2453750.5, 0.892855139, -0.000201, &b1, &b2); + + vvd(b1, 2453750.5, 1e-6, "iauTttdb", "b1", status); + vvd(b2, 0.8928551366736111111, 1e-12, "iauTttdb", "b2", status); + viv(j, 0, "iauTttdb", "j", status); + +} + +static void t_ttut1(int *status) +/* +** - - - - - - - - +** t _ t t u t 1 +** - - - - - - - - +** +** Test iauTtut1 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauTtut1, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double u1, u2; + int j; + + + j = iauTtut1(2453750.5, 0.892855139, 64.8499, &u1, &u2); + + vvd(u1, 2453750.5, 1e-6, "iauTtut1", "u1", status); + vvd(u2, 0.8921045614537037037, 1e-12, "iauTtut1", "u2", status); + viv(j, 0, "iauTtut1", "j", status); + +} + +static void t_ut1tai(int *status) +/* +** - - - - - - - - - +** t _ u t 1 t a i +** - - - - - - - - - +** +** Test iauUt1tai function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauUt1tai, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double a1, a2; + int j; + + + j = iauUt1tai(2453750.5, 0.892104561, -32.6659, &a1, &a2); + + vvd(a1, 2453750.5, 1e-6, "iauUt1tai", "a1", status); + vvd(a2, 0.8924826385462962963, 1e-12, "iauUt1tai", "a2", status); + viv(j, 0, "iauUt1tai", "j", status); + +} + +static void t_ut1tt(int *status) +/* +** - - - - - - - - +** t _ u t 1 t t +** - - - - - - - - +** +** Test iauUt1tt function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauUt1tt, vvd, viv +** +** This revision: 2013 October 3 +*/ +{ + double t1, t2; + int j; + + + j = iauUt1tt(2453750.5, 0.892104561, 64.8499, &t1, &t2); + + vvd(t1, 2453750.5, 1e-6, "iauUt1tt", "t1", status); + vvd(t2, 0.8928551385462962963, 1e-12, "iauUt1tt", "t2", status); + viv(j, 0, "iauUt1tt", "j", status); + +} + +static void t_ut1utc(int *status) +/* +** - - - - - - - - - +** t _ u t 1 u t c +** - - - - - - - - - +** +** Test iauUt1utc function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauUt1utc, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double u1, u2; + int j; + + + j = iauUt1utc(2453750.5, 0.892104561, 0.3341, &u1, &u2); + + vvd(u1, 2453750.5, 1e-6, "iauUt1utc", "u1", status); + vvd(u2, 0.8921006941018518519, 1e-12, "iauUt1utc", "u2", status); + viv(j, 0, "iauUt1utc", "j", status); + +} + +static void t_utctai(int *status) +/* +** - - - - - - - - - +** t _ u t c t a i +** - - - - - - - - - +** +** Test iauUtctai function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauUtctai, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double u1, u2; + int j; + + + j = iauUtctai(2453750.5, 0.892100694, &u1, &u2); + + vvd(u1, 2453750.5, 1e-6, "iauUtctai", "u1", status); + vvd(u2, 0.8924826384444444444, 1e-12, "iauUtctai", "u2", status); + viv(j, 0, "iauUtctai", "j", status); + +} + +static void t_utcut1(int *status) +/* +** - - - - - - - - - +** t _ u t c u t 1 +** - - - - - - - - - +** +** Test iauUtcut1 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauUtcut1, vvd, viv +** +** This revision: 2013 August 7 +*/ +{ + double u1, u2; + int j; + + + j = iauUtcut1(2453750.5, 0.892100694, 0.3341, &u1, &u2); + + vvd(u1, 2453750.5, 1e-6, "iauUtcut1", "u1", status); + vvd(u2, 0.8921045608981481481, 1e-12, "iauUtcut1", "u2", status); + viv(j, 0, "iauUtcut1", "j", status); + +} + +static void t_xy06(int *status) +/* +** - - - - - - - +** t _ x y 0 6 +** - - - - - - - +** +** Test iauXy06 function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauXy06, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y; + + + iauXy06(2400000.5, 53736.0, &x, &y); + + vvd(x, 0.5791308486706010975e-3, 1e-15, "iauXy06", "x", status); + vvd(y, 0.4020579816732958141e-4, 1e-16, "iauXy06", "y", status); + +} + +static void t_xys00a(int *status) +/* +** - - - - - - - - - +** t _ x y s 0 0 a +** - - - - - - - - - +** +** Test iauXys00a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauXys00a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y, s; + + + iauXys00a(2400000.5, 53736.0, &x, &y, &s); + + vvd(x, 0.5791308472168152904e-3, 1e-14, "iauXys00a", "x", status); + vvd(y, 0.4020595661591500259e-4, 1e-15, "iauXys00a", "y", status); + vvd(s, -0.1220040848471549623e-7, 1e-18, "iauXys00a", "s", status); + +} + +static void t_xys00b(int *status) +/* +** - - - - - - - - - +** t _ x y s 0 0 b +** - - - - - - - - - +** +** Test iauXys00b function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauXys00b, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y, s; + + + iauXys00b(2400000.5, 53736.0, &x, &y, &s); + + vvd(x, 0.5791301929950208873e-3, 1e-14, "iauXys00b", "x", status); + vvd(y, 0.4020553681373720832e-4, 1e-15, "iauXys00b", "y", status); + vvd(s, -0.1220027377285083189e-7, 1e-18, "iauXys00b", "s", status); + +} + +static void t_xys06a(int *status) +/* +** - - - - - - - - - +** t _ x y s 0 6 a +** - - - - - - - - - +** +** Test iauXys06a function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauXys06a, vvd +** +** This revision: 2013 August 7 +*/ +{ + double x, y, s; + + + iauXys06a(2400000.5, 53736.0, &x, &y, &s); + + vvd(x, 0.5791308482835292617e-3, 1e-14, "iauXys06a", "x", status); + vvd(y, 0.4020580099454020310e-4, 1e-15, "iauXys06a", "y", status); + vvd(s, -0.1220032294164579896e-7, 1e-18, "iauXys06a", "s", status); + +} + +static void t_zp(int *status) +/* +** - - - - - +** t _ z p +** - - - - - +** +** Test iauZp function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauZp, vvd +** +** This revision: 2013 August 7 +*/ +{ + double p[3]; + + + p[0] = 0.3; + p[1] = 1.2; + p[2] = -2.5; + + iauZp(p); + + vvd(p[0], 0.0, 0.0, "iauZp", "1", status); + vvd(p[1], 0.0, 0.0, "iauZp", "2", status); + vvd(p[2], 0.0, 0.0, "iauZp", "3", status); + +} + +static void t_zpv(int *status) +/* +** - - - - - - +** t _ z p v +** - - - - - - +** +** Test iauZpv function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauZpv, vvd +** +** This revision: 2013 August 7 +*/ +{ + double pv[2][3]; + + + pv[0][0] = 0.3; + pv[0][1] = 1.2; + pv[0][2] = -2.5; + + pv[1][0] = -0.5; + pv[1][1] = 3.1; + pv[1][2] = 0.9; + + iauZpv(pv); + + vvd(pv[0][0], 0.0, 0.0, "iauZpv", "p1", status); + vvd(pv[0][1], 0.0, 0.0, "iauZpv", "p2", status); + vvd(pv[0][2], 0.0, 0.0, "iauZpv", "p3", status); + + vvd(pv[1][0], 0.0, 0.0, "iauZpv", "v1", status); + vvd(pv[1][1], 0.0, 0.0, "iauZpv", "v2", status); + vvd(pv[1][2], 0.0, 0.0, "iauZpv", "v3", status); + +} + +static void t_zr(int *status) +/* +** - - - - - +** t _ z r +** - - - - - +** +** Test iauZr function. +** +** Returned: +** status int FALSE = success, TRUE = fail +** +** Called: iauZr, vvd +** +** This revision: 2013 August 7 +*/ +{ + double r[3][3]; + + + r[0][0] = 2.0; + r[1][0] = 3.0; + r[2][0] = 2.0; + + r[0][1] = 3.0; + r[1][1] = 2.0; + r[2][1] = 3.0; + + r[0][2] = 3.0; + r[1][2] = 4.0; + r[2][2] = 5.0; + + iauZr(r); + + vvd(r[0][0], 0.0, 0.0, "iauZr", "00", status); + vvd(r[1][0], 0.0, 0.0, "iauZr", "01", status); + vvd(r[2][0], 0.0, 0.0, "iauZr", "02", status); + + vvd(r[0][1], 0.0, 0.0, "iauZr", "10", status); + vvd(r[1][1], 0.0, 0.0, "iauZr", "11", status); + vvd(r[2][1], 0.0, 0.0, "iauZr", "12", status); + + vvd(r[0][2], 0.0, 0.0, "iauZr", "20", status); + vvd(r[1][2], 0.0, 0.0, "iauZr", "21", status); + vvd(r[2][2], 0.0, 0.0, "iauZr", "22", status); + +} + +int main(int argc, char *argv[]) +/* +** - - - - - +** m a i n +** - - - - - +** +** This revision: 2021 April 18 +*/ +{ + int status; + + +/* If any command-line argument, switch to verbose reporting. */ + if (argc > 1) { + verbose = 1; + argv[0][0] += 0; /* to avoid compiler warnings */ + } + +/* Preset the &status to FALSE = success. */ + status = 0; + +/* Test all of the SOFA functions. */ + t_a2af(&status); + t_a2tf(&status); + t_ab(&status); + t_ae2hd(&status); + t_af2a(&status); + t_anp(&status); + t_anpm(&status); + t_apcg(&status); + t_apcg13(&status); + t_apci(&status); + t_apci13(&status); + t_apco(&status); + t_apco13(&status); + t_apcs(&status); + t_apcs13(&status); + t_aper(&status); + t_aper13(&status); + t_apio(&status); + t_apio13(&status); + t_atcc13(&status); + t_atccq(&status); + t_atci13(&status); + t_atciq(&status); + t_atciqn(&status); + t_atciqz(&status); + t_atco13(&status); + t_atic13(&status); + t_aticq(&status); + t_aticqn(&status); + t_atio13(&status); + t_atioq(&status); + t_atoc13(&status); + t_atoi13(&status); + t_atoiq(&status); + t_bi00(&status); + t_bp00(&status); + t_bp06(&status); + t_bpn2xy(&status); + t_c2i00a(&status); + t_c2i00b(&status); + t_c2i06a(&status); + t_c2ibpn(&status); + t_c2ixy(&status); + t_c2ixys(&status); + t_c2s(&status); + t_c2t00a(&status); + t_c2t00b(&status); + t_c2t06a(&status); + t_c2tcio(&status); + t_c2teqx(&status); + t_c2tpe(&status); + t_c2txy(&status); + t_cal2jd(&status); + t_cp(&status); + t_cpv(&status); + t_cr(&status); + t_d2dtf(&status); + t_d2tf(&status); + t_dat(&status); + t_dtdb(&status); + t_dtf2d(&status); + t_eceq06(&status); + t_ecm06(&status); + t_ee00(&status); + t_ee00a(&status); + t_ee00b(&status); + t_ee06a(&status); + t_eect00(&status); + t_eform(&status); + t_eo06a(&status); + t_eors(&status); + t_epb(&status); + t_epb2jd(&status); + t_epj(&status); + t_epj2jd(&status); + t_epv00(&status); + t_eqec06(&status); + t_eqeq94(&status); + t_era00(&status); + t_fad03(&status); + t_fae03(&status); + t_faf03(&status); + t_faju03(&status); + t_fal03(&status); + t_falp03(&status); + t_fama03(&status); + t_fame03(&status); + t_fane03(&status); + t_faom03(&status); + t_fapa03(&status); + t_fasa03(&status); + t_faur03(&status); + t_fave03(&status); + t_fk425(&status); + t_fk45z(&status); + t_fk524(&status); + t_fk52h(&status); + t_fk54z(&status); + t_fk5hip(&status); + t_fk5hz(&status); + t_fw2m(&status); + t_fw2xy(&status); + t_g2icrs(&status); + t_gc2gd(&status); + t_gc2gde(&status); + t_gd2gc(&status); + t_gd2gce(&status); + t_gmst00(&status); + t_gmst06(&status); + t_gmst82(&status); + t_gst00a(&status); + t_gst00b(&status); + t_gst06(&status); + t_gst06a(&status); + t_gst94(&status); + t_h2fk5(&status); + t_hd2ae(&status); + t_hd2pa(&status); + t_hfk5z(&status); + t_icrs2g(&status); + t_ir(&status); + t_jd2cal(&status); + t_jdcalf(&status); + t_ld(&status); + t_ldn(&status); + t_ldsun(&status); + t_lteceq(&status); + t_ltecm(&status); + t_lteqec(&status); + t_ltp(&status); + t_ltpb(&status); + t_ltpecl(&status); + t_ltpequ(&status); + t_moon98(&status); + t_num00a(&status); + t_num00b(&status); + t_num06a(&status); + t_numat(&status); + t_nut00a(&status); + t_nut00b(&status); + t_nut06a(&status); + t_nut80(&status); + t_nutm80(&status); + t_obl06(&status); + t_obl80(&status); + t_p06e(&status); + t_p2pv(&status); + t_p2s(&status); + t_pap(&status); + t_pas(&status); + t_pb06(&status); + t_pdp(&status); + t_pfw06(&status); + t_plan94(&status); + t_pmat00(&status); + t_pmat06(&status); + t_pmat76(&status); + t_pm(&status); + t_pmp(&status); + t_pmpx(&status); + t_pmsafe(&status); + t_pn(&status); + t_pn00(&status); + t_pn00a(&status); + t_pn00b(&status); + t_pn06a(&status); + t_pn06(&status); + t_pnm00a(&status); + t_pnm00b(&status); + t_pnm06a(&status); + t_pnm80(&status); + t_pom00(&status); + t_ppp(&status); + t_ppsp(&status); + t_pr00(&status); + t_prec76(&status); + t_pv2p(&status); + t_pv2s(&status); + t_pvdpv(&status); + t_pvm(&status); + t_pvmpv(&status); + t_pvppv(&status); + t_pvstar(&status); + t_pvtob(&status); + t_pvu(&status); + t_pvup(&status); + t_pvxpv(&status); + t_pxp(&status); + t_refco(&status); + t_rm2v(&status); + t_rv2m(&status); + t_rx(&status); + t_rxp(&status); + t_rxpv(&status); + t_rxr(&status); + t_ry(&status); + t_rz(&status); + t_s00a(&status); + t_s00b(&status); + t_s00(&status); + t_s06a(&status); + t_s06(&status); + t_s2c(&status); + t_s2p(&status); + t_s2pv(&status); + t_s2xpv(&status); + t_sepp(&status); + t_seps(&status); + t_sp00(&status); + t_starpm(&status); + t_starpv(&status); + t_sxp(&status); + t_sxpv(&status); + t_taitt(&status); + t_taiut1(&status); + t_taiutc(&status); + t_tcbtdb(&status); + t_tcgtt(&status); + t_tdbtcb(&status); + t_tdbtt(&status); + t_tf2a(&status); + t_tf2d(&status); + t_tpors(&status); + t_tporv(&status); + t_tpsts(&status); + t_tpstv(&status); + t_tpxes(&status); + t_tpxev(&status); + t_tr(&status); + t_trxp(&status); + t_trxpv(&status); + t_tttai(&status); + t_tttcg(&status); + t_tttdb(&status); + t_ttut1(&status); + t_ut1tai(&status); + t_ut1tt(&status) ; + t_ut1utc(&status); + t_utctai(&status); + t_utcut1(&status); + t_xy06(&status); + t_xys00a(&status); + t_xys00b(&status); + t_xys06a(&status); + t_zp(&status); + t_zpv(&status); + t_zr(&status); + +/* Report, set up an appropriate exit status, and finish. */ + if (status) { + printf("t_sofa_c validation failed!\n"); + } else { + printf("t_sofa_c validation successful\n"); + } + return status; +} +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ diff --git a/src/cpp/3rdparty/sofa/src/taitt.c b/src/cpp/3rdparty/sofa/src/taitt.c new file mode 100644 index 000000000..683da48f2 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/taitt.c @@ -0,0 +1,163 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTaitt(double tai1, double tai2, double *tt1, double *tt2) +/* +** - - - - - - - - - +** i a u T a i t t +** - - - - - - - - - +** +** Time scale transformation: International Atomic Time, TAI, to +** Terrestrial Time, TT. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tai1,tai2 double TAI as a 2-part Julian Date +** +** Returned: +** tt1,tt2 double TT as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Note: +** +** tai1+tai2 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where tai1 is the Julian +** Day Number and tai2 is the fraction of a day. The returned +** tt1,tt2 follow suit. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* TT minus TAI (days). */ + static const double dtat = TTMTAI/DAYSEC; + + +/* Result, safeguarding precision. */ + if ( fabs(tai1) > fabs(tai2) ) { + *tt1 = tai1; + *tt2 = tai2 + dtat; + } else { + *tt1 = tai1 + dtat; + *tt2 = tai2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/taiut1.c b/src/cpp/3rdparty/sofa/src/taiut1.c new file mode 100644 index 000000000..45fd36254 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/taiut1.c @@ -0,0 +1,165 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTaiut1(double tai1, double tai2, double dta, + double *ut11, double *ut12) +/* +** - - - - - - - - - - +** i a u T a i u t 1 +** - - - - - - - - - - +** +** Time scale transformation: International Atomic Time, TAI, to +** Universal Time, UT1. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tai1,tai2 double TAI as a 2-part Julian Date +** dta double UT1-TAI in seconds +** +** Returned: +** ut11,ut12 double UT1 as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) tai1+tai2 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where tai1 is the Julian +** Day Number and tai2 is the fraction of a day. The returned +** UT11,UT12 follow suit. +** +** 2) The argument dta, i.e. UT1-TAI, is an observed quantity, and is +** available from IERS tabulations. +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +** +*/ +{ + double dtad; + + +/* Result, safeguarding precision. */ + dtad = dta / DAYSEC; + if ( fabs(tai1) > fabs(tai2) ) { + *ut11 = tai1; + *ut12 = tai2 + dtad; + } else { + *ut11 = tai1 + dtad; + *ut12 = tai2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/taiutc.c b/src/cpp/3rdparty/sofa/src/taiutc.c new file mode 100644 index 000000000..3adf53d15 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/taiutc.c @@ -0,0 +1,211 @@ +#include "sofa.h" + +int iauTaiutc(double tai1, double tai2, double *utc1, double *utc2) +/* +** - - - - - - - - - - +** i a u T a i u t c +** - - - - - - - - - - +** +** Time scale transformation: International Atomic Time, TAI, to +** Coordinated Universal Time, UTC. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tai1,tai2 double TAI as a 2-part Julian Date (Note 1) +** +** Returned: +** utc1,utc2 double UTC as a 2-part quasi Julian Date (Notes 1-3) +** +** Returned (function value): +** int status: +1 = dubious year (Note 4) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) tai1+tai2 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where tai1 is the Julian +** Day Number and tai2 is the fraction of a day. The returned utc1 +** and utc2 form an analogous pair, except that a special convention +** is used, to deal with the problem of leap seconds - see the next +** note. +** +** 2) JD cannot unambiguously represent UTC during a leap second unless +** special measures are taken. The convention in the present +** function is that the JD day represents UTC days whether the +** length is 86399, 86400 or 86401 SI seconds. In the 1960-1972 era +** there were smaller jumps (in either direction) each time the +** linear UTC(TAI) expression was changed, and these "mini-leaps" +** are also included in the SOFA convention. +** +** 3) The function iauD2dtf can be used to transform the UTC quasi-JD +** into calendar date and clock time, including UTC leap second +** handling. +** +** 4) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the future +** to be trusted. See iauDat for further details. +** +** Called: +** iauUtctai UTC to TAI +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int big1; + int i, j; + double a1, a2, u1, u2, g1, g2; + + +/* Put the two parts of the TAI into big-first order. */ + big1 = ( fabs(tai1) >= fabs(tai2) ); + if ( big1 ) { + a1 = tai1; + a2 = tai2; + } else { + a1 = tai2; + a2 = tai1; + } + +/* Initial guess for UTC. */ + u1 = a1; + u2 = a2; + +/* Iterate (though in most cases just once is enough). */ + for ( i = 0; i < 3; i++ ) { + + /* Guessed UTC to TAI. */ + j = iauUtctai(u1, u2, &g1, &g2); + if ( j < 0 ) return j; + + /* Adjust guessed UTC. */ + u2 += a1 - g1; + u2 += a2 - g2; + } + +/* Return the UTC result, preserving the TAI order. */ + if ( big1 ) { + *utc1 = u1; + *utc2 = u2; + } else { + *utc1 = u2; + *utc2 = u1; + } + +/* Status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tcbtdb.c b/src/cpp/3rdparty/sofa/src/tcbtdb.c new file mode 100644 index 000000000..818923368 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tcbtdb.c @@ -0,0 +1,185 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTcbtdb(double tcb1, double tcb2, double *tdb1, double *tdb2) +/* +** - - - - - - - - - - +** i a u T c b t d b +** - - - - - - - - - - +** +** Time scale transformation: Barycentric Coordinate Time, TCB, to +** Barycentric Dynamical Time, TDB. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tcb1,tcb2 double TCB as a 2-part Julian Date +** +** Returned: +** tdb1,tdb2 double TDB as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) tcb1+tcb2 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where tcb1 is the Julian +** Day Number and tcb2 is the fraction of a day. The returned +** tdb1,tdb2 follow suit. +** +** 2) The 2006 IAU General Assembly introduced a conventional linear +** transformation between TDB and TCB. This transformation +** compensates for the drift between TCB and terrestrial time TT, +** and keeps TDB approximately centered on TT. Because the +** relationship between TT and TCB depends on the adopted solar +** system ephemeris, the degree of alignment between TDB and TT over +** long intervals will vary according to which ephemeris is used. +** Former definitions of TDB attempted to avoid this problem by +** stipulating that TDB and TT should differ only by periodic +** effects. This is a good description of the nature of the +** relationship but eluded precise mathematical formulation. The +** conventional linear relationship adopted in 2006 sidestepped +** these difficulties whilst delivering a TDB that in practice was +** consistent with values before that date. +** +** 3) TDB is essentially the same as Teph, the time argument for the +** JPL solar system ephemerides. +** +** Reference: +** +** IAU 2006 Resolution B3 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* 1977 Jan 1 00:00:32.184 TT, as two-part JD */ + static const double t77td = DJM0 + DJM77; + static const double t77tf = TTMTAI/DAYSEC; + +/* TDB (days) at TAI 1977 Jan 1.0 */ + static const double tdb0 = TDB0/DAYSEC; + + double d; + + +/* Result, safeguarding precision. */ + if ( fabs(tcb1) > fabs(tcb2) ) { + d = tcb1 - t77td; + *tdb1 = tcb1; + *tdb2 = tcb2 + tdb0 - ( d + ( tcb2 - t77tf ) ) * ELB; + } else { + d = tcb2 - t77td; + *tdb1 = tcb1 + tdb0 - ( d + ( tcb1 - t77tf ) ) * ELB; + *tdb2 = tcb2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tcgtt.c b/src/cpp/3rdparty/sofa/src/tcgtt.c new file mode 100644 index 000000000..afef1aea4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tcgtt.c @@ -0,0 +1,162 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTcgtt(double tcg1, double tcg2, double *tt1, double *tt2) +/* +** - - - - - - - - - +** i a u T c g t t +** - - - - - - - - - +** +** Time scale transformation: Geocentric Coordinate Time, TCG, to +** Terrestrial Time, TT. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tcg1,tcg2 double TCG as a 2-part Julian Date +** +** Returned: +** tt1,tt2 double TT as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Note: +** +** tcg1+tcg2 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where tcg1 is the Julian +** Day Number and tcg22 is the fraction of a day. The returned +** tt1,tt2 follow suit. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** IAU 2000 Resolution B1.9 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* 1977 Jan 1 00:00:32.184 TT, as MJD */ + static const double t77t = DJM77 + TTMTAI/DAYSEC; + + +/* Result, safeguarding precision. */ + if ( fabs(tcg1) > fabs(tcg2) ) { + *tt1 = tcg1; + *tt2 = tcg2 - ( ( tcg1 - DJM0 ) + ( tcg2 - t77t ) ) * ELG; + } else { + *tt1 = tcg1 - ( ( tcg2 - DJM0 ) + ( tcg1 - t77t ) ) * ELG; + *tt2 = tcg2; + } + +/* OK status. */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tdbtcb.c b/src/cpp/3rdparty/sofa/src/tdbtcb.c new file mode 100644 index 000000000..3ff64c0d5 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tdbtcb.c @@ -0,0 +1,190 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTdbtcb(double tdb1, double tdb2, double *tcb1, double *tcb2) +/* +** - - - - - - - - - - +** i a u T d b t c b +** - - - - - - - - - - +** +** Time scale transformation: Barycentric Dynamical Time, TDB, to +** Barycentric Coordinate Time, TCB. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tdb1,tdb2 double TDB as a 2-part Julian Date +** +** Returned: +** tcb1,tcb2 double TCB as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) tdb1+tdb2 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where tdb1 is the Julian +** Day Number and tdb2 is the fraction of a day. The returned +** tcb1,tcb2 follow suit. +** +** 2) The 2006 IAU General Assembly introduced a conventional linear +** transformation between TDB and TCB. This transformation +** compensates for the drift between TCB and terrestrial time TT, +** and keeps TDB approximately centered on TT. Because the +** relationship between TT and TCB depends on the adopted solar +** system ephemeris, the degree of alignment between TDB and TT over +** long intervals will vary according to which ephemeris is used. +** Former definitions of TDB attempted to avoid this problem by +** stipulating that TDB and TT should differ only by periodic +** effects. This is a good description of the nature of the +** relationship but eluded precise mathematical formulation. The +** conventional linear relationship adopted in 2006 sidestepped +** these difficulties whilst delivering a TDB that in practice was +** consistent with values before that date. +** +** 3) TDB is essentially the same as Teph, the time argument for the +** JPL solar system ephemerides. +** +** Reference: +** +** IAU 2006 Resolution B3 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* 1977 Jan 1 00:00:32.184 TT, as two-part JD */ + static const double t77td = DJM0 + DJM77; + static const double t77tf = TTMTAI/DAYSEC; + +/* TDB (days) at TAI 1977 Jan 1.0 */ + static const double tdb0 = TDB0/DAYSEC; + +/* TDB to TCB rate */ + static const double elbb = ELB/(1.0-ELB); + + double d, f; + + +/* Result, preserving date format but safeguarding precision. */ + if ( fabs(tdb1) > fabs(tdb2) ) { + d = t77td - tdb1; + f = tdb2 - tdb0; + *tcb1 = tdb1; + *tcb2 = f - ( d - ( f - t77tf ) ) * elbb; + } else { + d = t77td - tdb2; + f = tdb1 - tdb0; + *tcb1 = f - ( d - ( f - t77tf ) ) * elbb; + *tcb2 = tdb2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tdbtt.c b/src/cpp/3rdparty/sofa/src/tdbtt.c new file mode 100644 index 000000000..61f4fe175 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tdbtt.c @@ -0,0 +1,175 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTdbtt(double tdb1, double tdb2, double dtr, + double *tt1, double *tt2 ) +/* +** - - - - - - - - - +** i a u T d b t t +** - - - - - - - - - +** +** Time scale transformation: Barycentric Dynamical Time, TDB, to +** Terrestrial Time, TT. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tdb1,tdb2 double TDB as a 2-part Julian Date +** dtr double TDB-TT in seconds +** +** Returned: +** tt1,tt2 double TT as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) tdb1+tdb2 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where tdb1 is the Julian +** Day Number and tdb2 is the fraction of a day. The returned +** tt1,tt2 follow suit. +** +** 2) The argument dtr represents the quasi-periodic component of the +** GR transformation between TT and TCB. It is dependent upon the +** adopted solar-system ephemeris, and can be obtained by numerical +** integration, by interrogating a precomputed time ephemeris or by +** evaluating a model such as that implemented in the SOFA function +** iauDtdb. The quantity is dominated by an annual term of 1.7 ms +** amplitude. +** +** 3) TDB is essentially the same as Teph, the time argument for the +** JPL solar system ephemerides. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** IAU 2006 Resolution 3 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +** +*/ +{ + double dtrd; + + +/* Result, safeguarding precision. */ + dtrd = dtr / DAYSEC; + if ( fabs(tdb1) > fabs(tdb2) ) { + *tt1 = tdb1; + *tt2 = tdb2 - dtrd; + } else { + *tt1 = tdb1 - dtrd; + *tt2 = tdb2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tf2a.c b/src/cpp/3rdparty/sofa/src/tf2a.c new file mode 100644 index 000000000..2b1beed2c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tf2a.c @@ -0,0 +1,160 @@ +#include "sofa.h" +#include "sofam.h" +#include + +int iauTf2a(char s, int ihour, int imin, double sec, double *rad) +/* +** - - - - - - - - +** i a u T f 2 a +** - - - - - - - - +** +** Convert hours, minutes, seconds to radians. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** s char sign: '-' = negative, otherwise positive +** ihour int hours +** imin int minutes +** sec double seconds +** +** Returned: +** rad double angle in radians +** +** Returned (function value): +** int status: 0 = OK +** 1 = ihour outside range 0-23 +** 2 = imin outside range 0-59 +** 3 = sec outside range 0-59.999... +** +** Notes: +** +** 1) The result is computed even if any of the range checks fail. +** +** 2) Negative ihour, imin and/or sec produce a warning status, but +** the absolute value is used in the conversion. +** +** 3) If there are multiple errors, the status value reflects only the +** first, the smallest taking precedence. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Compute the interval. */ + *rad = ( s == '-' ? -1.0 : 1.0 ) * + ( 60.0 * ( 60.0 * ( (double) abs(ihour) ) + + ( (double) abs(imin) ) ) + + fabs(sec) ) * DS2R; + +/* Validate arguments and return status. */ + if ( ihour < 0 || ihour > 23 ) return 1; + if ( imin < 0 || imin > 59 ) return 2; + if ( sec < 0.0 || sec >= 60.0 ) return 3; + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tf2d.c b/src/cpp/3rdparty/sofa/src/tf2d.c new file mode 100644 index 000000000..6078242f7 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tf2d.c @@ -0,0 +1,160 @@ +#include "sofa.h" +#include "sofam.h" +#include + +int iauTf2d(char s, int ihour, int imin, double sec, double *days) +/* +** - - - - - - - - +** i a u T f 2 d +** - - - - - - - - +** +** Convert hours, minutes, seconds to days. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** s char sign: '-' = negative, otherwise positive +** ihour int hours +** imin int minutes +** sec double seconds +** +** Returned: +** days double interval in days +** +** Returned (function value): +** int status: 0 = OK +** 1 = ihour outside range 0-23 +** 2 = imin outside range 0-59 +** 3 = sec outside range 0-59.999... +** +** Notes: +** +** 1) The result is computed even if any of the range checks fail. +** +** 2) Negative ihour, imin and/or sec produce a warning status, but +** the absolute value is used in the conversion. +** +** 3) If there are multiple errors, the status value reflects only the +** first, the smallest taking precedence. +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Compute the interval. */ + *days = ( s == '-' ? -1.0 : 1.0 ) * + ( 60.0 * ( 60.0 * ( (double) abs(ihour) ) + + ( (double) abs(imin) ) ) + + fabs(sec) ) / DAYSEC; + +/* Validate arguments and return status. */ + if ( ihour < 0 || ihour > 23 ) return 1; + if ( imin < 0 || imin > 59 ) return 2; + if ( sec < 0.0 || sec >= 60.0 ) return 3; + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tpors.c b/src/cpp/3rdparty/sofa/src/tpors.c new file mode 100644 index 000000000..4e11818dd --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tpors.c @@ -0,0 +1,222 @@ +#include "sofa.h" + +int iauTpors(double xi, double eta, double a, double b, + double *a01, double *b01, double *a02, double *b02) +/* +** - - - - - - - - - +** i a u T p o r s +** - - - - - - - - - +** +** In the tangent plane projection, given the rectangular coordinates +** of a star and its spherical coordinates, determine the spherical +** coordinates of the tangent point. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** xi,eta double rectangular coordinates of star image (Note 2) +** a,b double star's spherical coordinates (Note 3) +** +** Returned: +** *a01,*b01 double tangent point's spherical coordinates, Soln. 1 +** *a02,*b02 double tangent point's spherical coordinates, Soln. 2 +** +** Returned (function value): +** int number of solutions: +** 0 = no solutions returned (Note 5) +** 1 = only the first solution is useful (Note 6) +** 2 = both solutions are useful (Note 6) +** +** Notes: +** +** 1) The tangent plane projection is also called the "gnomonic +** projection" and the "central projection". +** +** 2) The eta axis points due north in the adopted coordinate system. +** If the spherical coordinates are observed (RA,Dec), the tangent +** plane coordinates (xi,eta) are conventionally called the +** "standard coordinates". If the spherical coordinates are with +** respect to a right-handed triad, (xi,eta) are also right-handed. +** The units of (xi,eta) are, effectively, radians at the tangent +** point. +** +** 3) All angular arguments are in radians. +** +** 4) The angles a01 and a02 are returned in the range 0-2pi. The +** angles b01 and b02 are returned in the range +/-pi, but in the +** usual, non-pole-crossing, case, the range is +/-pi/2. +** +** 5) Cases where there is no solution can arise only near the poles. +** For example, it is clearly impossible for a star at the pole +** itself to have a non-zero xi value, and hence it is meaningless +** to ask where the tangent point would have to be to bring about +** this combination of xi and dec. +** +** 6) Also near the poles, cases can arise where there are two useful +** solutions. The return value indicates whether the second of the +** two solutions returned is useful; 1 indicates only one useful +** solution, the usual case. +** +** 7) The basis of the algorithm is to solve the spherical triangle PSC, +** where P is the north celestial pole, S is the star and C is the +** tangent point. The spherical coordinates of the tangent point are +** [a0,b0]; writing rho^2 = (xi^2+eta^2) and r^2 = (1+rho^2), side c +** is then (pi/2-b), side p is sqrt(xi^2+eta^2) and side s (to be +** found) is (pi/2-b0). Angle C is given by sin(C) = xi/rho and +** cos(C) = eta/rho. Angle P (to be found) is the longitude +** difference between star and tangent point (a-a0). +** +** 8) This function is a member of the following set: +** +** spherical vector solve for +** +** iauTpxes iauTpxev xi,eta +** iauTpsts iauTpstv star +** > iauTpors < iauTporv origin +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Calabretta M.R. & Greisen, E.W., 2002, "Representations of +** celestial coordinates in FITS", Astron.Astrophys. 395, 1077 +** +** Green, R.M., "Spherical Astronomy", Cambridge University Press, +** 1987, Chapter 13. +** +** This revision: 2018 January 2 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double xi2, r, sb, cb, rsb, rcb, w2, w, s, c; + + + xi2 = xi*xi; + r = sqrt(1.0 + xi2 + eta*eta); + sb = sin(b); + cb = cos(b); + rsb = r*sb; + rcb = r*cb; + w2 = rcb*rcb - xi2; + if ( w2 >= 0.0 ) { + w = sqrt(w2); + s = rsb - eta*w; + c = rsb*eta + w; + if ( xi == 0.0 && w == 0.0 ) w = 1.0; + *a01 = iauAnp(a - atan2(xi,w)); + *b01 = atan2(s,c); + w = -w; + s = rsb - eta*w; + c = rsb*eta + w; + *a02 = iauAnp(a - atan2(xi,w)); + *b02 = atan2(s,c); + return (fabs(rsb) < 1.0) ? 1 : 2; + } else { + return 0; + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tporv.c b/src/cpp/3rdparty/sofa/src/tporv.c new file mode 100644 index 000000000..767aa7823 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tporv.c @@ -0,0 +1,219 @@ +#include "sofa.h" + +int iauTporv(double xi, double eta, double v[3], + double v01[3], double v02[3]) +/* +** - - - - - - - - - +** i a u T p o r v +** - - - - - - - - - +** +** In the tangent plane projection, given the rectangular coordinates +** of a star and its direction cosines, determine the direction +** cosines of the tangent point. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** xi,eta double rectangular coordinates of star image (Note 2) +** v double[3] star's direction cosines (Note 3) +** +** Returned: +** v01 double[3] tangent point's direction cosines, Solution 1 +** v02 double[3] tangent point's direction cosines, Solution 2 +** +** Returned (function value): +** int number of solutions: +** 0 = no solutions returned (Note 4) +** 1 = only the first solution is useful (Note 5) +** 2 = both solutions are useful (Note 5) +** +** Notes: +** +** 1) The tangent plane projection is also called the "gnomonic +** projection" and the "central projection". +** +** 2) The eta axis points due north in the adopted coordinate system. +** If the direction cosines represent observed (RA,Dec), the tangent +** plane coordinates (xi,eta) are conventionally called the +** "standard coordinates". If the direction cosines are with +** respect to a right-handed triad, (xi,eta) are also right-handed. +** The units of (xi,eta) are, effectively, radians at the tangent +** point. +** +** 3) The vector v must be of unit length or the result will be wrong. +** +** 4) Cases where there is no solution can arise only near the poles. +** For example, it is clearly impossible for a star at the pole +** itself to have a non-zero xi value, and hence it is meaningless +** to ask where the tangent point would have to be. +** +** 5) Also near the poles, cases can arise where there are two useful +** solutions. The return value indicates whether the second of the +** two solutions returned is useful; 1 indicates only one useful +** solution, the usual case. +** +** 6) The basis of the algorithm is to solve the spherical triangle +** PSC, where P is the north celestial pole, S is the star and C is +** the tangent point. Calling the celestial spherical coordinates +** of the star and tangent point (a,b) and (a0,b0) respectively, and +** writing rho^2 = (xi^2+eta^2) and r^2 = (1+rho^2), and +** transforming the vector v into (a,b) in the normal way, side c is +** then (pi/2-b), side p is sqrt(xi^2+eta^2) and side s (to be +** found) is (pi/2-b0), while angle C is given by sin(C) = xi/rho +** and cos(C) = eta/rho; angle P (to be found) is (a-a0). After +** solving the spherical triangle, the result (a0,b0) can be +** expressed in vector form as v0. +** +** 7) This function is a member of the following set: +** +** spherical vector solve for +** +** iauTpxes iauTpxev xi,eta +** iauTpsts iauTpstv star +** iauTpors > iauTporv < origin +** +** References: +** +** Calabretta M.R. & Greisen, E.W., 2002, "Representations of +** celestial coordinates in FITS", Astron.Astrophys. 395, 1077 +** +** Green, R.M., "Spherical Astronomy", Cambridge University Press, +** 1987, Chapter 13. +** +** This revision: 2018 January 2 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y, z, rxy2, xi2, eta2p1, r, rsb, rcb, w2, w, c; + + + x = v[0]; + y = v[1]; + z = v[2]; + rxy2 = x*x + y*y; + xi2 = xi*xi; + eta2p1 = eta*eta + 1.0; + r = sqrt(xi2 + eta2p1); + rsb = r*z; + rcb = r*sqrt(x*x + y*y); + w2 = rcb*rcb - xi2; + if ( w2 > 0.0 ) { + w = sqrt(w2); + c = (rsb*eta + w) / (eta2p1*sqrt(rxy2*(w2+xi2))); + v01[0] = c * (x*w + y*xi); + v01[1] = c * (y*w - x*xi); + v01[2] = (rsb - eta*w) / eta2p1; + w = - w; + c = (rsb*eta + w) / (eta2p1*sqrt(rxy2*(w2+xi2))); + v02[0] = c * (x*w + y*xi); + v02[1] = c * (y*w - x*xi); + v02[2] = (rsb - eta*w) / eta2p1; + return (fabs(rsb) < 1.0) ? 1 : 2; + } else { + return 0; + } + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tpsts.c b/src/cpp/3rdparty/sofa/src/tpsts.c new file mode 100644 index 000000000..aeb55652c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tpsts.c @@ -0,0 +1,170 @@ +#include "sofa.h" + +void iauTpsts(double xi, double eta, double a0, double b0, + double *a, double *b) +/* +** - - - - - - - - - +** i a u T p s t s +** - - - - - - - - - +** +** In the tangent plane projection, given the star's rectangular +** coordinates and the spherical coordinates of the tangent point, +** solve for the spherical coordinates of the star. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** xi,eta double rectangular coordinates of star image (Note 2) +** a0,b0 double tangent point's spherical coordinates +** +** Returned: +** *a,*b double star's spherical coordinates +** +** 1) The tangent plane projection is also called the "gnomonic +** projection" and the "central projection". +** +** 2) The eta axis points due north in the adopted coordinate system. +** If the spherical coordinates are observed (RA,Dec), the tangent +** plane coordinates (xi,eta) are conventionally called the +** "standard coordinates". If the spherical coordinates are with +** respect to a right-handed triad, (xi,eta) are also right-handed. +** The units of (xi,eta) are, effectively, radians at the tangent +** point. +** +** 3) All angular arguments are in radians. +** +** 4) This function is a member of the following set: +** +** spherical vector solve for +** +** iauTpxes iauTpxev xi,eta +** > iauTpsts < iauTpstv star +** iauTpors iauTporv origin +** +** Called: +** iauAnp normalize angle into range 0 to 2pi +** +** References: +** +** Calabretta M.R. & Greisen, E.W., 2002, "Representations of +** celestial coordinates in FITS", Astron.Astrophys. 395, 1077 +** +** Green, R.M., "Spherical Astronomy", Cambridge University Press, +** 1987, Chapter 13. +** +** This revision: 2018 January 2 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double sb0, cb0, d; + + sb0 = sin(b0); + cb0 = cos(b0); + d = cb0 - eta*sb0; + *a = iauAnp(atan2(xi,d) + a0); + *b = atan2(sb0+eta*cb0, sqrt(xi*xi+d*d)); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tpstv.c b/src/cpp/3rdparty/sofa/src/tpstv.c new file mode 100644 index 000000000..b59e0b119 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tpstv.c @@ -0,0 +1,194 @@ +#include "sofa.h" + +void iauTpstv(double xi, double eta, double v0[3], double v[3]) +/* +** - - - - - - - - - +** i a u T p s t v +** - - - - - - - - - +** +** In the tangent plane projection, given the star's rectangular +** coordinates and the direction cosines of the tangent point, solve +** for the direction cosines of the star. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** xi,eta double rectangular coordinates of star image (Note 2) +** v0 double[3] tangent point's direction cosines +** +** Returned: +** v double[3] star's direction cosines +** +** 1) The tangent plane projection is also called the "gnomonic +** projection" and the "central projection". +** +** 2) The eta axis points due north in the adopted coordinate system. +** If the direction cosines represent observed (RA,Dec), the tangent +** plane coordinates (xi,eta) are conventionally called the +** "standard coordinates". If the direction cosines are with +** respect to a right-handed triad, (xi,eta) are also right-handed. +** The units of (xi,eta) are, effectively, radians at the tangent +** point. +** +** 3) The method used is to complete the star vector in the (xi,eta) +** based triad and normalize it, then rotate the triad to put the +** tangent point at the pole with the x-axis aligned to zero +** longitude. Writing (a0,b0) for the celestial spherical +** coordinates of the tangent point, the sequence of rotations is +** (b-pi/2) around the x-axis followed by (-a-pi/2) around the +** z-axis. +** +** 4) If vector v0 is not of unit length, the returned vector v will +** be wrong. +** +** 5) If vector v0 points at a pole, the returned vector v will be +** based on the arbitrary assumption that the longitude coordinate +** of the tangent point is zero. +** +** 6) This function is a member of the following set: +** +** spherical vector solve for +** +** iauTpxes iauTpxev xi,eta +** iauTpsts > iauTpstv < star +** iauTpors iauTporv origin +** +** References: +** +** Calabretta M.R. & Greisen, E.W., 2002, "Representations of +** celestial coordinates in FITS", Astron.Astrophys. 395, 1077 +** +** Green, R.M., "Spherical Astronomy", Cambridge University Press, +** 1987, Chapter 13. +** +** This revision: 2018 January 2 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double x, y, z, f, r; + + +/* Tangent point. */ + x = v0[0]; + y = v0[1]; + z = v0[2]; + +/* Deal with polar case. */ + r = sqrt(x*x + y*y); + if ( r == 0.0 ) { + r = 1e-20; + x = r; + } + +/* Star vector length to tangent plane. */ + f = sqrt(1.0 + xi*xi + eta*eta); + +/* Apply the transformation and normalize. */ + v[0] = (x - (xi*y + eta*x*z) / r) / f; + v[1] = (y + (xi*x - eta*y*z) / r) / f; + v[2] = (z + eta*r) / f; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tpxes.c b/src/cpp/3rdparty/sofa/src/tpxes.c new file mode 100644 index 000000000..b4f94bb94 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tpxes.c @@ -0,0 +1,203 @@ +#include "sofa.h" + +int iauTpxes(double a, double b, double a0, double b0, + double *xi, double *eta) +/* +** - - - - - - - - - +** i a u T p x e s +** - - - - - - - - - +** +** In the tangent plane projection, given celestial spherical +** coordinates for a star and the tangent point, solve for the star's +** rectangular coordinates in the tangent plane. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** a,b double star's spherical coordinates +** a0,b0 double tangent point's spherical coordinates +** +** Returned: +** *xi,*eta double rectangular coordinates of star image (Note 2) +** +** Returned (function value): +** int status: 0 = OK +** 1 = star too far from axis +** 2 = antistar on tangent plane +** 3 = antistar too far from axis +** +** Notes: +** +** 1) The tangent plane projection is also called the "gnomonic +** projection" and the "central projection". +** +** 2) The eta axis points due north in the adopted coordinate system. +** If the spherical coordinates are observed (RA,Dec), the tangent +** plane coordinates (xi,eta) are conventionally called the +** "standard coordinates". For right-handed spherical coordinates, +** (xi,eta) are also right-handed. The units of (xi,eta) are, +** effectively, radians at the tangent point. +** +** 3) All angular arguments are in radians. +** +** 4) This function is a member of the following set: +** +** spherical vector solve for +** +** > iauTpxes < iauTpxev xi,eta +** iauTpsts iauTpstv star +** iauTpors iauTporv origin +** +** References: +** +** Calabretta M.R. & Greisen, E.W., 2002, "Representations of +** celestial coordinates in FITS", Astron.Astrophys. 395, 1077 +** +** Green, R.M., "Spherical Astronomy", Cambridge University Press, +** 1987, Chapter 13. +** +** This revision: 2018 January 2 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + const double TINY = 1e-6; + int j; + double sb0, sb, cb0, cb, da, sda, cda, d; + + +/* Functions of the spherical coordinates. */ + sb0 = sin(b0); + sb = sin(b); + cb0 = cos(b0); + cb = cos(b); + da = a - a0; + sda = sin(da); + cda = cos(da); + +/* Reciprocal of star vector length to tangent plane. */ + d = sb*sb0 + cb*cb0*cda; + +/* Check for error cases. */ + if ( d > TINY ) { + j = 0; + } else if ( d >= 0.0 ) { + j = 1; + d = TINY; + } else if ( d > -TINY ) { + j = 2; + d = -TINY; + } else { + j = 3; + } + +/* Return the tangent plane coordinates (even in dubious cases). */ + *xi = cb*sda / d; + *eta = (sb*cb0 - cb*sb0*cda) / d; + +/* Return the status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tpxev.c b/src/cpp/3rdparty/sofa/src/tpxev.c new file mode 100644 index 000000000..ca7882a87 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tpxev.c @@ -0,0 +1,223 @@ +#include "sofa.h" + +int iauTpxev(double v[3], double v0[3], double *xi, double *eta) +/* +** - - - - - - - - - +** i a u T p x e v +** - - - - - - - - - +** +** In the tangent plane projection, given celestial direction cosines +** for a star and the tangent point, solve for the star's rectangular +** coordinates in the tangent plane. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** v double[3] direction cosines of star (Note 4) +** v0 double[3] direction cosines of tangent point (Note 4) +** +** Returned: +** *xi,*eta double tangent plane coordinates of star +** +** Returned (function value): +** int status: 0 = OK +** 1 = star too far from axis +** 2 = antistar on tangent plane +** 3 = antistar too far from axis +** +** Notes: +** +** 1) The tangent plane projection is also called the "gnomonic +** projection" and the "central projection". +** +** 2) The eta axis points due north in the adopted coordinate system. +** If the direction cosines represent observed (RA,Dec), the tangent +** plane coordinates (xi,eta) are conventionally called the +** "standard coordinates". If the direction cosines are with +** respect to a right-handed triad, (xi,eta) are also right-handed. +** The units of (xi,eta) are, effectively, radians at the tangent +** point. +** +** 3) The method used is to extend the star vector to the tangent +** plane and then rotate the triad so that (x,y) becomes (xi,eta). +** Writing (a,b) for the celestial spherical coordinates of the +** star, the sequence of rotations is (a+pi/2) around the z-axis +** followed by (pi/2-b) around the x-axis. +** +** 4) If vector v0 is not of unit length, or if vector v is of zero +** length, the results will be wrong. +** +** 5) If v0 points at a pole, the returned (xi,eta) will be based on +** the arbitrary assumption that the longitude coordinate of the +** tangent point is zero. +** +** 6) This function is a member of the following set: +** +** spherical vector solve for +** +** iauTpxes > iauTpxev < xi,eta +** iauTpsts iauTpstv star +** iauTpors iauTporv origin +** +** References: +** +** Calabretta M.R. & Greisen, E.W., 2002, "Representations of +** celestial coordinates in FITS", Astron.Astrophys. 395, 1077 +** +** Green, R.M., "Spherical Astronomy", Cambridge University Press, +** 1987, Chapter 13. +** +** This revision: 2018 January 2 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + const double TINY = 1e-6; + int j; + double x, y, z, x0, y0, z0, r2, r, w, d; + + +/* Star and tangent point. */ + x = v[0]; + y = v[1]; + z = v[2]; + x0 = v0[0]; + y0 = v0[1]; + z0 = v0[2]; + +/* Deal with polar case. */ + r2 = x0*x0 + y0*y0; + r = sqrt(r2); + if ( r == 0.0 ) { + r = 1e-20; + x0 = r; + } + +/* Reciprocal of star vector length to tangent plane. */ + w = x*x0 + y*y0; + d = w + z*z0; + +/* Check for error cases. */ + if ( d > TINY ) { + j = 0; + } else if ( d >= 0.0 ) { + j = 1; + d = TINY; + } else if ( d > -TINY ) { + j = 2; + d = -TINY; + } else { + j = 3; + } + +/* Return the tangent plane coordinates (even in dubious cases). */ + d *= r; + *xi = (y*x0 - x*y0) / d; + *eta = (z*r2 - z0*w) / d; + +/* Return the status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tr.c b/src/cpp/3rdparty/sofa/src/tr.c new file mode 100644 index 000000000..686dd3ec8 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tr.c @@ -0,0 +1,143 @@ +#include "sofa.h" + +void iauTr(double r[3][3], double rt[3][3]) +/* +** - - - - - - +** i a u T r +** - - - - - - +** +** Transpose an r-matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** r double[3][3] r-matrix +** +** Returned: +** rt double[3][3] transpose +** +** Note: +** It is permissible for r and rt to be the same array. +** +** Called: +** iauCr copy r-matrix +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double wm[3][3]; + int i, j; + + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + wm[i][j] = r[j][i]; + } + } + iauCr(wm, rt); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/trxp.c b/src/cpp/3rdparty/sofa/src/trxp.c new file mode 100644 index 000000000..442d353a4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/trxp.c @@ -0,0 +1,143 @@ +#include "sofa.h" + +void iauTrxp(double r[3][3], double p[3], double trp[3]) +/* +** - - - - - - - - +** i a u T r x p +** - - - - - - - - +** +** Multiply a p-vector by the transpose of an r-matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** r double[3][3] r-matrix +** p double[3] p-vector +** +** Returned: +** trp double[3] r^T * p +** +** Note: +** It is permissible for p and trp to be the same array. +** +** Called: +** iauTr transpose r-matrix +** iauRxp product of r-matrix and p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double tr[3][3]; + + +/* Transpose of matrix r. */ + iauTr(r, tr); + +/* Matrix tr * vector p -> vector trp. */ + iauRxp(tr, p, trp); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/trxpv.c b/src/cpp/3rdparty/sofa/src/trxpv.c new file mode 100644 index 000000000..6f7e4f214 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/trxpv.c @@ -0,0 +1,149 @@ +#include "sofa.h" + +void iauTrxpv(double r[3][3], double pv[2][3], double trpv[2][3]) +/* +** - - - - - - - - - +** i a u T r x p v +** - - - - - - - - - +** +** Multiply a pv-vector by the transpose of an r-matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Given: +** r double[3][3] r-matrix +** pv double[2][3] pv-vector +** +** Returned: +** trpv double[2][3] r^T * pv +** +** Notes: +** +** 1) The algorithm is for the simple case where the r-matrix r is not +** a function of time. The case where r is a function of time leads +** to an additional velocity component equal to the product of the +** derivative of the transpose of r and the position vector. +** +** 2) It is permissible for pv and rpv to be the same array. +** +** Called: +** iauTr transpose r-matrix +** iauRxpv product of r-matrix and pv-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double tr[3][3]; + + +/* Transpose of matrix r. */ + iauTr(r, tr); + +/* Matrix tr * vector pv -> vector trpv. */ + iauRxpv(tr, pv, trpv); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tttai.c b/src/cpp/3rdparty/sofa/src/tttai.c new file mode 100644 index 000000000..a4c04b57f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tttai.c @@ -0,0 +1,163 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTttai(double tt1, double tt2, double *tai1, double *tai2) +/* +** - - - - - - - - - +** i a u T t t a i +** - - - - - - - - - +** +** Time scale transformation: Terrestrial Time, TT, to International +** Atomic Time, TAI. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tt1,tt2 double TT as a 2-part Julian Date +** +** Returned: +** tai1,tai2 double TAI as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Note: +** +** tt1+tt2 is Julian Date, apportioned in any convenient way between +** the two arguments, for example where tt1 is the Julian Day Number +** and tt2 is the fraction of a day. The returned tai1,tai2 follow +** suit. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* TT minus TAI (days). */ + static const double dtat = TTMTAI/DAYSEC; + + +/* Result, safeguarding precision. */ + if ( fabs(tt1) > fabs(tt2) ) { + *tai1 = tt1; + *tai2 = tt2 - dtat; + } else { + *tai1 = tt1 - dtat; + *tai2 = tt2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tttcg.c b/src/cpp/3rdparty/sofa/src/tttcg.c new file mode 100644 index 000000000..8f667c2eb --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tttcg.c @@ -0,0 +1,165 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTttcg(double tt1, double tt2, double *tcg1, double *tcg2) +/* +** - - - - - - - - - +** i a u T t t c g +** - - - - - - - - - +** +** Time scale transformation: Terrestrial Time, TT, to Geocentric +** Coordinate Time, TCG. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tt1,tt2 double TT as a 2-part Julian Date +** +** Returned: +** tcg1,tcg2 double TCG as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Note: +** +** tt1+tt2 is Julian Date, apportioned in any convenient way between +** the two arguments, for example where tt1 is the Julian Day Number +** and tt2 is the fraction of a day. The returned tcg1,tcg2 follow +** suit. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** IAU 2000 Resolution B1.9 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* 1977 Jan 1 00:00:32.184 TT, as MJD */ + static const double t77t = DJM77 + TTMTAI/DAYSEC; + +/* TT to TCG rate */ + static const double elgg = ELG/(1.0-ELG); + + +/* Result, safeguarding precision. */ + if ( fabs(tt1) > fabs(tt2) ) { + *tcg1 = tt1; + *tcg2 = tt2 + ( ( tt1 - DJM0 ) + ( tt2 - t77t ) ) * elgg; + } else { + *tcg1 = tt1 + ( ( tt2 - DJM0 ) + ( tt1 - t77t ) ) * elgg; + *tcg2 = tt2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/tttdb.c b/src/cpp/3rdparty/sofa/src/tttdb.c new file mode 100644 index 000000000..e11564f99 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/tttdb.c @@ -0,0 +1,174 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTttdb(double tt1, double tt2, double dtr, + double *tdb1, double *tdb2) +/* +** - - - - - - - - - +** i a u T t t d b +** - - - - - - - - - +** +** Time scale transformation: Terrestrial Time, TT, to Barycentric +** Dynamical Time, TDB. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tt1,tt2 double TT as a 2-part Julian Date +** dtr double TDB-TT in seconds +** +** Returned: +** tdb1,tdb2 double TDB as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) tt1+tt2 is Julian Date, apportioned in any convenient way between +** the two arguments, for example where tt1 is the Julian Day Number +** and tt2 is the fraction of a day. The returned tdb1,tdb2 follow +** suit. +** +** 2) The argument dtr represents the quasi-periodic component of the +** GR transformation between TT and TCB. It is dependent upon the +** adopted solar-system ephemeris, and can be obtained by numerical +** integration, by interrogating a precomputed time ephemeris or by +** evaluating a model such as that implemented in the SOFA function +** iauDtdb. The quantity is dominated by an annual term of 1.7 ms +** amplitude. +** +** 3) TDB is essentially the same as Teph, the time argument for the JPL +** solar system ephemerides. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** IAU 2006 Resolution 3 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dtrd; + + +/* Result, safeguarding precision. */ + dtrd = dtr / DAYSEC; + if ( fabs(tt1) > fabs(tt2) ) { + *tdb1 = tt1; + *tdb2 = tt2 + dtrd; + } else { + *tdb1 = tt1 + dtrd; + *tdb2 = tt2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ttut1.c b/src/cpp/3rdparty/sofa/src/ttut1.c new file mode 100644 index 000000000..042f94609 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ttut1.c @@ -0,0 +1,163 @@ +#include "sofa.h" +#include "sofam.h" + +int iauTtut1(double tt1, double tt2, double dt, + double *ut11, double *ut12) +/* +** - - - - - - - - - +** i a u T t u t 1 +** - - - - - - - - - +** +** Time scale transformation: Terrestrial Time, TT, to Universal Time, +** UT1. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** tt1,tt2 double TT as a 2-part Julian Date +** dt double TT-UT1 in seconds +** +** Returned: +** ut11,ut12 double UT1 as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) tt1+tt2 is Julian Date, apportioned in any convenient way between +** the two arguments, for example where tt1 is the Julian Day Number +** and tt2 is the fraction of a day. The returned ut11,ut12 follow +** suit. +** +** 2) The argument dt is classical Delta T. +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dtd; + + +/* Result, safeguarding precision. */ + dtd = dt / DAYSEC; + if ( fabs(tt1) > fabs(tt2) ) { + *ut11 = tt1; + *ut12 = tt2 - dtd; + } else { + *ut11 = tt1 - dtd; + *ut12 = tt2; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ut1tai.c b/src/cpp/3rdparty/sofa/src/ut1tai.c new file mode 100644 index 000000000..9909ce159 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ut1tai.c @@ -0,0 +1,164 @@ +#include "sofa.h" +#include "sofam.h" + +int iauUt1tai(double ut11, double ut12, double dta, + double *tai1, double *tai2) +/* +** - - - - - - - - - - +** i a u U t 1 t a i +** - - - - - - - - - - +** +** Time scale transformation: Universal Time, UT1, to International +** Atomic Time, TAI. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** ut11,ut12 double UT1 as a 2-part Julian Date +** dta double UT1-TAI in seconds +** +** Returned: +** tai1,tai2 double TAI as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) ut11+ut12 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where ut11 is the Julian +** Day Number and ut12 is the fraction of a day. The returned +** tai1,tai2 follow suit. +** +** 2) The argument dta, i.e. UT1-TAI, is an observed quantity, and is +** available from IERS tabulations. +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dtad; + + +/* Result, safeguarding precision. */ + dtad = dta / DAYSEC; + if ( fabs(ut11) > fabs(ut12) ) { + *tai1 = ut11; + *tai2 = ut12 - dtad; + } else { + *tai1 = ut11 - dtad; + *tai2 = ut12; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ut1tt.c b/src/cpp/3rdparty/sofa/src/ut1tt.c new file mode 100644 index 000000000..a2ad4fe48 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ut1tt.c @@ -0,0 +1,163 @@ +#include "sofa.h" +#include "sofam.h" + +int iauUt1tt(double ut11, double ut12, double dt, + double *tt1, double *tt2) +/* +** - - - - - - - - - +** i a u U t 1 t t +** - - - - - - - - - +** +** Time scale transformation: Universal Time, UT1, to Terrestrial +** Time, TT. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** ut11,ut12 double UT1 as a 2-part Julian Date +** dt double TT-UT1 in seconds +** +** Returned: +** tt1,tt2 double TT as a 2-part Julian Date +** +** Returned (function value): +** int status: 0 = OK +** +** Notes: +** +** 1) ut11+ut12 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where ut11 is the Julian +** Day Number and ut12 is the fraction of a day. The returned +** tt1,tt2 follow suit. +** +** 2) The argument dt is classical Delta T. +** +** Reference: +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double dtd; + + +/* Result, safeguarding precision. */ + dtd = dt / DAYSEC; + if ( fabs(ut11) > fabs(ut12) ) { + *tt1 = ut11; + *tt2 = ut12 + dtd; + } else { + *tt1 = ut11 + dtd; + *tt2 = ut12; + } + +/* Status (always OK). */ + return 0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/ut1utc.c b/src/cpp/3rdparty/sofa/src/ut1utc.c new file mode 100644 index 000000000..08ff68ab4 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/ut1utc.c @@ -0,0 +1,246 @@ +#include "sofa.h" +#include "sofam.h" + +int iauUt1utc(double ut11, double ut12, double dut1, + double *utc1, double *utc2) +/* +** - - - - - - - - - - +** i a u U t 1 u t c +** - - - - - - - - - - +** +** Time scale transformation: Universal Time, UT1, to Coordinated +** Universal Time, UTC. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** ut11,ut12 double UT1 as a 2-part Julian Date (Note 1) +** dut1 double Delta UT1: UT1-UTC in seconds (Note 2) +** +** Returned: +** utc1,utc2 double UTC as a 2-part quasi Julian Date (Notes 3,4) +** +** Returned (function value): +** int status: +1 = dubious year (Note 5) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) ut11+ut12 is Julian Date, apportioned in any convenient way +** between the two arguments, for example where ut11 is the Julian +** Day Number and ut12 is the fraction of a day. The returned utc1 +** and utc2 form an analogous pair, except that a special convention +** is used, to deal with the problem of leap seconds - see Note 3. +** +** 2) Delta UT1 can be obtained from tabulations provided by the +** International Earth Rotation and Reference Systems Service. The +** value changes abruptly by 1s at a leap second; however, close to +** a leap second the algorithm used here is tolerant of the "wrong" +** choice of value being made. +** +** 3) JD cannot unambiguously represent UTC during a leap second unless +** special measures are taken. The convention in the present +** function is that the returned quasi-JD UTC1+UTC2 represents UTC +** days whether the length is 86399, 86400 or 86401 SI seconds. +** +** 4) The function iauD2dtf can be used to transform the UTC quasi-JD +** into calendar date and clock time, including UTC leap second +** handling. +** +** 5) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the future +** to be trusted. See iauDat for further details. +** +** Called: +** iauJd2cal JD to Gregorian calendar +** iauDat delta(AT) = TAI-UTC +** iauCal2jd Gregorian calendar to JD +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int big1; + int i, iy, im, id, js; + double duts, u1, u2, d1, dats1, d2, fd, dats2, ddats, us1, us2, du; + + +/* UT1-UTC in seconds. */ + duts = dut1; + +/* Put the two parts of the UT1 into big-first order. */ + big1 = ( fabs(ut11) >= fabs(ut12) ); + if ( big1 ) { + u1 = ut11; + u2 = ut12; + } else { + u1 = ut12; + u2 = ut11; + } + +/* See if the UT1 can possibly be in a leap-second day. */ + d1 = u1; + dats1 = 0; + for ( i = -1; i <= 3; i++ ) { + d2 = u2 + (double) i; + if ( iauJd2cal(d1, d2, &iy, &im, &id, &fd) ) return -1; + js = iauDat(iy, im, id, 0.0, &dats2); + if ( js < 0 ) return -1; + if ( i == - 1 ) dats1 = dats2; + ddats = dats2 - dats1; + if ( fabs(ddats) >= 0.5 ) { + + /* Yes, leap second nearby: ensure UT1-UTC is "before" value. */ + if ( ddats * duts >= 0 ) duts -= ddats; + + /* UT1 for the start of the UTC day that ends in a leap. */ + if ( iauCal2jd(iy, im, id, &d1, &d2) ) return -1; + us1 = d1; + us2 = d2 - 1.0 + duts/DAYSEC; + + /* Is the UT1 after this point? */ + du = u1 - us1; + du += u2 - us2; + if ( du > 0 ) { + + /* Yes: fraction of the current UTC day that has elapsed. */ + fd = du * DAYSEC / ( DAYSEC + ddats ); + + /* Ramp UT1-UTC to bring about SOFA's JD(UTC) convention. */ + duts += ddats * ( fd <= 1.0 ? fd : 1.0 ); + } + + /* Done. */ + break; + } + dats1 = dats2; + } + +/* Subtract the (possibly adjusted) UT1-UTC from UT1 to give UTC. */ + u2 -= duts / DAYSEC; + +/* Result, safeguarding precision. */ + if ( big1 ) { + *utc1 = u1; + *utc2 = u2; + } else { + *utc1 = u2; + *utc2 = u1; + } + +/* Status. */ + return js; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/utctai.c b/src/cpp/3rdparty/sofa/src/utctai.c new file mode 100644 index 000000000..a005d1f68 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/utctai.c @@ -0,0 +1,231 @@ +#include "sofa.h" +#include "sofam.h" + +int iauUtctai(double utc1, double utc2, double *tai1, double *tai2) +/* +** - - - - - - - - - - +** i a u U t c t a i +** - - - - - - - - - - +** +** Time scale transformation: Coordinated Universal Time, UTC, to +** International Atomic Time, TAI. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** utc1,utc2 double UTC as a 2-part quasi Julian Date (Notes 1-4) +** +** Returned: +** tai1,tai2 double TAI as a 2-part Julian Date (Note 5) +** +** Returned (function value): +** int status: +1 = dubious year (Note 3) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** 2) JD cannot unambiguously represent UTC during a leap second unless +** special measures are taken. The convention in the present +** function is that the JD day represents UTC days whether the +** length is 86399, 86400 or 86401 SI seconds. In the 1960-1972 era +** there were smaller jumps (in either direction) each time the +** linear UTC(TAI) expression was changed, and these "mini-leaps" +** are also included in the SOFA convention. +** +** 3) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the future +** to be trusted. See iauDat for further details. +** +** 4) The function iauDtf2d converts from calendar date and time of day +** into 2-part Julian Date, and in the case of UTC implements the +** leap-second-ambiguity convention described above. +** +** 5) The returned TAI1,TAI2 are such that their sum is the TAI Julian +** Date. +** +** Called: +** iauJd2cal JD to Gregorian calendar +** iauDat delta(AT) = TAI-UTC +** iauCal2jd Gregorian calendar to JD +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +** +*/ +{ + int big1; + int iy, im, id, j, iyt, imt, idt; + double u1, u2, fd, dat0, dat12, w, dat24, dlod, dleap, z1, z2, a2; + + +/* Put the two parts of the UTC into big-first order. */ + big1 = ( fabs(utc1) >= fabs(utc2) ); + if ( big1 ) { + u1 = utc1; + u2 = utc2; + } else { + u1 = utc2; + u2 = utc1; + } + +/* Get TAI-UTC at 0h today. */ + j = iauJd2cal(u1, u2, &iy, &im, &id, &fd); + if ( j ) return j; + j = iauDat(iy, im, id, 0.0, &dat0); + if ( j < 0 ) return j; + +/* Get TAI-UTC at 12h today (to detect drift). */ + j = iauDat(iy, im, id, 0.5, &dat12); + if ( j < 0 ) return j; + +/* Get TAI-UTC at 0h tomorrow (to detect jumps). */ + j = iauJd2cal(u1+1.5, u2-fd, &iyt, &imt, &idt, &w); + if ( j ) return j; + j = iauDat(iyt, imt, idt, 0.0, &dat24); + if ( j < 0 ) return j; + +/* Separate TAI-UTC change into per-day (DLOD) and any jump (DLEAP). */ + dlod = 2.0 * (dat12 - dat0); + dleap = dat24 - (dat0 + dlod); + +/* Remove any scaling applied to spread leap into preceding day. */ + fd *= (DAYSEC+dleap)/DAYSEC; + +/* Scale from (pre-1972) UTC seconds to SI seconds. */ + fd *= (DAYSEC+dlod)/DAYSEC; + +/* Today's calendar date to 2-part JD. */ + if ( iauCal2jd(iy, im, id, &z1, &z2) ) return -1; + +/* Assemble the TAI result, preserving the UTC split and order. */ + a2 = z1 - u1; + a2 += z2; + a2 += fd + dat0/DAYSEC; + if ( big1 ) { + *tai1 = u1; + *tai2 = a2; + } else { + *tai1 = a2; + *tai2 = u1; + } + +/* Status. */ + return j; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/utcut1.c b/src/cpp/3rdparty/sofa/src/utcut1.c new file mode 100644 index 000000000..b3970dd2f --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/utcut1.c @@ -0,0 +1,199 @@ +#include "sofa.h" + +int iauUtcut1(double utc1, double utc2, double dut1, + double *ut11, double *ut12) +/* +** - - - - - - - - - - +** i a u U t c u t 1 +** - - - - - - - - - - +** +** Time scale transformation: Coordinated Universal Time, UTC, to +** Universal Time, UT1. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards of Fundamental Astronomy) software collection. +** +** Status: canonical. +** +** Given: +** utc1,utc2 double UTC as a 2-part quasi Julian Date (Notes 1-4) +** dut1 double Delta UT1 = UT1-UTC in seconds (Note 5) +** +** Returned: +** ut11,ut12 double UT1 as a 2-part Julian Date (Note 6) +** +** Returned (function value): +** int status: +1 = dubious year (Note 3) +** 0 = OK +** -1 = unacceptable date +** +** Notes: +** +** 1) utc1+utc2 is quasi Julian Date (see Note 2), apportioned in any +** convenient way between the two arguments, for example where utc1 +** is the Julian Day Number and utc2 is the fraction of a day. +** +** 2) JD cannot unambiguously represent UTC during a leap second unless +** special measures are taken. The convention in the present +** function is that the JD day represents UTC days whether the +** length is 86399, 86400 or 86401 SI seconds. +** +** 3) The warning status "dubious year" flags UTCs that predate the +** introduction of the time scale or that are too far in the future +** to be trusted. See iauDat for further details. +** +** 4) The function iauDtf2d converts from calendar date and time of +** day into 2-part Julian Date, and in the case of UTC implements +** the leap-second-ambiguity convention described above. +** +** 5) Delta UT1 can be obtained from tabulations provided by the +** International Earth Rotation and Reference Systems Service. +** It is the caller's responsibility to supply a dut1 argument +** containing the UT1-UTC value that matches the given UTC. +** +** 6) The returned ut11,ut12 are such that their sum is the UT1 Julian +** Date. +** +** References: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** Explanatory Supplement to the Astronomical Almanac, +** P. Kenneth Seidelmann (ed), University Science Books (1992) +** +** Called: +** iauJd2cal JD to Gregorian calendar +** iauDat delta(AT) = TAI-UTC +** iauUtctai UTC to TAI +** iauTaiut1 TAI to UT1 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + int iy, im, id, js, jw; + double w, dat, dta, tai1, tai2; + + +/* Look up TAI-UTC. */ + if ( iauJd2cal(utc1, utc2, &iy, &im, &id, &w) ) return -1; + js = iauDat ( iy, im, id, 0.0, &dat); + if ( js < 0 ) return -1; + +/* Form UT1-TAI. */ + dta = dut1 - dat; + +/* UTC to TAI to UT1. */ + jw = iauUtctai(utc1, utc2, &tai1, &tai2); + if ( jw < 0 ) { + return -1; + } else if ( jw > 0 ) { + js = jw; + } + if ( iauTaiut1(tai1, tai2, dta, ut11, ut12) ) return -1; + +/* Status. */ + return js; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/xy06.c b/src/cpp/3rdparty/sofa/src/xy06.c new file mode 100644 index 000000000..6f3155acf --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/xy06.c @@ -0,0 +1,2809 @@ +#include "sofa.h" +#include "sofam.h" + +void iauXy06(double date1, double date2, double *x, double *y) +/* +** - - - - - - - - +** i a u X y 0 6 +** - - - - - - - - +** +** X,Y coordinates of celestial intermediate pole from series based +** on IAU 2006 precession and IAU 2000A nutation. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: canonical model. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** x,y double CIP X,Y coordinates (Note 2) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The X,Y coordinates are those of the unit vector towards the +** celestial intermediate pole. They represent the combined effects +** of frame bias, precession and nutation. +** +** 3) The fundamental arguments used are as adopted in IERS Conventions +** (2003) and are from Simon et al. (1994) and Souchay et al. +** (1999). +** +** 4) This is an alternative to the angles-based method, via the SOFA +** function iauFw2xy and as used in iauXys06a for example. The two +** methods agree at the 1 microarcsecond level (at present), a +** negligible amount compared with the intrinsic accuracy of the +** models. However, it would be unwise to mix the two methods +** (angles-based and series-based) in a single application. +** +** Called: +** iauFal03 mean anomaly of the Moon +** iauFalp03 mean anomaly of the Sun +** iauFaf03 mean argument of the latitude of the Moon +** iauFad03 mean elongation of the Moon from the Sun +** iauFaom03 mean longitude of the Moon's ascending node +** iauFame03 mean longitude of Mercury +** iauFave03 mean longitude of Venus +** iauFae03 mean longitude of Earth +** iauFama03 mean longitude of Mars +** iauFaju03 mean longitude of Jupiter +** iauFasa03 mean longitude of Saturn +** iauFaur03 mean longitude of Uranus +** iauFane03 mean longitude of Neptune +** iauFapa03 general accumulated precession in longitude +** +** References: +** +** Capitaine, N., Wallace, P.T. & Chapront, J., 2003, +** Astron.Astrophys., 412, 567 +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** McCarthy, D. D., Petit, G. (eds.), 2004, IERS Conventions (2003), +** IERS Technical Note No. 32, BKG +** +** Simon, J.L., Bretagnon, P., Chapront, J., Chapront-Touze, M., +** Francou, G. & Laskar, J., Astron.Astrophys., 1994, 282, 663 +** +** Souchay, J., Loysel, B., Kinoshita, H., Folgueira, M., 1999, +** Astron.Astrophys.Supp.Ser. 135, 111 +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + +/* Maximum power of T in the polynomials for X and Y */ + enum { MAXPT = 5 }; + +/* Polynomial coefficients (arcsec, X then Y). */ + static const double xyp[2][MAXPT+1] = { + + { -0.016617, + 2004.191898, + -0.4297829, + -0.19861834, + 0.000007578, + 0.0000059285 + }, + { -0.006951, + -0.025896, + -22.4072747, + 0.00190059, + 0.001112526, + 0.0000001358 + } + }; + +/* Fundamental-argument multipliers: luni-solar terms */ + static const int mfals[][5] = { + + /* 1-10 */ + { 0, 0, 0, 0, 1 }, + { 0, 0, 2, -2, 2 }, + { 0, 0, 2, 0, 2 }, + { 0, 0, 0, 0, 2 }, + { 0, 1, 0, 0, 0 }, + { 0, 1, 2, -2, 2 }, + { 1, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 1 }, + { 1, 0, 2, 0, 2 }, + { 0, 1, -2, 2, -2 }, + + /* 11-20 */ + { 0, 0, 2, -2, 1 }, + { 1, 0, -2, 0, -2 }, + { 1, 0, 0, -2, 0 }, + { 1, 0, 0, 0, 1 }, + { 1, 0, 0, 0, -1 }, + { 1, 0, -2, -2, -2 }, + { 1, 0, 2, 0, 1 }, + { 2, 0, -2, 0, -1 }, + { 0, 0, 0, 2, 0 }, + { 0, 0, 2, 2, 2 }, + + /* 21-30 */ + { 2, 0, 0, -2, 0 }, + { 0, 2, -2, 2, -2 }, + { 2, 0, 2, 0, 2 }, + { 1, 0, 2, -2, 2 }, + { 1, 0, -2, 0, -1 }, + { 2, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 0 }, + { 0, 1, 0, 0, 1 }, + { 1, 0, 0, -2, -1 }, + { 0, 2, 2, -2, 2 }, + + /* 31-40 */ + { 0, 0, 2, -2, 0 }, + { 1, 0, 0, -2, 1 }, + { 0, 1, 0, 0, -1 }, + { 0, 2, 0, 0, 0 }, + { 1, 0, -2, -2, -1 }, + { 1, 0, 2, 2, 2 }, + { 0, 1, 2, 0, 2 }, + { 2, 0, -2, 0, 0 }, + { 0, 0, 2, 2, 1 }, + { 0, 1, -2, 0, -2 }, + + /* 41-50 */ + { 0, 0, 0, 2, 1 }, + { 1, 0, 2, -2, 1 }, + { 2, 0, 0, -2, -1 }, + { 2, 0, 2, -2, 2 }, + { 2, 0, 2, 0, 1 }, + { 0, 0, 0, 2, -1 }, + { 0, 1, -2, 2, -1 }, + { 1, 1, 0, -2, 0 }, + { 2, 0, 0, -2, 1 }, + { 1, 0, 0, 2, 0 }, + + /* 51-60 */ + { 0, 1, 2, -2, 1 }, + { 1, -1, 0, 0, 0 }, + { 0, 1, -1, 1, -1 }, + { 2, 0, -2, 0, -2 }, + { 0, 1, 0, -2, 0 }, + { 1, 0, 0, -1, 0 }, + { 3, 0, 2, 0, 2 }, + { 0, 0, 0, 1, 0 }, + { 1, -1, 2, 0, 2 }, + { 1, 1, -2, -2, -2 }, + + /* 61-70 */ + { 1, 0, -2, 0, 0 }, + { 2, 0, 0, 0, -1 }, + { 0, 1, -2, -2, -2 }, + { 1, 1, 2, 0, 2 }, + { 2, 0, 0, 0, 1 }, + { 1, 1, 0, 0, 0 }, + { 1, 0, -2, 2, -1 }, + { 1, 0, 2, 0, 0 }, + { 1, -1, 0, -1, 0 }, + { 1, 0, 0, 0, 2 }, + + /* 71-80 */ + { 1, 0, -1, 0, -1 }, + { 0, 0, 2, 1, 2 }, + { 1, 0, -2, -4, -2 }, + { 1, -1, 0, -1, -1 }, + { 1, 0, 2, 2, 1 }, + { 0, 2, -2, 2, -1 }, + { 1, 0, 0, 0, -2 }, + { 2, 0, -2, -2, -2 }, + { 1, 1, 2, -2, 2 }, + { 2, 0, -2, -4, -2 }, + + /* 81-90 */ + { 1, 0, -4, 0, -2 }, + { 2, 0, 2, -2, 1 }, + { 1, 0, 0, -1, -1 }, + { 2, 0, 2, 2, 2 }, + { 3, 0, 0, 0, 0 }, + { 1, 0, 0, 2, 1 }, + { 0, 0, 2, -2, -1 }, + { 3, 0, 2, -2, 2 }, + { 0, 0, 4, -2, 2 }, + { 1, 0, 0, -4, 0 }, + + /* 91-100 */ + { 0, 1, 2, 0, 1 }, + { 2, 0, 0, -4, 0 }, + { 1, 1, 0, -2, -1 }, + { 2, 0, -2, 0, 1 }, + { 0, 0, 2, 0, -1 }, + { 0, 1, -2, 0, -1 }, + { 0, 1, 0, 0, 2 }, + { 0, 0, 2, -1, 2 }, + { 0, 0, 2, 4, 2 }, + { 2, 1, 0, -2, 0 }, + + /* 101-110 */ + { 1, 1, 0, -2, 1 }, + { 1, -1, 0, -2, 0 }, + { 1, -1, 0, -1, -2 }, + { 1, -1, 0, 0, 1 }, + { 0, 1, -2, 2, 0 }, + { 0, 1, 0, 0, -2 }, + { 1, -1, 2, 2, 2 }, + { 1, 0, 0, 2, -1 }, + { 1, -1, -2, -2, -2 }, + { 3, 0, 2, 0, 1 }, + + /* 111-120 */ + { 0, 1, 2, 2, 2 }, + { 1, 0, 2, -2, 0 }, + { 1, 1, -2, -2, -1 }, + { 1, 0, 2, -4, 1 }, + { 0, 1, -2, -2, -1 }, + { 2, -1, 2, 0, 2 }, + { 0, 0, 0, 2, 2 }, + { 1, -1, 2, 0, 1 }, + { 1, -1, -2, 0, -2 }, + { 0, 1, 0, 2, 0 }, + + /* 121-130 */ + { 0, 1, 2, -2, 0 }, + { 0, 0, 0, 1, 1 }, + { 1, 0, -2, -2, 0 }, + { 0, 3, 2, -2, 2 }, + { 2, 1, 2, 0, 2 }, + { 1, 1, 0, 0, 1 }, + { 2, 0, 0, 2, 0 }, + { 1, 1, 2, 0, 1 }, + { 1, 0, 0, -2, -2 }, + { 1, 0, -2, 2, 0 }, + + /* 131-140 */ + { 1, 0, -1, 0, -2 }, + { 0, 1, 0, -2, 1 }, + { 0, 1, 0, 1, 0 }, + { 0, 0, 0, 1, -1 }, + { 1, 0, -2, 2, -2 }, + { 1, -1, 0, 0, -1 }, + { 0, 0, 0, 4, 0 }, + { 1, -1, 0, 2, 0 }, + { 1, 0, 2, 1, 2 }, + { 1, 0, 2, -1, 2 }, + + /* 141-150 */ + { 0, 0, 2, 1, 1 }, + { 1, 0, 0, -2, 2 }, + { 1, 0, -2, 0, 1 }, + { 1, 0, -2, -4, -1 }, + { 0, 0, 2, 2, 0 }, + { 1, 1, 2, -2, 1 }, + { 1, 0, -2, 1, -1 }, + { 0, 0, 1, 0, 1 }, + { 2, 0, -2, -2, -1 }, + { 4, 0, 2, 0, 2 }, + + /* 151-160 */ + { 2, -1, 0, 0, 0 }, + { 2, 1, 2, -2, 2 }, + { 0, 1, 2, 1, 2 }, + { 1, 0, 4, -2, 2 }, + { 1, 1, 0, 0, -1 }, + { 2, 0, 2, 0, 0 }, + { 2, 0, -2, -4, -1 }, + { 1, 0, -1, 0, 0 }, + { 1, 0, 0, 1, 0 }, + { 0, 1, 0, 2, 1 }, + + /* 161-170 */ + { 1, 0, -4, 0, -1 }, + { 1, 0, 0, -4, -1 }, + { 2, 0, 2, 2, 1 }, + { 2, 1, 0, 0, 0 }, + { 0, 0, 2, -3, 2 }, + { 1, 2, 0, -2, 0 }, + { 0, 3, 0, 0, 0 }, + { 0, 0, 4, 0, 2 }, + { 0, 0, 2, -4, 1 }, + { 2, 0, 0, -2, -2 }, + + /* 171-180 */ + { 1, 1, -2, -4, -2 }, + { 0, 1, 0, -2, -1 }, + { 0, 0, 0, 4, 1 }, + { 3, 0, 2, -2, 1 }, + { 1, 0, 2, 4, 2 }, + { 1, 1, -2, 0, -2 }, + { 0, 0, 4, -2, 1 }, + { 2, -2, 0, -2, 0 }, + { 2, 1, 0, -2, -1 }, + { 0, 2, 0, -2, 0 }, + + /* 181-190 */ + { 1, 0, 0, -1, 1 }, + { 1, 1, 2, 2, 2 }, + { 3, 0, 0, 0, -1 }, + { 2, 0, 0, -4, -1 }, + { 3, 0, 2, 2, 2 }, + { 0, 0, 2, 4, 1 }, + { 0, 2, -2, -2, -2 }, + { 1, -1, 0, -2, -1 }, + { 0, 0, 2, -1, 1 }, + { 2, 0, 0, 2, 1 }, + + /* 191-200 */ + { 1, -1, -2, 2, -1 }, + { 0, 0, 0, 2, -2 }, + { 2, 0, 0, -4, 1 }, + { 1, 0, 0, -4, 1 }, + { 2, 0, 2, -4, 1 }, + { 4, 0, 2, -2, 2 }, + { 2, 1, -2, 0, -1 }, + { 2, 1, -2, -4, -2 }, + { 3, 0, 0, -4, 0 }, + { 1, -1, 2, 2, 1 }, + + /* 201-210 */ + { 1, -1, -2, 0, -1 }, + { 0, 2, 0, 0, 1 }, + { 1, 2, -2, -2, -2 }, + { 1, 1, 0, -4, 0 }, + { 2, 0, 0, -2, 2 }, + { 0, 2, 2, -2, 1 }, + { 1, 0, 2, 0, -1 }, + { 2, 1, 0, -2, 1 }, + { 2, -1, -2, 0, -1 }, + { 1, -1, -2, -2, -1 }, + + /* 211-220 */ + { 0, 1, -2, 1, -2 }, + { 1, 0, -4, 2, -2 }, + { 0, 1, 2, 2, 1 }, + { 3, 0, 0, 0, 1 }, + { 2, -1, 2, 2, 2 }, + { 0, 1, -2, -4, -2 }, + { 1, 0, -2, -3, -2 }, + { 2, 0, 0, 0, 2 }, + { 1, -1, 0, -2, -2 }, + { 2, 0, -2, 2, -1 }, + + /* 221-230 */ + { 0, 2, -2, 0, -2 }, + { 3, 0, -2, 0, -1 }, + { 2, -1, 2, 0, 1 }, + { 1, 0, -2, -1, -2 }, + { 0, 0, 2, 0, 3 }, + { 2, 0, -4, 0, -2 }, + { 2, 1, 0, -4, 0 }, + { 1, 1, -2, 1, -1 }, + { 0, 2, 2, 0, 2 }, + { 1, -1, 2, -2, 2 }, + + /* 231-240 */ + { 1, -1, 0, -2, 1 }, + { 2, 1, 2, 0, 1 }, + { 1, 0, 2, -4, 2 }, + { 1, 1, -2, 0, -1 }, + { 1, 1, 0, 2, 0 }, + { 1, 0, 0, -3, 0 }, + { 2, 0, 2, -1, 2 }, + { 0, 2, 0, 0, -1 }, + { 2, -1, 0, -2, 0 }, + { 4, 0, 0, 0, 0 }, + + /* 241-250 */ + { 2, 1, -2, -2, -2 }, + { 0, 2, -2, 2, 0 }, + { 1, 0, 2, 1, 1 }, + { 1, 0, -1, 0, -3 }, + { 3, -1, 2, 0, 2 }, + { 2, 0, 2, -2, 0 }, + { 1, -2, 0, 0, 0 }, + { 2, 0, 0, 0, -2 }, + { 1, 0, 0, 4, 0 }, + { 0, 1, 0, 1, 1 }, + + /* 251-260 */ + { 1, 0, 2, 2, 0 }, + { 0, 1, 0, 2, -1 }, + { 0, 1, 0, 1, -1 }, + { 0, 0, 2, -2, 3 }, + { 3, 1, 2, 0, 2 }, + { 1, 1, 2, 1, 2 }, + { 1, 1, -2, 2, -1 }, + { 2, -1, 2, -2, 2 }, + { 1, -2, 2, 0, 2 }, + { 1, 0, 2, -4, 0 }, + + /* 261-270 */ + { 0, 0, 1, 0, 0 }, + { 1, 0, 2, -3, 1 }, + { 1, -2, 0, -2, 0 }, + { 2, 0, 0, 2, -1 }, + { 1, 1, 2, -4, 1 }, + { 4, 0, 2, 0, 1 }, + { 0, 1, 2, 1, 1 }, + { 1, 2, 2, -2, 2 }, + { 2, 0, 2, 1, 2 }, + { 2, 1, 2, -2, 1 }, + + /* 271-280 */ + { 1, 0, 2, -1, 1 }, + { 1, 0, 4, -2, 1 }, + { 1, -1, 2, -2, 1 }, + { 0, 1, 0, -4, 0 }, + { 3, 0, -2, -2, -2 }, + { 0, 0, 4, -4, 2 }, + { 2, 0, -4, -2, -2 }, + { 2, -2, 0, -2, -1 }, + { 1, 0, 2, -2, -1 }, + { 2, 0, -2, -6, -2 }, + + /* 281-290 */ + { 1, 0, -2, 1, -2 }, + { 1, 0, -2, 2, 1 }, + { 1, -1, 0, 2, -1 }, + { 1, 0, -2, 1, 0 }, + { 2, -1, 0, -2, 1 }, + { 1, -1, 0, 2, 1 }, + { 2, 0, -2, -2, 0 }, + { 1, 0, 2, -3, 2 }, + { 0, 0, 0, 4, -1 }, + { 2, -1, 0, 0, 1 }, + + /* 291-300 */ + { 2, 0, 4, -2, 2 }, + { 0, 0, 2, 3, 2 }, + { 0, 1, 4, -2, 2 }, + { 0, 1, -2, 2, 1 }, + { 1, 1, 0, 2, 1 }, + { 1, 0, 0, 4, 1 }, + { 0, 0, 4, 0, 1 }, + { 2, 0, 0, -3, 0 }, + { 1, 0, 0, -1, -2 }, + { 1, -2, -2, -2, -2 }, + + /* 301-310 */ + { 3, 0, 0, 2, 0 }, + { 2, 0, 2, -4, 2 }, + { 1, 1, -2, -4, -1 }, + { 1, 0, -2, -6, -2 }, + { 2, -1, 0, 0, -1 }, + { 2, -1, 0, 2, 0 }, + { 0, 1, 2, -2, -1 }, + { 1, 1, 0, 1, 0 }, + { 1, 2, 0, -2, -1 }, + { 1, 0, 0, 1, -1 }, + + /* 311-320 */ + { 0, 0, 1, 0, 2 }, + { 3, 1, 2, -2, 2 }, + { 1, 0, -4, -2, -2 }, + { 1, 0, 2, 4, 1 }, + { 1, -2, 2, 2, 2 }, + { 1, -1, -2, -4, -2 }, + { 0, 0, 2, -4, 2 }, + { 0, 0, 2, -3, 1 }, + { 2, 1, -2, 0, 0 }, + { 3, 0, -2, -2, -1 }, + + /* 321-330 */ + { 2, 0, 2, 4, 2 }, + { 0, 0, 0, 0, 3 }, + { 2, -1, -2, -2, -2 }, + { 2, 0, 0, -1, 0 }, + { 3, 0, 2, -4, 2 }, + { 2, 1, 2, 2, 2 }, + { 0, 0, 3, 0, 3 }, + { 1, 1, 2, 2, 1 }, + { 2, 1, 0, 0, -1 }, + { 1, 2, 0, -2, 1 }, + + /* 331-340 */ + { 3, 0, 2, 2, 1 }, + { 1, -1, -2, 2, -2 }, + { 1, 1, 0, -1, 0 }, + { 1, 2, 0, 0, 0 }, + { 1, 0, 4, 0, 2 }, + { 1, -1, 2, 4, 2 }, + { 2, 1, 0, 0, 1 }, + { 1, 0, 0, 2, 2 }, + { 1, -1, -2, 2, 0 }, + { 0, 2, -2, -2, -1 }, + + /* 341-350 */ + { 2, 0, -2, 0, 2 }, + { 5, 0, 2, 0, 2 }, + { 3, 0, -2, -6, -2 }, + { 1, -1, 2, -1, 2 }, + { 3, 0, 0, -4, -1 }, + { 1, 0, 0, 1, 1 }, + { 1, 0, -4, 2, -1 }, + { 0, 1, 2, -4, 1 }, + { 1, 2, 2, 0, 2 }, + { 0, 1, 0, -2, -2 }, + + /* 351-360 */ + { 0, 0, 2, -1, 0 }, + { 1, 0, 1, 0, 1 }, + { 0, 2, 0, -2, 1 }, + { 3, 0, 2, 0, 0 }, + { 1, 1, -2, 1, 0 }, + { 2, 1, -2, -4, -1 }, + { 3, -1, 0, 0, 0 }, + { 2, -1, -2, 0, 0 }, + { 4, 0, 2, -2, 1 }, + { 2, 0, -2, 2, 0 }, + + /* 361-370 */ + { 1, 1, 2, -2, 0 }, + { 1, 0, -2, 4, -1 }, + { 1, 0, -2, -2, 1 }, + { 2, 0, 2, -4, 0 }, + { 1, 1, 0, -2, -2 }, + { 1, 1, -2, -2, 0 }, + { 1, 0, 1, -2, 1 }, + { 2, -1, -2, -4, -2 }, + { 3, 0, -2, 0, -2 }, + { 0, 1, -2, -2, 0 }, + + /* 371-380 */ + { 3, 0, 0, -2, -1 }, + { 1, 0, -2, -3, -1 }, + { 0, 1, 0, -4, -1 }, + { 1, -2, 2, -2, 1 }, + { 0, 1, -2, 1, -1 }, + { 1, -1, 0, 0, 2 }, + { 2, 0, 0, 1, 0 }, + { 1, -2, 0, 2, 0 }, + { 1, 2, -2, -2, -1 }, + { 0, 0, 4, -4, 1 }, + + /* 381-390 */ + { 0, 1, 2, 4, 2 }, + { 0, 1, -4, 2, -2 }, + { 3, 0, -2, 0, 0 }, + { 2, -1, 2, 2, 1 }, + { 0, 1, -2, -4, -1 }, + { 4, 0, 2, 2, 2 }, + { 2, 0, -2, -3, -2 }, + { 2, 0, 0, -6, 0 }, + { 1, 0, 2, 0, 3 }, + { 3, 1, 0, 0, 0 }, + + /* 391-400 */ + { 3, 0, 0, -4, 1 }, + { 1, -1, 2, 0, 0 }, + { 1, -1, 0, -4, 0 }, + { 2, 0, -2, 2, -2 }, + { 1, 1, 0, -2, 2 }, + { 4, 0, 0, -2, 0 }, + { 2, 2, 0, -2, 0 }, + { 0, 1, 2, 0, 0 }, + { 1, 1, 0, -4, 1 }, + { 1, 0, 0, -4, -2 }, + + /* 401-410 */ + { 0, 0, 0, 1, 2 }, + { 3, 0, 0, 2, 1 }, + { 1, 1, 0, -4, -1 }, + { 0, 0, 2, 2, -1 }, + { 1, 1, 2, 0, 0 }, + { 1, -1, 2, -4, 1 }, + { 1, 1, 0, 0, 2 }, + { 0, 0, 2, 6, 2 }, + { 4, 0, -2, -2, -1 }, + { 2, 1, 0, -4, -1 }, + + /* 411-420 */ + { 0, 0, 0, 3, 1 }, + { 1, -1, -2, 0, 0 }, + { 0, 0, 2, 1, 0 }, + { 1, 0, 0, 2, -2 }, + { 3, -1, 2, 2, 2 }, + { 3, -1, 2, -2, 2 }, + { 1, 0, 0, -1, 2 }, + { 1, -2, 2, -2, 2 }, + { 0, 1, 0, 2, 2 }, + { 0, 1, -2, -1, -2 }, + + /* 421-430 */ + { 1, 1, -2, 0, 0 }, + { 0, 2, 2, -2, 0 }, + { 3, -1, -2, -1, -2 }, + { 1, 0, 0, -6, 0 }, + { 1, 0, -2, -4, 0 }, + { 2, 1, 0, -4, 1 }, + { 2, 0, 2, 0, -1 }, + { 2, 0, -4, 0, -1 }, + { 0, 0, 3, 0, 2 }, + { 2, 1, -2, -2, -1 }, + + /* 431-440 */ + { 1, -2, 0, 0, 1 }, + { 2, -1, 0, -4, 0 }, + { 0, 0, 0, 3, 0 }, + { 5, 0, 2, -2, 2 }, + { 1, 2, -2, -4, -2 }, + { 1, 0, 4, -4, 2 }, + { 0, 0, 4, -1, 2 }, + { 3, 1, 0, -4, 0 }, + { 3, 0, 0, -6, 0 }, + { 2, 0, 0, 2, 2 }, + + /* 441-450 */ + { 2, -2, 2, 0, 2 }, + { 1, 0, 0, -3, 1 }, + { 1, -2, -2, 0, -2 }, + { 1, -1, -2, -3, -2 }, + { 0, 0, 2, -2, -2 }, + { 2, 0, -2, -4, 0 }, + { 1, 0, -4, 0, 0 }, + { 0, 1, 0, -1, 0 }, + { 4, 0, 0, 0, -1 }, + { 3, 0, 2, -1, 2 }, + + /* 451-460 */ + { 3, -1, 2, 0, 1 }, + { 2, 0, 2, -1, 1 }, + { 1, 2, 2, -2, 1 }, + { 1, 1, 0, 2, -1 }, + { 0, 2, 2, 0, 1 }, + { 3, 1, 2, 0, 1 }, + { 1, 1, 2, 1, 1 }, + { 1, 1, 0, -1, 1 }, + { 1, -2, 0, -2, -1 }, + { 4, 0, 0, -4, 0 }, + + /* 461-470 */ + { 2, 1, 0, 2, 0 }, + { 1, -1, 0, 4, 0 }, + { 0, 1, 0, -2, 2 }, + { 0, 0, 2, 0, -2 }, + { 1, 0, -1, 0, 1 }, + { 3, 0, 2, -2, 0 }, + { 2, 0, 2, 2, 0 }, + { 1, 2, 0, -4, 0 }, + { 1, -1, 0, -3, 0 }, + { 0, 1, 0, 4, 0 }, + + /* 471 - 480 */ + { 0, 1, -2, 0, 0 }, + { 2, 2, 2, -2, 2 }, + { 0, 0, 0, 1, -2 }, + { 0, 2, -2, 0, -1 }, + { 4, 0, 2, -4, 2 }, + { 2, 0, -4, 2, -2 }, + { 2, -1, -2, 0, -2 }, + { 1, 1, 4, -2, 2 }, + { 1, 1, 2, -4, 2 }, + { 1, 0, 2, 3, 2 }, + + /* 481-490 */ + { 1, 0, 0, 4, -1 }, + { 0, 0, 0, 4, 2 }, + { 2, 0, 0, 4, 0 }, + { 1, 1, -2, 2, 0 }, + { 2, 1, 2, 1, 2 }, + { 2, 1, 2, -4, 1 }, + { 2, 0, 2, 1, 1 }, + { 2, 0, -4, -2, -1 }, + { 2, 0, -2, -6, -1 }, + { 2, -1, 2, -1, 2 }, + + /* 491-500 */ + { 1, -2, 2, 0, 1 }, + { 1, -2, 0, -2, 1 }, + { 1, -1, 0, -4, -1 }, + { 0, 2, 2, 2, 2 }, + { 0, 2, -2, -4, -2 }, + { 0, 1, 2, 3, 2 }, + { 0, 1, 0, -4, 1 }, + { 3, 0, 0, -2, 1 }, + { 2, 1, -2, 0, 1 }, + { 2, 0, 4, -2, 1 }, + + /* 501-510 */ + { 2, 0, 0, -3, -1 }, + { 2, -2, 0, -2, 1 }, + { 2, -1, 2, -2, 1 }, + { 1, 0, 0, -6, -1 }, + { 1, -2, 0, 0, -1 }, + { 1, -2, -2, -2, -1 }, + { 0, 1, 4, -2, 1 }, + { 0, 0, 2, 3, 1 }, + { 2, -1, 0, -1, 0 }, + { 1, 3, 0, -2, 0 }, + + /* 511-520 */ + { 0, 3, 0, -2, 0 }, + { 2, -2, 2, -2, 2 }, + { 0, 0, 4, -2, 0 }, + { 4, -1, 2, 0, 2 }, + { 2, 2, -2, -4, -2 }, + { 4, 1, 2, 0, 2 }, + { 4, -1, -2, -2, -2 }, + { 2, 1, 0, -2, -2 }, + { 2, 1, -2, -6, -2 }, + { 2, 0, 0, -1, 1 }, + + /* 521-530 */ + { 2, -1, -2, 2, -1 }, + { 1, 1, -2, 2, -2 }, + { 1, 1, -2, -3, -2 }, + { 1, 0, 3, 0, 3 }, + { 1, 0, -2, 1, 1 }, + { 1, 0, -2, 0, 2 }, + { 1, -1, 2, 1, 2 }, + { 1, -1, 0, 0, -2 }, + { 1, -1, -4, 2, -2 }, + { 0, 3, -2, -2, -2 }, + + /* 531-540 */ + { 0, 1, 0, 4, 1 }, + { 0, 0, 4, 2, 2 }, + { 3, 0, -2, -2, 0 }, + { 2, -2, 0, 0, 0 }, + { 1, 1, 2, -4, 0 }, + { 1, 1, 0, -3, 0 }, + { 1, 0, 2, -3, 0 }, + { 1, -1, 2, -2, 0 }, + { 0, 2, 0, 2, 0 }, + { 0, 0, 2, 4, 0 }, + + /* 541-550 */ + { 1, 0, 1, 0, 0 }, + { 3, 1, 2, -2, 1 }, + { 3, 0, 4, -2, 2 }, + { 3, 0, 2, 1, 2 }, + { 3, 0, 0, 2, -1 }, + { 3, 0, 0, 0, 2 }, + { 3, 0, -2, 2, -1 }, + { 2, 0, 4, -4, 2 }, + { 2, 0, 2, -3, 2 }, + { 2, 0, 0, 4, 1 }, + + /* 551-560 */ + { 2, 0, 0, -3, 1 }, + { 2, 0, -4, 2, -1 }, + { 2, 0, -2, -2, 1 }, + { 2, -2, 2, 2, 2 }, + { 2, -2, 0, -2, -2 }, + { 2, -1, 0, 2, 1 }, + { 2, -1, 0, 2, -1 }, + { 1, 1, 2, 4, 2 }, + { 1, 1, 0, 1, 1 }, + { 1, 1, 0, 1, -1 }, + + /* 561-570 */ + { 1, 1, -2, -6, -2 }, + { 1, 0, 0, -3, -1 }, + { 1, 0, -4, -2, -1 }, + { 1, 0, -2, -6, -1 }, + { 1, -2, 2, 2, 1 }, + { 1, -2, -2, 2, -1 }, + { 1, -1, -2, -4, -1 }, + { 0, 2, 0, 0, 2 }, + { 0, 1, 2, -4, 2 }, + { 0, 1, -2, 4, -1 }, + + /* 571-580 */ + { 5, 0, 0, 0, 0 }, + { 3, 0, 0, -3, 0 }, + { 2, 2, 0, -4, 0 }, + { 1, -1, 2, 2, 0 }, + { 0, 1, 0, 3, 0 }, + { 4, 0, -2, 0, -1 }, + { 3, 0, -2, -6, -1 }, + { 3, 0, -2, -1, -1 }, + { 2, 1, 2, 2, 1 }, + { 2, 1, 0, 2, 1 }, + + /* 581-590 */ + { 2, 0, 2, 4, 1 }, + { 2, 0, 2, -6, 1 }, + { 2, 0, 2, -2, -1 }, + { 2, 0, 0, -6, -1 }, + { 2, -1, -2, -2, -1 }, + { 1, 2, 2, 0, 1 }, + { 1, 2, 0, 0, 1 }, + { 1, 0, 4, 0, 1 }, + { 1, 0, 2, -6, 1 }, + { 1, 0, 2, -4, -1 }, + + /* 591-600 */ + { 1, 0, -1, -2, -1 }, + { 1, -1, 2, 4, 1 }, + { 1, -1, 2, -3, 1 }, + { 1, -1, 0, 4, 1 }, + { 1, -1, -2, 1, -1 }, + { 0, 1, 2, -2, 3 }, + { 3, 0, 0, -2, 0 }, + { 1, 0, 1, -2, 0 }, + { 0, 2, 0, -4, 0 }, + { 0, 0, 2, -4, 0 }, + + /* 601-610 */ + { 0, 0, 1, -1, 0 }, + { 0, 0, 0, 6, 0 }, + { 0, 2, 0, 0, -2 }, + { 0, 1, -2, 2, -3 }, + { 4, 0, 0, 2, 0 }, + { 3, 0, 0, -1, 0 }, + { 3, -1, 0, 2, 0 }, + { 2, 1, 0, 1, 0 }, + { 2, 1, 0, -6, 0 }, + { 2, -1, 2, 0, 0 }, + + /* 611-620 */ + { 1, 0, 2, -1, 0 }, + { 1, -1, 0, 1, 0 }, + { 1, -1, -2, -2, 0 }, + { 0, 1, 2, 2, 0 }, + { 0, 0, 2, -3, 0 }, + { 2, 2, 0, -2, -1 }, + { 2, -1, -2, 0, 1 }, + { 1, 2, 2, -4, 1 }, + { 0, 1, 4, -4, 2 }, + { 0, 0, 0, 3, 2 }, + + /* 621-630 */ + { 5, 0, 2, 0, 1 }, + { 4, 1, 2, -2, 2 }, + { 4, 0, -2, -2, 0 }, + { 3, 1, 2, 2, 2 }, + { 3, 1, 0, -2, 0 }, + { 3, 1, -2, -6, -2 }, + { 3, 0, 0, 0, -2 }, + { 3, 0, -2, -4, -2 }, + { 3, -1, 0, -3, 0 }, + { 3, -1, 0, -2, 0 }, + + /* 631-640 */ + { 2, 1, 2, 0, 0 }, + { 2, 1, 2, -4, 2 }, + { 2, 1, 2, -2, 0 }, + { 2, 1, 0, -3, 0 }, + { 2, 1, -2, 0, -2 }, + { 2, 0, 0, -4, 2 }, + { 2, 0, 0, -4, -2 }, + { 2, 0, -2, -5, -2 }, + { 2, -1, 2, 4, 2 }, + { 2, -1, 0, -2, 2 }, + + /* 641-650 */ + { 1, 3, -2, -2, -2 }, + { 1, 1, 0, 0, -2 }, + { 1, 1, 0, -6, 0 }, + { 1, 1, -2, 1, -2 }, + { 1, 1, -2, -1, -2 }, + { 1, 0, 2, 1, 0 }, + { 1, 0, 0, 3, 0 }, + { 1, 0, 0, -4, 2 }, + { 1, 0, -2, 4, -2 }, + { 1, -2, 0, -1, 0 }, + + /* 651-NFLS */ + { 0, 1, -4, 2, -1 }, + { 1, 0, -2, 0, -3 }, + { 0, 0, 4, -4, 4 } + }; + +/* Number of frequencies: luni-solar */ + static const int NFLS = (int) (sizeof mfals / sizeof (int) / 5); + +/* Fundamental-argument multipliers: planetary terms */ + static const int mfapl[][14] = { + + /* 1-10 */ + { 0, 0, 1, -1, 1, 0, 0, -1, 0, -2, 5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 1, 0, -8, 12, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 8,-16, 4, 5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, -1, 2, 0, 0, 0, 0, 0 }, + + /* 11-20 */ + { 0, 0, 0, 0, 0, 0, 8,-13, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 2, -5, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, -5, 6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 4, -6, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, -1, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -8, 3, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 6, -8, 3, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0, 0 }, + + /* 21-30 */ + { 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 1, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 1, -1, 1, 0, 0, 0, -2, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, -1, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1 }, + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + + /* 31-40 */ + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8,-13, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 5, -8, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, 1 }, + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, -1, 0, 0, 0 }, + + /* 41-50 */ + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -7, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, 0, -2, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 8,-13, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 2, -1, 0, 0, 0, 0, 0, 2 }, + { 1, 0, 0, 0, 0, 0,-18, 16, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 2 }, + + /* 51-60 */ + { 0, 0, 1, -1, 1, 0, -5, 7, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0,-10, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 0, 0, -5, 6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -1, 0, 0, 0, 2 }, + { 1, 0, 2, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1 }, + { 1, 0, -2, 0, -2, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, 2, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + + /* 61-70 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 8,-16, 4, 5, 0, 0, -2 }, + { 0, 0, 1, -1, 1, 0, 0, 3, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8,-11, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 8,-16, 4, 5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 4, -6, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -3, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 0 }, + + /* 71-80 */ + { 0, 0, 0, 0, 0, 0, 6, -8, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 3, -2, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 8,-15, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 1, -3, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, -2, 0, 0, 0, 2 }, + { 0, 0, 1, -1, 1, 0, 0, -5, 8, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -2, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0, 0 }, + + /* 81-90 */ + { 2, 0, 0, -2, 1, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -8, 0, 0, 0, 0, 0, -1 }, + { 2, 0, 0, -2, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 8,-13, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 0, 0, -2, 5, 0, 0, 0 }, + { 1, 0, 0, -1, 0, 0, -3, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2 }, + { 1, 0, 0, 0, -1, 0,-18, 16, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, -5, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, + + /* 91-100 */ + { 1, 0, 0, -2, 0, 0, 19,-21, 3, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, -8, 13, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 7, -9, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2 }, + { 1, 0, 0, 0, 1, 0,-18, 16, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 6,-16, 4, 5, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 4, -7, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 3, -7, 0, 0, 0, 0, 0, -2 }, + + /* 101-110 */ + { 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1 }, + { 2, 0, 0, -2, 1, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, -1, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2 }, + + /* 111-120 */ + { 0, 0, 0, 0, 1, 0, 0, 1, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2 }, + { 0, 0, 2, -2, 1, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, -6, 8, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -2, 2, 0, 0, 0, 0, 0 }, + + /* 121-130 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8,-10, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 1, 0, -3, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 6, -9, 0, 0, 0, 0, 0, -2 }, + { 1, 0, 0, -1, 1, 0, 0, -1, 0, 2, 0, 0, 0, 0 }, + + /* 131-140 */ + { 0, 0, 0, 0, 0, 0, 5, -7, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, 0, -3, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1, 0, 2, -3, 0, 0, 0, 0, 0, 0 }, + + /* 141-150 */ + { 1, 0, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, -3, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -4, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 9,-11, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 8,-15, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -4, 5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 4, -6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, 0, -1, 0, 0, 0, 2 }, + + /* 151-160 */ + { 1, 0, 0, -1, 1, 0, -3, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, -4, 10, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -4, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, -2 }, + { 0, 0, 2, -2, 1, 0, -4, 4, 0, 0, 0, 0, 0, 0 }, + + /* 161-170 */ + { 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, -1, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -3, 0, 0, 0, 0, 2 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, 0, 0, 2, 0 }, + { 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 5, -8, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -9, 13, 0, 0, 0, 0, 0 }, + { 2, 0, 2, 0, 2, 0, 0, 2, 0, -3, 0, 0, 0, 0 }, + + /* 171-180 */ + { 0, 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 2, 0, 0, -1, 0, 0, 2, 0, 0, 0 }, + { 1, 0, 0, -1, -1, 0, -3, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1 }, + { 1, 0, 2, 0, 1, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 1, 0, -2, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, -2, 4, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0 }, + + /* 181-190 */ + { 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 2, 0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, -8, 3, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 6,-10, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 7, -8, 3, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 1, 0, -3, 5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, -5, 7, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 1 }, + + /* 191-200 */ + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 7,-10, 0, 0, 0, 0, 0, -2 }, + { 1, 0, 0, -2, 0, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, -5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 6, -8, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 1, -1, 1, 0, 0, -9, 15, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, -2, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, -1, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, 0 }, + + /* 201-210 */ + { 0, 0, 0, 0, 0, 0, 0, 1, -4, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, -1, 0, 0, 2 }, + { 2, 0, 0, -2, 1, 0, -6, 8, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 1, -1, 1, 0, 3, -6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 8,-14, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + + /* 211-220 */ + { 0, 0, 0, 0, 1, 0, 0, 8,-15, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -6, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 7, -7, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 1, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 2 }, + { 2, 0, -1, -1, 0, 0, 0, 3, -7, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -7, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -3, 4, 0, 0, 0, 0, 0 }, + + /* 221-230 */ + { 2, 0, 0, -2, 0, 0, 0, -6, 8, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, 0, -5, 6, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 1, 0, 0, 1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -9, 4, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, -2 }, + + /* 231-240 */ + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -4, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1 }, + { 0, 0, 0, 0, 0, 0, 7,-11, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 3, -5, 4, 0, 0, 0, 0, 2 }, + { 0, 0, 1, -1, 0, 0, 0, -1, 0, -1, 1, 0, 0, 0 }, + { 2, 0, 0, 0, 0, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 8,-15, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 2, 0, 0, -2, 2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 0, 0, 0, -1 }, + + /* 241-250 */ + { 0, 0, 1, -1, 1, 0, 0, -1, 0, -1, 1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -7, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 2, -4, 0, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 3, -5, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, -3, 0, 0, 0, 2 }, + { 0, 0, 2, -2, 2, 0, -8, 11, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -2, 0, 0, 0 }, + + /* 251-260 */ + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -9, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 7, -9, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 4, -7, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 2, -1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, -2, -2, -2, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, 0, 0, 0, 1 }, + + /* 261-270 */ + { 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, -5, 0, 0, 2 }, + { 2, 0, 0, -2, -1, 0, 0, -2, 0, 0, 5, 0, 0, 0 }, + { 2, 0, 0, -2, -1, 0, -6, 8, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8, -8, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, 2, -5, 0, 0, 2 }, + { 0, 0, 0, 0, 1, 0, 3, -7, 4, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + + /* 271-280 */ + { 0, 0, 1, -1, 0, 0, 0, -1, 0, -2, 5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 6,-15, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 2 }, + { 1, 0, 0, -1, 0, 0, 0, -3, 4, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, -3, 7, -4, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, 0, -2, 0, 0, 0, 2 }, + + /* 281-290 */ + { 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 2, -2, 2, 0, -5, 6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 2, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -8, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -5, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -7, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 6,-11, 0, 0, 0, 0, -2 }, + + /* 291-300 */ + { 0, 0, 0, 0, 0, 0, 0, 1, -3, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, -1, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 9,-12, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 1, -1, 0, 0, -8, 12, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -2, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 7, -7, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, -1 }, + + /* 301-310 */ + { 0, 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 1, 0, -4, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 6, -9, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 1, -1, -1, 0, 0, 0, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, -5, 0, 0, 0, 0, -2 }, + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 3, -1, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, -2, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -9, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, 2 }, + + /* 311-320 */ + { 0, 0, 0, 0, 0, 0, 9, -9, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, 3, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 2, -4, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -3, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1 }, + { 0, 0, 1, -1, 2, 0, 0, -1, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -9, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -3, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 2 }, + { 0, 0, 2, 0, 2, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + + /* 321-330 */ + { 0, 0, 2, 0, 2, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, 0, -3, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0 }, + { 2, 0, -1, -1, -1, 0, 0, -1, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 4, -3, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 5,-10, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 8,-13, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 2, -2, 1, -1, 0, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, 0, 2, 0, 0 }, + + /* 331-340 */ + { 0, 0, 0, 0, 1, 0, 3, -5, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 9, -9, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 2, 0, 1, -1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -8, 11, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -2, 0, 0, 2, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, -1, 2, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 2, -6, 0, 0, 0, 0, 0, -2 }, + + /* 341-350 */ + { 0, 0, 0, 0, 0, 0, 0, 8,-15, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -2, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 7,-13, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, -2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 0, 0, 2 }, + { 0, 0, 2, -2, 1, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8, -8, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 8,-10, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 0, 1 }, + + /* 351-360 */ + { 0, 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -4, 0, 0, 0, 0 }, + { 2, 0, 0, -2, -1, 0, 0, -5, 6, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, 0, 0, -2 }, + { 2, 0, -1, -1, -1, 0, 0, 3, -7, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -8, 0, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 2, 0, -1, 1, 0, 0, 0, 0, 0, 0 }, + + /* 361-370 */ + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 4, -3, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 6,-11, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 1, 0, 0, -6, 8, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -8, 1, 5, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 6, -5, 0, 0, 0, 0, 2 }, + { 1, 0, -2, -2, -2, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 2, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 2, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 1 }, + + /* 371-380 */ + { 0, 0, 0, 0, 0, 0, 0, 6, -7, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, -2, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, -2, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 1, -6, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 3, -5, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 7,-13, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 2 }, + + /* 381-390 */ + { 0, 0, 1, -1, 0, 0, 0, -1, 0, 0, 2, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, -8, 15, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, -2, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 2, 0, -1, -1, -1, 0, 0, -1, 0, 2, 0, 0, 0, 0 }, + { 1, 0, 2, -2, 2, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 1, 0, -1, 1, -1, 0,-18, 17, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 2, 0, 0, 1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 2, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 2, -2, -1, 0, -5, 6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 2, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + + /* 391-400 */ + { 0, 0, 0, 0, 1, 0, 2, -2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8,-16, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2 }, + { 0, 0, 0, 0, 2, 0, 0, -1, 2, 0, 0, 0, 0, 0 }, + { 2, 0, -1, -1, -2, 0, 0, -1, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 6,-10, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, -2, 4, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2 }, + { 2, 0, 0, -2, -1, 0, 0, -2, 0, 4, -5, 0, 0, 0 }, + + /* 401-410 */ + { 2, 0, 0, -2, -1, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 2, 0, -1, -1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 1, -1, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, -1, -1, 0, 0, -2, 2, 0, 0, 0, 0, 0 }, + { 1, 0, -1, -1, -1, 0, 20,-20, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 1, -2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -2, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 5, -8, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0 }, + + /* 411-420 */ + { 0, 0, 0, 0, 0, 0, 9,-11, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 5, -3, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -3, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 6, -7, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, -2, 0, 0, 0 }, + { 0, 0, 1, -1, 2, 0, 0, -1, 0, -2, 5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -7, 0, 0, 0, 0, 0 }, + + /* 421-430 */ + { 0, 0, 0, 0, 0, 0, 1, -3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -8, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -6, 0, 0, 0, 0, -2 }, + { 1, 0, 0, -2, 0, 0, 20,-21, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8,-12, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 2, 0, 0, -1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 8,-12, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 9,-17, 0, 0, 0, 0, 0 }, + + /* 431-440 */ + { 0, 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -8, 1, 5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -6, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -7, 0, 0, 0, 0, -2 }, + { 1, 0, 0, -1, 1, 0, 0, -3, 4, 0, 0, 0, 0, 0 }, + { 1, 0, -2, 0, -2, 0,-10, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, -9, 17, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, -4, 0, 0, 0, 0, 0, -2 }, + { 1, 0, -2, -2, -2, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 1, 0, -1, 1, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + + /* 441-450 */ + { 0, 0, 2, -2, 2, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 2, 0, 0, -1, 0, 0, 1, 0, 0, 0 }, + { 0, 0, 1, -1, 2, 0, -5, 7, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 2, -2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 4, -5, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5,-10, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, 0, -4, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, -5, 0, 0, 0, -2 }, + + /* 451-460 */ + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -5, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -2, 5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -2, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 2, -3, 0, 0, 0, 0, 0, 1 }, + { 1, 0, 0, -2, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -7, 4, 0, 0, 0, 0, 0 }, + { 2, 0, 2, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, -1, 0, 0, -1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 1, 0, -2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 6,-10, 0, 0, 0, 0, -2 }, + + /* 461-470 */ + { 1, 0, 0, -1, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, 1, 0, -1, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -3, 0, 3, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, -5, 5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 1, -3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -4, 6, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 0, 0, -1, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -5, 6, 0, 0, 0, 0, 0, 0 }, + + /* 471-480 */ + { 0, 0, 0, 0, 1, 0, 3, -4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 7,-10, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 5, -5, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 4, -5, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 3, -8, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 2, -5, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 7, -9, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 7, -8, 0, 0, 0, 0, 2 }, + + /* 481-490 */ + { 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -8, 3, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, -2, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -4, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, -1 }, + { 2, 0, 0, -2, -1, 0, 0, -6, 8, 0, 0, 0, 0, 0 }, + { 2, 0, -1, -1, 1, 0, 0, 3, -7, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -7, 9, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0, 0, -1 }, + + /* 491-500 */ + { 0, 0, 1, -1, 2, 0, -8, 12, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 7, -8, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 1, 0, 0, -5, 6, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, -1, 0, 0, -2, 0, 3, -1, 0, 0, 0 }, + { 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 1, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 1, 0, 0, -2, -1, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + + /* 501-510 */ + { 1, 0, 0, -1, -1, 0, 0, -3, 4, 0, 0, 0, 0, 0 }, + { 1, 0, -1, 0, -1, 0, -3, 5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -4, 4, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, -8, 11, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 0, 0, 0, -9, 13, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 1, 2, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, 1, -4, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, 0, -1, 0, 1, -3, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, 7,-13, 0, 0, 0, 0, 0 }, + + /* 511-520 */ + { 0, 0, 0, 0, 1, 0, 0, 2, 0, -2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, -2, 2, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, -3, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 1, 0, -4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 7,-11, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 6, -6, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 6, -4, 0, 0, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 4, -2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -4, 0, 0, 0, 0, 0, 1 }, + + /* 521-530 */ + { 0, 0, 0, 0, 0, 0, 1, -4, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 9,-17, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 7, -7, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -8, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, -7, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -4, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + + /* 531-540 */ + { 2, 0, 0, -2, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, 17,-16, 0, -2, 0, 0, 0, 0 }, + { 1, 0, 0, -1, 0, 0, 0, -2, 2, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 0, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 6, -9, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 3, 0, -4, 0, 0, 0, 0 }, + + /* 541-550 */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 2 }, + { 2, 0, 0, -2, 0, 0, 0, -4, 4, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 2, 2, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + + /* 551-560 */ + { 1, 0, 0, -2, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 3, -6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, -2, 2, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, -4, 5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, -3, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 2, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0 }, + + /* 561-570 */ + { 0, 0, 0, 0, 0, 0, 8, -9, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0 }, + { 2, 0, -2, -2, -2, 0, 0, -2, 0, 2, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 1, 0,-10, 3, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, -1, 0,-10, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 2, 0, 2, -3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 2, 0, 2, -2, 0, 0, 0, 0, 0, 0 }, + + /* 571-580 */ + { 0, 0, 2, 0, 2, 0, -2, 3, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, 0, 2, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, 0, -1, 0, 2, 0, 0, 0, 0 }, + { 2, 0, 2, -2, 2, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 2, 0, 1, -3, 1, 0, -6, 7, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, 2, -5, 0, 0, 0, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 5, -5, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 1, 5, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 0, 5, 0, 0, 0 }, + + /* 581-590 */ + { 2, 0, 0, -2, 0, 0, 0, -2, 0, 0, 2, 0, 0, 0 }, + { 2, 0, 0, -2, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0 }, + { 2, 0, -2, 0, -2, 0, 0, 5, -9, 0, 0, 0, 0, 0 }, + { 2, 0, -1, -1, 0, 0, 0, -1, 0, 3, 0, 0, 0, 0 }, + { 1, 0, 2, 0, 2, 0, 1, -1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 2, 0, 2, 0, 0, 4, -8, 3, 0, 0, 0, 0 }, + { 1, 0, 2, 0, 2, 0, 0, -4, 8, -3, 0, 0, 0, 0 }, + { 1, 0, 2, 0, 2, 0, -1, 1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 2, -2, 2, 0, -3, 3, 0, 0, 0, 0, 0, 0 }, + { 1, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0 }, + + /* 591-600 */ + { 1, 0, 0, 0, 0, 0, 0, -2, 0, 3, 0, 0, 0, 0 }, + { 1, 0, 0, -2, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0 }, + { 1, 0, -2, -2, -2, 0, 0, 1, 0, -1, 0, 0, 0, 0 }, + { 1, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 1, 0, -1, -1, 0, 0, 0, 8,-15, 0, 0, 0, 0, 0 }, + { 0, 0, 2, 2, 2, 0, 0, 2, 0, -2, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 1, -1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0, -2, 0, 1, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 1, 0, 0,-10, 15, 0, 0, 0, 0, 0 }, + { 0, 0, 2, -2, 0, -1, 0, 2, 0, 0, 0, 0, 0, 0 }, + + /* 601-610 */ + { 0, 0, 1, -1, 2, 0, 0, -1, 0, 0, -1, 0, 0, 0 }, + { 0, 0, 1, -1, 2, 0, -3, 4, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -4, 6, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 1, 0, -1, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, 0, -1, 0, 0, -2, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 1, -1, -1, 0, -5, 7, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 2, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0 }, + + /* 611-620 */ + { 0, 0, 0, 2, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 2, 0, -3, 5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 1, 0, -1, 2, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 9,-13, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 8,-14, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 8,-11, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 6, -9, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 6, -8, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 6, -7, 0, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0, -2 }, + + /* 621-630 */ + { 0, 0, 0, 0, 0, 0, 5, -6, -4, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 5, -4, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 4, -8, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 4, -5, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 3, -3, 0, 2, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 3, -1, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 7,-12, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 6, -9, 0, 0, 0, 0, -2 }, + + /* 631-640 */ + { 0, 0, 0, 0, 0, 0, 0, 6, -8, 1, 5, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 6, -4, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 6,-10, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5, 0, -4, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -9, 0, 0, 0, 0, -1 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -8, 3, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -7, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 5, -6, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 5,-16, 4, 5, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 5,-13, 0, 0, 0, 0, -2 }, + + /* 641-650 */ + { 0, 0, 0, 0, 0, 0, 0, 3, 0, -5, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -9, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 3, -7, 0, 0, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, -3, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 2, -8, 1, 5, 0, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, -5, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -3, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 1, 0, -3, 5, 0, 0, 0 }, + + /* 651-NFPL */ + { 0, 0, 0, 0, 0, 0, 0, 1, -3, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -6, 3, 0, -2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -2, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 } + }; + +/* Number of frequencies: planetary */ + static const int NFPL = (int) (sizeof mfapl / sizeof (int) / 14); + +/* Pointers into amplitudes array, one pointer per frequency */ + static const int nc[] = { + + /* 1-100 */ + 1, 21, 37, 51, 65, 79, 91, 103, 115, 127, + 139, 151, 163, 172, 184, 196, 207, 219, 231, 240, + 252, 261, 273, 285, 297, 309, 318, 327, 339, 351, + 363, 372, 384, 396, 405, 415, 423, 435, 444, 452, + 460, 467, 474, 482, 490, 498, 506, 513, 521, 528, + 536, 543, 551, 559, 566, 574, 582, 590, 597, 605, + 613, 620, 628, 636, 644, 651, 658, 666, 674, 680, + 687, 695, 702, 710, 717, 725, 732, 739, 746, 753, + 760, 767, 774, 782, 790, 798, 805, 812, 819, 826, + 833, 840, 846, 853, 860, 867, 874, 881, 888, 895, + + /* 101-200 */ + 901, 908, 914, 921, 928, 934, 941, 948, 955, 962, + 969, 976, 982, 989, 996, 1003, 1010, 1017, 1024, 1031, + 1037, 1043, 1050, 1057, 1064, 1071, 1078, 1084, 1091, 1098, + 1104, 1112, 1118, 1124, 1131, 1138, 1145, 1151, 1157, 1164, + 1171, 1178, 1185, 1192, 1199, 1205, 1212, 1218, 1226, 1232, + 1239, 1245, 1252, 1259, 1266, 1272, 1278, 1284, 1292, 1298, + 1304, 1310, 1316, 1323, 1329, 1335, 1341, 1347, 1353, 1359, + 1365, 1371, 1377, 1383, 1389, 1396, 1402, 1408, 1414, 1420, + 1426, 1434, 1440, 1446, 1452, 1459, 1465, 1471, 1477, 1482, + 1488, 1493, 1499, 1504, 1509, 1514, 1520, 1527, 1532, 1538, + + /* 201-300 */ + 1543, 1548, 1553, 1558, 1564, 1569, 1574, 1579, 1584, 1589, + 1594, 1596, 1598, 1600, 1602, 1605, 1608, 1610, 1612, 1617, + 1619, 1623, 1625, 1627, 1629, 1632, 1634, 1640, 1642, 1644, + 1646, 1648, 1650, 1652, 1654, 1658, 1660, 1662, 1664, 1668, + 1670, 1672, 1673, 1675, 1679, 1681, 1683, 1684, 1686, 1688, + 1690, 1693, 1695, 1697, 1701, 1703, 1705, 1707, 1709, 1711, + 1712, 1715, 1717, 1721, 1723, 1725, 1727, 1729, 1731, 1733, + 1735, 1737, 1739, 1741, 1743, 1745, 1747, 1749, 1751, 1753, + 1755, 1757, 1759, 1761, 1762, 1764, 1766, 1768, 1769, 1771, + 1773, 1775, 1777, 1779, 1781, 1783, 1785, 1787, 1788, 1790, + + /* 301-400 */ + 1792, 1794, 1796, 1798, 1800, 1802, 1804, 1806, 1807, 1809, + 1811, 1815, 1817, 1819, 1821, 1823, 1825, 1827, 1829, 1831, + 1833, 1835, 1837, 1839, 1840, 1842, 1844, 1848, 1850, 1852, + 1854, 1856, 1858, 1859, 1860, 1862, 1864, 1866, 1868, 1869, + 1871, 1873, 1875, 1877, 1879, 1881, 1883, 1885, 1887, 1889, + 1891, 1892, 1896, 1898, 1900, 1901, 1903, 1905, 1907, 1909, + 1910, 1911, 1913, 1915, 1919, 1921, 1923, 1927, 1929, 1931, + 1933, 1935, 1937, 1939, 1943, 1945, 1947, 1948, 1949, 1951, + 1953, 1955, 1957, 1958, 1960, 1962, 1964, 1966, 1968, 1970, + 1971, 1973, 1974, 1975, 1977, 1979, 1980, 1981, 1982, 1984, + + /* 401-500 */ + 1986, 1988, 1990, 1992, 1994, 1995, 1997, 1999, 2001, 2003, + 2005, 2007, 2008, 2009, 2011, 2013, 2015, 2017, 2019, 2021, + 2023, 2024, 2025, 2027, 2029, 2031, 2033, 2035, 2037, 2041, + 2043, 2045, 2046, 2047, 2049, 2051, 2053, 2055, 2056, 2057, + 2059, 2061, 2063, 2065, 2067, 2069, 2070, 2071, 2072, 2074, + 2076, 2078, 2080, 2082, 2084, 2086, 2088, 2090, 2092, 2094, + 2095, 2096, 2097, 2099, 2101, 2105, 2106, 2107, 2108, 2109, + 2110, 2111, 2113, 2115, 2119, 2121, 2123, 2125, 2127, 2129, + 2131, 2133, 2135, 2136, 2137, 2139, 2141, 2143, 2145, 2147, + 2149, 2151, 2153, 2155, 2157, 2159, 2161, 2163, 2165, 2167, + + /* 501-600 */ + 2169, 2171, 2173, 2175, 2177, 2179, 2181, 2183, 2185, 2186, + 2187, 2188, 2192, 2193, 2195, 2197, 2199, 2201, 2203, 2205, + 2207, 2209, 2211, 2213, 2217, 2219, 2221, 2223, 2225, 2227, + 2229, 2231, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, + 2241, 2244, 2246, 2248, 2250, 2252, 2254, 2256, 2258, 2260, + 2262, 2264, 2266, 2268, 2270, 2272, 2274, 2276, 2278, 2280, + 2282, 2284, 2286, 2288, 2290, 2292, 2294, 2296, 2298, 2300, + 2302, 2303, 2304, 2305, 2306, 2307, 2309, 2311, 2313, 2315, + 2317, 2319, 2321, 2323, 2325, 2327, 2329, 2331, 2333, 2335, + 2337, 2341, 2343, 2345, 2347, 2349, 2351, 2352, 2355, 2356, + + /* 601-700 */ + 2357, 2358, 2359, 2361, 2363, 2364, 2365, 2366, 2367, 2368, + 2369, 2370, 2371, 2372, 2373, 2374, 2376, 2378, 2380, 2382, + 2384, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, + 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2402, 2403, + 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 2412, 2413, + 2414, 2415, 2417, 2418, 2430, 2438, 2445, 2453, 2460, 2468, + 2474, 2480, 2488, 2496, 2504, 2512, 2520, 2527, 2535, 2543, + 2550, 2558, 2566, 2574, 2580, 2588, 2596, 2604, 2612, 2619, + 2627, 2634, 2642, 2648, 2656, 2664, 2671, 2679, 2685, 2693, + 2701, 2709, 2717, 2725, 2733, 2739, 2747, 2753, 2761, 2769, + + /* 701-800 */ + 2777, 2785, 2793, 2801, 2809, 2817, 2825, 2833, 2841, 2848, + 2856, 2864, 2872, 2878, 2884, 2892, 2898, 2906, 2914, 2922, + 2930, 2938, 2944, 2952, 2958, 2966, 2974, 2982, 2988, 2996, + 3001, 3009, 3017, 3025, 3032, 3039, 3045, 3052, 3059, 3067, + 3069, 3076, 3083, 3090, 3098, 3105, 3109, 3111, 3113, 3120, + 3124, 3128, 3132, 3136, 3140, 3144, 3146, 3150, 3158, 3161, + 3165, 3166, 3168, 3172, 3176, 3180, 3182, 3185, 3189, 3193, + 3194, 3197, 3200, 3204, 3208, 3212, 3216, 3219, 3221, 3222, + 3226, 3230, 3234, 3238, 3242, 3243, 3247, 3251, 3254, 3258, + 3262, 3266, 3270, 3274, 3275, 3279, 3283, 3287, 3289, 3293, + + /* 801-900 */ + 3296, 3300, 3303, 3307, 3311, 3315, 3319, 3321, 3324, 3327, + 3330, 3334, 3338, 3340, 3342, 3346, 3350, 3354, 3358, 3361, + 3365, 3369, 3373, 3377, 3381, 3385, 3389, 3393, 3394, 3398, + 3402, 3406, 3410, 3413, 3417, 3421, 3425, 3429, 3433, 3435, + 3439, 3443, 3446, 3450, 3453, 3457, 3458, 3461, 3464, 3468, + 3472, 3476, 3478, 3481, 3485, 3489, 3493, 3497, 3501, 3505, + 3507, 3511, 3514, 3517, 3521, 3524, 3525, 3527, 3529, 3533, + 3536, 3540, 3541, 3545, 3548, 3551, 3555, 3559, 3563, 3567, + 3569, 3570, 3574, 3576, 3578, 3582, 3586, 3590, 3593, 3596, + 3600, 3604, 3608, 3612, 3616, 3620, 3623, 3626, 3630, 3632, + + /* 901-1000 */ + 3636, 3640, 3643, 3646, 3648, 3652, 3656, 3660, 3664, 3667, + 3669, 3671, 3675, 3679, 3683, 3687, 3689, 3693, 3694, 3695, + 3699, 3703, 3705, 3707, 3710, 3713, 3717, 3721, 3725, 3729, + 3733, 3736, 3740, 3744, 3748, 3752, 3754, 3757, 3759, 3763, + 3767, 3770, 3773, 3777, 3779, 3783, 3786, 3790, 3794, 3798, + 3801, 3805, 3809, 3813, 3817, 3821, 3825, 3827, 3831, 3835, + 3836, 3837, 3840, 3844, 3848, 3852, 3856, 3859, 3863, 3867, + 3869, 3871, 3875, 3879, 3883, 3887, 3890, 3894, 3898, 3901, + 3905, 3909, 3913, 3917, 3921, 3922, 3923, 3924, 3926, 3930, + 3932, 3936, 3938, 3940, 3944, 3948, 3952, 3956, 3959, 3963, + + /* 1001-1100 */ + 3965, 3969, 3973, 3977, 3979, 3981, 3982, 3986, 3989, 3993, + 3997, 4001, 4004, 4006, 4009, 4012, 4016, 4020, 4024, 4026, + 4028, 4032, 4036, 4040, 4044, 4046, 4050, 4054, 4058, 4060, + 4062, 4063, 4064, 4068, 4071, 4075, 4077, 4081, 4083, 4087, + 4089, 4091, 4095, 4099, 4101, 4103, 4105, 4107, 4111, 4115, + 4119, 4123, 4127, 4129, 4131, 4135, 4139, 4141, 4143, 4145, + 4149, 4153, 4157, 4161, 4165, 4169, 4173, 4177, 4180, 4183, + 4187, 4191, 4195, 4198, 4201, 4205, 4209, 4212, 4213, 4216, + 4217, 4221, 4223, 4226, 4230, 4234, 4236, 4240, 4244, 4248, + 4252, 4256, 4258, 4262, 4264, 4266, 4268, 4270, 4272, 4276, + + /* 1101-1200 */ + 4279, 4283, 4285, 4287, 4289, 4293, 4295, 4299, 4300, 4301, + 4305, 4309, 4313, 4317, 4319, 4323, 4325, 4329, 4331, 4333, + 4335, 4337, 4341, 4345, 4349, 4351, 4353, 4357, 4361, 4365, + 4367, 4369, 4373, 4377, 4381, 4383, 4387, 4389, 4391, 4395, + 4399, 4403, 4407, 4411, 4413, 4414, 4415, 4418, 4419, 4421, + 4423, 4427, 4429, 4431, 4433, 4435, 4437, 4439, 4443, 4446, + 4450, 4452, 4456, 4458, 4460, 4462, 4466, 4469, 4473, 4477, + 4481, 4483, 4487, 4489, 4491, 4493, 4497, 4499, 4501, 4504, + 4506, 4510, 4513, 4514, 4515, 4518, 4521, 4522, 4525, 4526, + 4527, 4530, 4533, 4534, 4537, 4541, 4542, 4543, 4544, 4545, + + /* 1201-1300 */ + 4546, 4547, 4550, 4553, 4554, 4555, 4558, 4561, 4564, 4567, + 4568, 4571, 4574, 4575, 4578, 4581, 4582, 4585, 4586, 4588, + 4590, 4592, 4596, 4598, 4602, 4604, 4608, 4612, 4613, 4616, + 4619, 4622, 4623, 4624, 4625, 4626, 4629, 4632, 4633, 4636, + 4639, 4640, 4641, 4642, 4643, 4644, 4645, 4648, 4649, 4650, + 4651, 4652, 4653, 4656, 4657, 4660, 4661, 4664, 4667, 4670, + 4671, 4674, 4675, 4676, 4677, 4678, 4681, 4682, 4683, 4684, + 4687, 4688, 4689, 4692, 4693, 4696, 4697, 4700, 4701, 4702, + 4703, 4704, 4707, 4708, 4711, 4712, 4715, 4716, 4717, 4718, + 4719, 4720, 4721, 4722, 4723, 4726, 4729, 4730, 4733, 4736, + + /* 1301-(NFLS+NFPL) */ + 4737, 4740, 4741, 4742, 4745, 4746, 4749, 4752, 4753 + }; + +/* Amplitude coefficients (microarcsec); indexed using the nc array. */ + static const double a[] = { + + /* 1-105 */ + -6844318.44, 9205236.26,1328.67,1538.18, 205833.11, + 153041.79, -3309.73, 853.32,2037.98, -2301.27, + 81.46, 120.56, -20.39, -15.22, 1.73, -1.61, -0.10, 0.11, + -0.02, -0.02, -523908.04, 573033.42,-544.75,-458.66, + 12814.01, 11714.49, 198.97,-290.91, 155.74,-143.27, + -2.75, -1.03, -1.27, -1.16, 0.00, -0.01, -90552.22, + 97846.69, 111.23, 137.41,2187.91,2024.68, 41.44, -51.26, + 26.92, -24.46, -0.46, -0.28, -0.22, -0.20, 82168.76, + -89618.24, -27.64, -29.05, -2004.36, -1837.32, + -36.07, 48.00, -24.43, 22.41, 0.47, 0.24, 0.20, 0.18, + 58707.02,7387.02, 470.05,-192.40, 164.33, -1312.21, + -179.73, -28.93, -17.36, -1.83, -0.50, 3.57, 0.00, 0.13, + -20557.78, 22438.42, -20.84, -17.40, 501.82, 459.68, + 59.20, -67.30, 6.08, -5.61, -1.36, -1.19, 28288.28, + -674.99, -34.69, 35.80, -15.07,-632.54, -11.19, 0.78, -8.41, + 0.17, 0.01, 0.07, -15406.85, 20069.50, 15.12, + + /* 106-219 */ + 31.80, 448.76, 344.50, -5.77, 1.41, 4.59, -5.02, 0.17, + 0.24, -11991.74, 12902.66, 32.46, 36.70, 288.49, + 268.14, 5.70, -7.06, 3.57, -3.23, -0.06, -0.04, + -8584.95, -9592.72, 4.42, -13.20,-214.50, 192.06, + 23.87, 29.83, 2.54, 2.40, 0.60, -0.48,5095.50, + -6918.22, 7.19, 3.92,-154.91,-113.94, 2.86, -1.04, + -1.52, 1.73, -0.07, -0.10, -4910.93, -5331.13, + 0.76, 0.40,-119.21, 109.81, 2.16, 3.20, 1.46, 1.33, + 0.04, -0.02, -6245.02,-123.48, -6.68, -8.20, -2.76, + 139.64, 2.71, 0.15, 1.86,2511.85, -3323.89, 1.07, + -0.90, -74.33, -56.17, 1.16, -0.01, -0.75, 0.83, -0.02, + -0.04,2307.58,3143.98, -7.52, 7.50, 70.31, -51.60, 1.46, + 0.16, -0.69, -0.79, 0.02, -0.05,2372.58,2554.51, 5.93, + -6.60, 57.12, -53.05, -0.96, -1.24, -0.71, -0.64, -0.01, + -2053.16,2636.13, 5.13, 7.80, 58.94, 45.91, -0.42, + -0.12, 0.61, -0.66, 0.02, 0.03, -1825.49, + + /* 220-339 */ + -2423.59, 1.23, -2.00, -54.19, 40.82, -1.07, -1.02, + 0.54, 0.61, -0.04, 0.04,2521.07,-122.28, -5.97, 2.90, + -2.73, -56.37, -0.82, 0.13, -0.75, -1534.09,1645.01, + 6.29, 6.80, 36.78, 34.30, 0.92, -1.25, 0.46, -0.41, + -0.02, -0.01,1898.27, 47.70, -0.72, 2.50, 1.07, -42.45, + -0.94, 0.02, -0.56, -1292.02, -1387.00, 0.00, + 0.00, -31.01, 28.89, 0.68, 0.00, 0.38, 0.35, -0.01, + -0.01, -1234.96,1323.81, 5.21, 5.90, 29.60, 27.61, + 0.74, -1.22, 0.37, -0.33, -0.02, -0.01,1137.48, + -1233.89, -0.04, -0.30, -27.59, -25.43, -0.61, 1.00, + -0.34, 0.31, 0.01, 0.01,-813.13, -1075.60, 0.40, + 0.30, -24.05, 18.18, -0.40, -0.01, 0.24, 0.27, -0.01, + 0.01,1163.22, -60.90, -2.94, 1.30, -1.36, -26.01, -0.58, + 0.07, -0.35,1029.70, -55.55, -2.63, 1.10, -1.25, -23.02, + -0.52, 0.06, -0.31,-556.26, 852.85, 3.16, -4.48, 19.06, + 12.44, -0.81, -0.27, 0.17, -0.21, 0.00, 0.02,-603.52, + + /* 340-467 */ + -800.34, 0.44, 0.10, -17.90, 13.49, -0.08, -0.01, 0.18, + 0.20, -0.01, 0.01,-628.24, 684.99, -0.64, -0.50, 15.32, + 14.05, 3.18, -4.19, 0.19, -0.17, -0.09, -0.07,-866.48, + -16.26, 0.52, -1.30, -0.36, 19.37, 0.43, -0.01, 0.26, + -512.37, 695.54, -1.47, -1.40, 15.55, 11.46, -0.16, 0.03, + 0.15, -0.17, 0.01, 0.01, 506.65, 643.75, 2.54, -2.62, + 14.40, -11.33, -0.77, -0.06, -0.15, -0.16, 0.00, 0.01, + 664.57, 16.81, -0.40, 1.00, 0.38, -14.86, -3.71, -0.09, + -0.20, 405.91, 522.11, 0.99, -1.50, 11.67, -9.08, -0.25, + -0.02, -0.12, -0.13,-305.78, 326.60, 1.75, 1.90, 7.30, + 6.84, 0.20, -0.04, 300.99,-325.03, -0.44, -0.50, -7.27, + -6.73, -1.01, 0.01, 0.00, 0.08, 0.00, 0.02, 438.51, + 10.47, -0.56, -0.20, 0.24, -9.81, -0.24, 0.01, -0.13, + -264.02, 335.24, 0.99, 1.40, 7.49, 5.90, -0.27, -0.02, + 284.09, 307.03, 0.32, -0.40, 6.87, -6.35, -0.99, -0.01, + -250.54, 327.11, 0.08, 0.40, 7.31, 5.60, -0.30, 230.72, + + /* 468-595 */ + -304.46, 0.08, -0.10, -6.81, -5.16, 0.27, 229.78, 304.17, + -0.60, 0.50, 6.80, -5.14, 0.33, 0.01, 256.30,-276.81, + -0.28, -0.40, -6.19, -5.73, -0.14, 0.01,-212.82, 269.45, + 0.84, 1.20, 6.02, 4.76, 0.14, -0.02, 196.64, 272.05, + -0.84, 0.90, 6.08, -4.40, 0.35, 0.02, 188.95, 272.22, + -0.12, 0.30, 6.09, -4.22, 0.34,-292.37, -5.10, -0.32, + -0.40, -0.11, 6.54, 0.14, 0.01, 161.79,-220.67, 0.24, + 0.10, -4.93, -3.62, -0.08, 261.54, -19.94, -0.95, 0.20, + -0.45, -5.85, -0.13, 0.02, 142.16,-190.79, 0.20, 0.10, + -4.27, -3.18, -0.07, 187.95, -4.11, -0.24, 0.30, -0.09, + -4.20, -0.09, 0.01, 0.00, 0.00, -79.08, 167.90, 0.04, + 0.00, 3.75, 1.77, 121.98, 131.04, -0.08, 0.10, 2.93, + -2.73, -0.06,-172.95, -8.11, -0.40, -0.20, -0.18, 3.87, + 0.09, 0.01,-160.15, -55.30, -14.04, 13.90, -1.23, 3.58, + 0.40, 0.31,-115.40, 123.20, 0.60, 0.70, 2.75, 2.58, + 0.08, -0.01,-168.26, -2.00, 0.20, -0.20, -0.04, 3.76, + + /* 596-723 */ + 0.08,-114.49, 123.20, 0.32, 0.40, 2.75, 2.56, 0.07, + -0.01, 112.14, 120.70, 0.28, -0.30, 2.70, -2.51, -0.07, + -0.01, 161.34, 4.03, 0.20, 0.20, 0.09, -3.61, -0.08, + 91.31, 126.64, -0.40, 0.40, 2.83, -2.04, -0.04, 0.01, + 105.29, 112.90, 0.44, -0.50, 2.52, -2.35, -0.07, -0.01, + 98.69,-106.20, -0.28, -0.30, -2.37, -2.21, -0.06, 0.01, + 86.74,-112.94, -0.08, -0.20, -2.53, -1.94, -0.05,-134.81, + 3.51, 0.20, -0.20, 0.08, 3.01, 0.07, 79.03, 107.31, + -0.24, 0.20, 2.40, -1.77, -0.04, 0.01, 132.81, -10.77, + -0.52, 0.10, -0.24, -2.97, -0.07, 0.01,-130.31, -0.90, + 0.04, 0.00, 0.00, 2.91, -78.56, 85.32, 0.00, 0.00, + 1.91, 1.76, 0.04, 0.00, 0.00, -41.53, 89.10, 0.02, + 0.00, 1.99, 0.93, 66.03, -71.00, -0.20, -0.20, -1.59, + -1.48, -0.04, 60.50, 64.70, 0.36, -0.40, 1.45, -1.35, + -0.04, -0.01, -52.27, -70.01, 0.00, 0.00, -1.57, 1.17, + 0.03, -52.95, 66.29, 0.32, 0.40, 1.48, 1.18, 0.04, + + /* 724-851 */ + -0.01, 51.02, 67.25, 0.00, 0.00, 1.50, -1.14, -0.03, + -55.66, -60.92, 0.16, -0.20, -1.36, 1.24, 0.03, -54.81, + -59.20, -0.08, 0.20, -1.32, 1.23, 0.03, 51.32, -55.60, + 0.00, 0.00, -1.24, -1.15, -0.03, 48.29, 51.80, 0.20, + -0.20, 1.16, -1.08, -0.03, -45.59, -49.00, -0.12, 0.10, + -1.10, 1.02, 0.03, 40.54, -52.69, -0.04, -0.10, -1.18, + -0.91, -0.02, -40.58, -49.51, -1.00, 1.00, -1.11, 0.91, + 0.04, 0.02, -43.76, 46.50, 0.36, 0.40, 1.04, 0.98, + 0.03, -0.01, 62.65, -5.00, -0.24, 0.00, -0.11, -1.40, + -0.03, 0.01, -38.57, 49.59, 0.08, 0.10, 1.11, 0.86, + 0.02, -33.22, -44.04, 0.08, -0.10, -0.98, 0.74, 0.02, + 37.15, -39.90, -0.12, -0.10, -0.89, -0.83, -0.02, 36.68, + -39.50, -0.04, -0.10, -0.88, -0.82, -0.02, -53.22, -3.91, + -0.20, 0.00, -0.09, 1.19, 0.03, 32.43, -42.19, -0.04, + -0.10, -0.94, -0.73, -0.02, -51.00, -2.30, -0.12, -0.10, + 0.00, 1.14, -29.53, -39.11, 0.04, 0.00, -0.87, 0.66, + + /* 852-979 */ + 0.02, 28.50, -38.92, -0.08, -0.10, -0.87, -0.64, -0.02, + 26.54, 36.95, -0.12, 0.10, 0.83, -0.59, -0.01, 26.54, + 34.59, 0.04, -0.10, 0.77, -0.59, -0.02, 28.35, -32.55, + -0.16, 0.20, -0.73, -0.63, -0.01, -28.00, 30.40, 0.00, + 0.00, 0.68, 0.63, 0.01, -27.61, 29.40, 0.20, 0.20, + 0.66, 0.62, 0.02, 40.33, 0.40, -0.04, 0.10, 0.00, + -0.90, -23.28, 31.61, -0.08, -0.10, 0.71, 0.52, 0.01, + 37.75, 0.80, 0.04, 0.10, 0.00, -0.84, 23.66, 25.80, + 0.00, 0.00, 0.58, -0.53, -0.01, 21.01, -27.91, 0.00, + 0.00, -0.62, -0.47, -0.01, -34.81, 2.89, 0.04, 0.00, + 0.00, 0.78, -23.49, -25.31, 0.00, 0.00, -0.57, 0.53, + 0.01, -23.47, 25.20, 0.16, 0.20, 0.56, 0.52, 0.02, + 19.58, 27.50, -0.12, 0.10, 0.62, -0.44, -0.01, -22.67, + -24.40, -0.08, 0.10, -0.55, 0.51, 0.01, -19.97, 25.00, + 0.12, 0.20, 0.56, 0.45, 0.01, 21.28, -22.80, -0.08, + -0.10, -0.51, -0.48, -0.01, -30.47, 0.91, 0.04, 0.00, + + /* 980-1107 */ + 0.00, 0.68, 18.58, 24.00, 0.04, -0.10, 0.54, -0.42, + -0.01, -18.02, 24.40, -0.04, -0.10, 0.55, 0.40, 0.01, + 17.74, 22.50, 0.08, -0.10, 0.50, -0.40, -0.01, -19.41, + 20.70, 0.08, 0.10, 0.46, 0.43, 0.01, -18.64, 20.11, + 0.00, 0.00, 0.45, 0.42, 0.01, -16.75, 21.60, 0.04, + 0.10, 0.48, 0.37, 0.01, -18.42, -20.00, 0.00, 0.00, + -0.45, 0.41, 0.01, -26.77, 1.41, 0.08, 0.00, 0.00, + 0.60, -26.17, -0.19, 0.00, 0.00, 0.00, 0.59, -15.52, + 20.51, 0.00, 0.00, 0.46, 0.35, 0.01, -25.42, -1.91, + -0.08, 0.00, -0.04, 0.57, 0.45, -17.42, 18.10, 0.00, + 0.00, 0.40, 0.39, 0.01, 16.39, -17.60, -0.08, -0.10, + -0.39, -0.37, -0.01, -14.37, 18.91, 0.00, 0.00, 0.42, + 0.32, 0.01, 23.39, -2.40, -0.12, 0.00, 0.00, -0.52, + 14.32, -18.50, -0.04, -0.10, -0.41, -0.32, -0.01, 15.69, + 17.08, 0.00, 0.00, 0.38, -0.35, -0.01, -22.99, 0.50, + 0.04, 0.00, 0.00, 0.51, 0.00, 0.00, 14.47, -17.60, + + /* 1108-1235 */ + -0.01, 0.00, -0.39, -0.32, -13.33, 18.40, -0.04, -0.10, + 0.41, 0.30, 22.47, -0.60, -0.04, 0.00, 0.00, -0.50, + -12.78, -17.41, 0.04, 0.00, -0.39, 0.29, 0.01, -14.10, + -15.31, 0.04, 0.00, -0.34, 0.32, 0.01, 11.98, 16.21, + -0.04, 0.00, 0.36, -0.27, -0.01, 19.65, -1.90, -0.08, + 0.00, 0.00, -0.44, 19.61, -1.50, -0.08, 0.00, 0.00, + -0.44, 13.41, -14.30, -0.04, -0.10, -0.32, -0.30, -0.01, + -13.29, 14.40, 0.00, 0.00, 0.32, 0.30, 0.01, 11.14, + -14.40, -0.04, 0.00, -0.32, -0.25, -0.01, 12.24, -13.38, + 0.04, 0.00, -0.30, -0.27, -0.01, 10.07, -13.81, 0.04, + 0.00, -0.31, -0.23, -0.01, 10.46, 13.10, 0.08, -0.10, + 0.29, -0.23, -0.01, 16.55, -1.71, -0.08, 0.00, 0.00, + -0.37, 9.75, -12.80, 0.00, 0.00, -0.29, -0.22, -0.01, + 9.11, 12.80, 0.00, 0.00, 0.29, -0.20, 0.00, 0.00, + -6.44, -13.80, 0.00, 0.00, -0.31, 0.14, -9.19, -12.00, + 0.00, 0.00, -0.27, 0.21, -10.30, 10.90, 0.08, 0.10, + + /* 1236-1363 */ + 0.24, 0.23, 0.01, 14.92, -0.80, -0.04, 0.00, 0.00, + -0.33, 10.02, -10.80, 0.00, 0.00, -0.24, -0.22, -0.01, + -9.75, 10.40, 0.04, 0.00, 0.23, 0.22, 0.01, 9.67, + -10.40, -0.04, 0.00, -0.23, -0.22, -0.01, -8.28, -11.20, + 0.04, 0.00, -0.25, 0.19, 13.32, -1.41, -0.08, 0.00, + 0.00, -0.30, 8.27, 10.50, 0.04, 0.00, 0.23, -0.19, + 0.00, 0.00, 13.13, 0.00, 0.00, 0.00, 0.00, -0.29, + -12.93, 0.70, 0.04, 0.00, 0.00, 0.29, 7.91, -10.20, + 0.00, 0.00, -0.23, -0.18, -7.84, -10.00, -0.04, 0.00, + -0.22, 0.18, 7.44, 9.60, 0.00, 0.00, 0.21, -0.17, + -7.64, 9.40, 0.08, 0.10, 0.21, 0.17, 0.01, -11.38, + 0.60, 0.04, 0.00, 0.00, 0.25, -7.48, 8.30, 0.00, + 0.00, 0.19, 0.17, -10.98, -0.20, 0.00, 0.00, 0.00, + 0.25, 10.98, 0.20, 0.00, 0.00, 0.00, -0.25, 7.40, + -7.90, -0.04, 0.00, -0.18, -0.17, -6.09, 8.40, -0.04, + 0.00, 0.19, 0.14, -6.94, -7.49, 0.00, 0.00, -0.17, + + /* 1364-1491 */ + 0.16, 6.92, 7.50, 0.04, 0.00, 0.17, -0.15, 6.20, + 8.09, 0.00, 0.00, 0.18, -0.14, -6.12, 7.80, 0.04, + 0.00, 0.17, 0.14, 5.85, -7.50, 0.00, 0.00, -0.17, + -0.13, -6.48, 6.90, 0.08, 0.10, 0.15, 0.14, 0.01, + 6.32, 6.90, 0.00, 0.00, 0.15, -0.14, 5.61, -7.20, + 0.00, 0.00, -0.16, -0.13, 9.07, 0.00, 0.00, 0.00, + 0.00, -0.20, 5.25, 6.90, 0.00, 0.00, 0.15, -0.12, + -8.47, -0.40, 0.00, 0.00, 0.00, 0.19, 6.32, -5.39, + -1.11, 1.10, -0.12, -0.14, 0.02, 0.02, 5.73, -6.10, + -0.04, 0.00, -0.14, -0.13, 4.70, 6.60, -0.04, 0.00, + 0.15, -0.11, -4.90, -6.40, 0.00, 0.00, -0.14, 0.11, + -5.33, 5.60, 0.04, 0.10, 0.13, 0.12, 0.01, -4.81, + 6.00, 0.04, 0.00, 0.13, 0.11, 5.13, 5.50, 0.04, + 0.00, 0.12, -0.11, 4.50, 5.90, 0.00, 0.00, 0.13, + -0.10, -4.22, 6.10, 0.00, 0.00, 0.14, -4.53, 5.70, + 0.00, 0.00, 0.13, 0.10, 4.18, 5.70, 0.00, 0.00, + + /* 1492-1619 */ + 0.13, -4.75, -5.19, 0.00, 0.00, -0.12, 0.11, -4.06, + 5.60, 0.00, 0.00, 0.13, -3.98, 5.60, -0.04, 0.00, + 0.13, 4.02, -5.40, 0.00, 0.00, -0.12, 4.49, -4.90, + -0.04, 0.00, -0.11, -0.10, -3.62, -5.40, -0.16, 0.20, + -0.12, 0.00, 0.01, 4.38, 4.80, 0.00, 0.00, 0.11, + -6.40, -0.10, 0.00, 0.00, 0.00, 0.14, -3.98, 5.00, + 0.04, 0.00, 0.11, -3.82, -5.00, 0.00, 0.00, -0.11, + -3.71, 5.07, 0.00, 0.00, 0.11, 4.14, 4.40, 0.00, + 0.00, 0.10, -6.01, -0.50, -0.04, 0.00, 0.00, 0.13, + -4.04, 4.39, 0.00, 0.00, 0.10, 3.45, -4.72, 0.00, + 0.00, -0.11, 3.31, 4.71, 0.00, 0.00, 0.11, 3.26, + -4.50, 0.00, 0.00, -0.10, -3.26, -4.50, 0.00, 0.00, + -0.10, -3.34, -4.40, 0.00, 0.00, -0.10, -3.74, -4.00, + 3.70, 4.00, 3.34, -4.30, 3.30, -4.30, -3.66, 3.90, + 0.04, 3.66, 3.90, 0.04, -3.62, -3.90, -3.61, 3.90, + -0.20, 5.30, 0.00, 0.00, 0.12, 3.06, 4.30, 3.30, + + /* 1620-1747 */ + 4.00, 0.40, 0.20, 3.10, 4.10, -3.06, 3.90, -3.30, + -3.60, -3.30, 3.36, 0.01, 3.14, 3.40, -4.57, -0.20, + 0.00, 0.00, 0.00, 0.10, -2.70, -3.60, 2.94, -3.20, + -2.90, 3.20, 2.47, -3.40, 2.55, -3.30, 2.80, -3.08, + 2.51, 3.30, -4.10, 0.30, -0.12, -0.10, 4.10, 0.20, + -2.74, 3.00, 2.46, 3.23, -3.66, 1.20, -0.20, 0.20, + 3.74, -0.40, -2.51, -2.80, -3.74, 2.27, -2.90, 0.00, + 0.00, -2.50, 2.70, -2.51, 2.60, -3.50, 0.20, 3.38, + -2.22, -2.50, 3.26, -0.40, 1.95, -2.60, 3.22, -0.40, + -0.04, -1.79, -2.60, 1.91, 2.50, 0.74, 3.05, -0.04, + 0.08, 2.11, -2.30, -2.11, 2.20, -1.87, -2.40, 2.03, + -2.20, -2.03, 2.20, 2.98, 0.00, 0.00, 2.98, -1.71, + 2.40, 2.94, -0.10, -0.12, 0.10, 1.67, 2.40, -1.79, + 2.30, -1.79, 2.20, -1.67, 2.20, 1.79, -2.00, 1.87, + -1.90, 1.63, -2.10, -1.59, 2.10, 1.55, -2.10, -1.55, + 2.10, -2.59, -0.20, -1.75, -1.90, -1.75, 1.90, -1.83, + + /* 1748-1875 */ + -1.80, 1.51, 2.00, -1.51, -2.00, 1.71, 1.80, 1.31, + 2.10, -1.43, 2.00, 1.43, 2.00, -2.43, -1.51, 1.90, + -1.47, 1.90, 2.39, 0.20, -2.39, 1.39, 1.90, 1.39, + -1.80, 1.47, -1.60, 1.47, -1.60, 1.43, -1.50, -1.31, + 1.60, 1.27, -1.60, -1.27, 1.60, 1.27, -1.60, 2.03, + 1.35, 1.50, -1.39, -1.40, 1.95, -0.20, -1.27, 1.49, + 1.19, 1.50, 1.27, 1.40, 1.15, 1.50, 1.87, -0.10, + -1.12, -1.50, 1.87, -1.11, -1.50, -1.11, -1.50, 0.00, + 0.00, 1.19, 1.40, 1.27, -1.30, -1.27, -1.30, -1.15, + 1.40, -1.23, 1.30, -1.23, -1.30, 1.22, -1.29, 1.07, + -1.40, 1.75, -0.20, -1.03, -1.40, -1.07, 1.20, -1.03, + 1.15, 1.07, 1.10, 1.51, -1.03, 1.10, 1.03, -1.10, + 0.00, 0.00, -1.03, -1.10, 0.91, -1.20, -0.88, -1.20, + -0.88, 1.20, -0.95, 1.10, -0.95, -1.10, 1.43, -1.39, + 0.95, -1.00, -0.95, 1.00, -0.80, 1.10, 0.91, -1.00, + -1.35, 0.88, 1.00, -0.83, 1.00, -0.91, 0.90, 0.91, + + /* 1876-2003 */ + 0.90, 0.88, -0.90, -0.76, -1.00, -0.76, 1.00, 0.76, + 1.00, -0.72, 1.00, 0.84, -0.90, 0.84, 0.90, 1.23, + 0.00, 0.00, -0.52, -1.10, -0.68, 1.00, 1.19, -0.20, + 1.19, 0.76, 0.90, 1.15, -0.10, 1.15, -0.10, 0.72, + -0.90, -1.15, -1.15, 0.68, 0.90, -0.68, 0.90, -1.11, + 0.00, 0.00, 0.20, 0.79, 0.80, -1.11, -0.10, 0.00, + 0.00, -0.48, -1.00, -0.76, -0.80, -0.72, -0.80, -1.07, + -0.10, 0.64, 0.80, -0.64, -0.80, 0.64, 0.80, 0.40, + 0.60, 0.52, -0.50, -0.60, -0.80, -0.71, 0.70, -0.99, + 0.99, 0.56, 0.80, -0.56, 0.80, 0.68, -0.70, 0.68, + 0.70, -0.95, -0.64, 0.70, 0.64, 0.70, -0.60, 0.70, + -0.60, -0.70, -0.91, -0.10, -0.51, 0.76, -0.91, -0.56, + 0.70, 0.88, 0.88, -0.63, -0.60, 0.55, -0.60, -0.80, + 0.80, -0.80, -0.52, 0.60, 0.52, 0.60, 0.52, -0.60, + -0.48, 0.60, 0.48, 0.60, 0.48, 0.60, -0.76, 0.44, + -0.60, 0.52, -0.50, -0.52, 0.50, 0.40, 0.60, -0.40, + + /* 2004-2131 */ + -0.60, 0.40, -0.60, 0.72, -0.72, -0.51, -0.50, -0.48, + 0.50, 0.48, -0.50, -0.48, 0.50, -0.48, 0.50, 0.48, + -0.50, -0.48, -0.50, -0.68, -0.68, 0.44, 0.50, -0.64, + -0.10, -0.64, -0.10, -0.40, 0.50, 0.40, 0.50, 0.40, + 0.50, 0.00, 0.00, -0.40, -0.50, -0.36, -0.50, 0.36, + -0.50, 0.60, -0.60, 0.40, -0.40, 0.40, 0.40, -0.40, + 0.40, -0.40, 0.40, -0.56, -0.56, 0.36, -0.40, -0.36, + 0.40, 0.36, -0.40, -0.36, -0.40, 0.36, 0.40, 0.36, + 0.40, -0.52, 0.52, 0.52, 0.32, 0.40, -0.32, 0.40, + -0.32, 0.40, -0.32, 0.40, 0.32, -0.40, -0.32, -0.40, + 0.32, -0.40, 0.28, -0.40, -0.28, 0.40, 0.28, -0.40, + 0.28, 0.40, 0.48, -0.48, 0.48, 0.36, -0.30, -0.36, + -0.30, 0.00, 0.00, 0.20, 0.40, -0.44, 0.44, -0.44, + -0.44, -0.44, -0.44, 0.32, -0.30, 0.32, 0.30, 0.24, + 0.30, -0.12, -0.10, -0.28, 0.30, 0.28, 0.30, 0.28, + 0.30, 0.28, -0.30, 0.28, -0.30, 0.28, -0.30, 0.28, + + /* 2132-2259 */ + 0.30, -0.28, 0.30, 0.40, 0.40, -0.24, 0.30, 0.24, + -0.30, 0.24, -0.30, -0.24, -0.30, 0.24, 0.30, 0.24, + -0.30, -0.24, 0.30, 0.24, -0.30, -0.24, -0.30, 0.24, + -0.30, 0.24, 0.30, -0.24, 0.30, -0.24, 0.30, 0.20, + -0.30, 0.20, -0.30, 0.20, -0.30, 0.20, 0.30, 0.20, + -0.30, 0.20, -0.30, 0.20, 0.30, 0.20, 0.30, -0.20, + -0.30, 0.20, -0.30, 0.20, -0.30, -0.36, -0.36, -0.36, + -0.04, 0.30, 0.12, -0.10, -0.32, -0.24, 0.20, 0.24, + 0.20, 0.20, -0.20, -0.20, -0.20, -0.20, -0.20, 0.20, + 0.20, 0.20, -0.20, 0.20, 0.20, 0.20, 0.20, -0.20, + -0.20, 0.00, 0.00, -0.20, -0.20, -0.20, 0.20, -0.20, + 0.20, 0.20, -0.20, -0.20, -0.20, 0.20, 0.20, 0.20, + 0.20, 0.20, -0.20, 0.20, -0.20, 0.28, 0.28, 0.28, + 0.28, 0.28, 0.28, -0.28, 0.28, 0.12, 0.00, 0.24, + 0.16, -0.20, 0.16, -0.20, 0.16, -0.20, 0.16, 0.20, + -0.16, 0.20, 0.16, 0.20, -0.16, 0.20, -0.16, 0.20, + + /* 2260-2387 */ + -0.16, 0.20, 0.16, -0.20, 0.16, 0.20, 0.16, -0.20, + -0.16, 0.20, -0.16, -0.20, -0.16, 0.20, 0.16, 0.20, + 0.16, -0.20, 0.16, -0.20, 0.16, 0.20, 0.16, 0.20, + 0.16, 0.20, -0.16, -0.20, 0.16, 0.20, -0.16, 0.20, + 0.16, 0.20, -0.16, -0.20, 0.16, -0.20, 0.16, -0.20, + -0.16, -0.20, 0.24, -0.24, -0.24, 0.24, 0.24, 0.12, + 0.20, 0.12, 0.20, -0.12, -0.20, 0.12, -0.20, 0.12, + -0.20, -0.12, 0.20, -0.12, 0.20, -0.12, -0.20, 0.12, + 0.20, 0.12, 0.20, 0.12, -0.20, -0.12, 0.20, 0.12, + -0.20, -0.12, 0.20, 0.12, 0.20, 0.00, 0.00, -0.12, + 0.20, -0.12, 0.20, 0.12, -0.20, -0.12, 0.20, 0.12, + 0.20, 0.00, -0.21, -0.20, 0.00, 0.00, 0.20, -0.20, + -0.20, -0.20, 0.20, -0.16, -0.10, 0.00, 0.17, 0.16, + 0.16, 0.16, 0.16, -0.16, 0.16, 0.16, -0.16, 0.16, + -0.16, 0.16, 0.12, 0.10, 0.12, -0.10, -0.12, 0.10, + -0.12, 0.10, 0.12, -0.10, -0.12, 0.12, -0.12, 0.12, + + /* 2388-2515 */ + -0.12, 0.12, -0.12, -0.12, -0.12, -0.12, -0.12, -0.12, + -0.12, 0.12, 0.12, 0.12, 0.12, -0.12, -0.12, 0.12, + 0.12, 0.12, -0.12, 0.12, -0.12, -0.12, -0.12, 0.12, + -0.12, -0.12, 0.12, 0.00, 0.11, 0.11,-122.67, 164.70, + 203.78, 273.50, 3.58, 2.74, 6.18, -4.56, 0.00, -0.04, + 0.00, -0.07, 57.44, -77.10, 95.82, 128.60, -1.77, -1.28, + 2.85, -2.14, 82.14, 89.50, 0.00, 0.00, 2.00, -1.84, + -0.04, 47.73, -64.10, 23.79, 31.90, -1.45, -1.07, 0.69, + -0.53, -46.38, 50.50, 0.00, 0.00, 1.13, 1.04, 0.02, + -18.38, 0.00, 63.80, 0.00, 0.00, 0.41, 0.00, -1.43, + 59.07, 0.00, 0.00, 0.00, 0.00, -1.32, 57.28, 0.00, + 0.00, 0.00, 0.00, -1.28, -48.65, 0.00, -1.15, 0.00, + 0.00, 1.09, 0.00, 0.03, -18.30, 24.60, -17.30, -23.20, + 0.56, 0.41, -0.51, 0.39, -16.91, 26.90, 8.43, 13.30, + 0.60, 0.38, 0.31, -0.19, 1.23, -1.70, -19.13, -25.70, + -0.03, -0.03, -0.58, 0.43, -0.72, 0.90, -17.34, -23.30, + + /* 2516-2643 */ + 0.03, 0.02, -0.52, 0.39, -19.49, -21.30, 0.00, 0.00, + -0.48, 0.44, 0.01, 20.57, -20.10, 0.64, 0.70, -0.45, + -0.46, 0.00, -0.01, 4.89, 5.90, -16.55, 19.90, 0.14, + -0.11, 0.44, 0.37, 18.22, 19.80, 0.00, 0.00, 0.44, + -0.41, -0.01, 4.89, -5.30, -16.51, -18.00, -0.11, -0.11, + -0.41, 0.37, -17.86, 0.00, 17.10, 0.00, 0.00, 0.40, + 0.00, -0.38, 0.32, 0.00, 24.42, 0.00, 0.00, -0.01, + 0.00, -0.55, -23.79, 0.00, 0.00, 0.00, 0.00, 0.53, + 14.72, -16.00, -0.32, 0.00, -0.36, -0.33, -0.01, 0.01, + 3.34, -4.50, 11.86, 15.90, -0.11, -0.07, 0.35, -0.27, + -3.26, 4.40, 11.62, 15.60, 0.09, 0.07, 0.35, -0.26, + -19.53, 0.00, 5.09, 0.00, 0.00, 0.44, 0.00, -0.11, + -13.48, 14.70, 0.00, 0.00, 0.33, 0.30, 0.01, 10.86, + -14.60, 3.18, 4.30, -0.33, -0.24, 0.09, -0.07, -11.30, + -15.10, 0.00, 0.00, -0.34, 0.25, 0.01, 2.03, -2.70, + 10.82, 14.50, -0.07, -0.05, 0.32, -0.24, 17.46, 0.00, + + /* 2644-2771 */ + 0.00, 0.00, 0.00, -0.39, 16.43, 0.00, 0.52, 0.00, + 0.00, -0.37, 0.00, -0.01, 9.35, 0.00, 13.29, 0.00, + 0.00, -0.21, 0.00, -0.30, -10.42, 11.40, 0.00, 0.00, + 0.25, 0.23, 0.01, 0.44, 0.50, -10.38, 11.30, 0.02, + -0.01, 0.25, 0.23, -14.64, 0.00, 0.00, 0.00, 0.00, + 0.33, 0.56, 0.80, -8.67, 11.70, 0.02, -0.01, 0.26, + 0.19, 13.88, 0.00, -2.47, 0.00, 0.00, -0.31, 0.00, + 0.06, -1.99, 2.70, 7.72, 10.30, 0.06, 0.04, 0.23, + -0.17, -0.20, 0.00, 13.05, 0.00, 0.00, 0.00, 0.00, + -0.29, 6.92, -9.30, 3.34, 4.50, -0.21, -0.15, 0.10, + -0.07, -6.60, 0.00, 10.70, 0.00, 0.00, 0.15, 0.00, + -0.24, -8.04, -8.70, 0.00, 0.00, -0.19, 0.18, -10.58, + 0.00, -3.10, 0.00, 0.00, 0.24, 0.00, 0.07, -7.32, + 8.00, -0.12, -0.10, 0.18, 0.16, 1.63, 1.70, 6.96, + -7.60, 0.03, -0.04, -0.17, -0.16, -3.62, 0.00, 9.86, + 0.00, 0.00, 0.08, 0.00, -0.22, 0.20, -0.20, -6.88, + + /* 2772-2899 */ + -7.50, 0.00, 0.00, -0.17, 0.15, -8.99, 0.00, 4.02, + 0.00, 0.00, 0.20, 0.00, -0.09, -1.07, 1.40, -5.69, + -7.70, 0.03, 0.02, -0.17, 0.13, 6.48, -7.20, -0.48, + -0.50, -0.16, -0.14, -0.01, 0.01, 5.57, -7.50, 1.07, + 1.40, -0.17, -0.12, 0.03, -0.02, 8.71, 0.00, 3.54, + 0.00, 0.00, -0.19, 0.00, -0.08, 0.40, 0.00, 9.27, + 0.00, 0.00, -0.01, 0.00, -0.21, -6.13, 6.70, -1.19, + -1.30, 0.15, 0.14, -0.03, 0.03, 5.21, -5.70, -2.51, + -2.60, -0.13, -0.12, -0.06, 0.06, 5.69, -6.20, -0.12, + -0.10, -0.14, -0.13, -0.01, 2.03, -2.70, 4.53, 6.10, + -0.06, -0.05, 0.14, -0.10, 5.01, 5.50, -2.51, 2.70, + 0.12, -0.11, 0.06, 0.06, -1.91, 2.60, -4.38, -5.90, + 0.06, 0.04, -0.13, 0.10, 4.65, -6.30, 0.00, 0.00, + -0.14, -0.10, -5.29, 5.70, 0.00, 0.00, 0.13, 0.12, + -2.23, -4.00, -4.65, 4.20, -0.09, 0.05, 0.10, 0.10, + -4.53, 6.10, 0.00, 0.00, 0.14, 0.10, 2.47, 2.70, + + /* 2900-3027 */ + -4.46, 4.90, 0.06, -0.06, 0.11, 0.10, -5.05, 5.50, + 0.84, 0.90, 0.12, 0.11, 0.02, -0.02, 4.97, -5.40, + -1.71, 0.00, -0.12, -0.11, 0.00, 0.04, -0.99, -1.30, + 4.22, -5.70, -0.03, 0.02, -0.13, -0.09, 0.99, 1.40, + 4.22, -5.60, 0.03, -0.02, -0.13, -0.09, -4.69, -5.20, + 0.00, 0.00, -0.12, 0.10, -3.42, 0.00, 6.09, 0.00, + 0.00, 0.08, 0.00, -0.14, -4.65, -5.10, 0.00, 0.00, + -0.11, 0.10, 0.00, 0.00, -4.53, -5.00, 0.00, 0.00, + -0.11, 0.10, -2.43, -2.70, -3.82, 4.20, -0.06, 0.05, + 0.10, 0.09, 0.00, 0.00, -4.53, 4.90, 0.00, 0.00, + 0.11, 0.10, -4.49, -4.90, 0.00, 0.00, -0.11, 0.10, + 2.67, -2.90, -3.62, -3.90, -0.06, -0.06, -0.09, 0.08, + 3.94, -5.30, 0.00, 0.00, -0.12, -3.38, 3.70, -2.78, + -3.10, 0.08, 0.08, -0.07, 0.06, 3.18, -3.50, -2.82, + -3.10, -0.08, -0.07, -0.07, 0.06, -5.77, 0.00, 1.87, + 0.00, 0.00, 0.13, 0.00, -0.04, 3.54, -4.80, -0.64, + + /* 3028-3155 */ + -0.90, -0.11, 0.00, -0.02, -3.50, -4.70, 0.68, -0.90, + -0.11, 0.00, -0.02, 5.49, 0.00, 0.00, 0.00, 0.00, + -0.12, 1.83, -2.50, 2.63, 3.50, -0.06, 0.00, 0.08, + 3.02, -4.10, 0.68, 0.90, -0.09, 0.00, 0.02, 0.00, + 0.00, 5.21, 0.00, 0.00, 0.00, 0.00, -0.12, -3.54, + 3.80, 2.70, 3.60, -1.35, 1.80, 0.08, 0.00, 0.04, + -2.90, 3.90, 0.68, 0.90, 0.09, 0.00, 0.02, 0.80, + -1.10, -2.78, -3.70, -0.02, 0.00, -0.08, 4.10, 0.00, + -2.39, 0.00, 0.00, -0.09, 0.00, 0.05, -1.59, 2.10, + 2.27, 3.00, 0.05, 0.00, 0.07, -2.63, 3.50, -0.48, + -0.60, -2.94, -3.20, -2.94, 3.20, 2.27, -3.00, -1.11, + -1.50, -0.07, 0.00, -0.03, -0.56, -0.80, -2.35, 3.10, + 0.00, -0.60, -3.42, 1.90, -0.12, -0.10, 2.63, -2.90, + 2.51, 2.80, -0.64, 0.70, -0.48, -0.60, 2.19, -2.90, + 0.24, -0.30, 2.15, 2.90, 2.15, -2.90, 0.52, 0.70, + 2.07, -2.80, -3.10, 0.00, 1.79, 0.00, 0.00, 0.07, + + /* 3156-3283 */ + 0.00, -0.04, 0.88, 0.00, -3.46, 2.11, 2.80, -0.36, + 0.50, 3.54, -0.20, -3.50, -1.39, 1.50, -1.91, -2.10, + -1.47, 2.00, 1.39, 1.90, 2.07, -2.30, 0.91, 1.00, + 1.99, -2.70, 3.30, 0.00, 0.60, -0.44, -0.70, -1.95, + 2.60, 2.15, -2.40, -0.60, -0.70, 3.30, 0.84, 0.00, + -3.10, -3.10, 0.00, -0.72, -0.32, 0.40, -1.87, -2.50, + 1.87, -2.50, 0.32, 0.40, -0.24, 0.30, -1.87, -2.50, + -0.24, -0.30, 1.87, -2.50, -2.70, 0.00, 1.55, 2.03, + 2.20, -2.98, -1.99, -2.20, 0.12, -0.10, -0.40, 0.50, + 1.59, 2.10, 0.00, 0.00, -1.79, 2.00, -1.03, 1.40, + -1.15, -1.60, 0.32, 0.50, 1.39, -1.90, 2.35, -1.27, + 1.70, 0.60, 0.80, -0.32, -0.40, 1.35, -1.80, 0.44, + 0.00, 2.23, -0.84, 0.90, -1.27, -1.40, -1.47, 1.60, + -0.28, -0.30, -0.28, 0.40, -1.27, -1.70, 0.28, -0.40, + -1.43, -1.50, 0.00, 0.00, -1.27, -1.70, 2.11, -0.32, + -0.40, -1.23, 1.60, 1.19, -1.30, -0.72, -0.80, 0.72, + + /* 3284-3411 */ + -0.80, -1.15, -1.30, -1.35, -1.50, -1.19, -1.60, -0.12, + 0.20, 1.79, 0.00, -0.88, -0.28, 0.40, 1.11, 1.50, + -1.83, 0.00, 0.56, -0.12, 0.10, -1.27, -1.40, 0.00, + 0.00, 1.15, 1.50, -0.12, 0.20, 1.11, 1.50, 0.36, + -0.50, -1.07, -1.40, -1.11, 1.50, 1.67, 0.00, 0.80, + -1.11, 0.00, 1.43, 1.23, -1.30, -0.24, -1.19, -1.30, + -0.24, 0.20, -0.44, -0.90, -0.95, 1.10, 1.07, -1.40, + 1.15, -1.30, 1.03, -1.10, -0.56, -0.60, -0.68, 0.90, + -0.76, -1.00, -0.24, -0.30, 0.95, -1.30, 0.56, 0.70, + 0.84, -1.10, -0.56, 0.00, -1.55, 0.91, -1.30, 0.28, + 0.30, 0.16, -0.20, 0.95, 1.30, 0.40, -0.50, -0.88, + -1.20, 0.95, -1.10, -0.48, -0.50, 0.00, 0.00, -1.07, + 1.20, 0.44, -0.50, 0.95, 1.10, 0.00, 0.00, 0.92, + -1.30, 0.95, 1.00, -0.52, 0.60, 1.59, 0.24, -0.40, + 0.91, 1.20, 0.84, -1.10, -0.44, -0.60, 0.84, 1.10, + -0.44, 0.60, -0.44, 0.60, -0.84, -1.10, -0.80, 0.00, + + /* 3412-3539 */ + 1.35, 0.76, 0.20, -0.91, -1.00, 0.20, -0.30, -0.91, + -1.20, -0.95, 1.00, -0.48, -0.50, 0.88, 1.00, 0.48, + -0.50, -0.95, -1.10, 0.20, -0.20, -0.99, 1.10, -0.84, + 1.10, -0.24, -0.30, 0.20, -0.30, 0.84, 1.10, -1.39, + 0.00, -0.28, -0.16, 0.20, 0.84, 1.10, 0.00, 0.00, + 1.39, 0.00, 0.00, -0.95, 1.00, 1.35, -0.99, 0.00, + 0.88, -0.52, 0.00, -1.19, 0.20, 0.20, 0.76, -1.00, + 0.00, 0.00, 0.76, 1.00, 0.00, 0.00, 0.76, 1.00, + -0.76, 1.00, 0.00, 0.00, 1.23, 0.76, 0.80, -0.32, + 0.40, -0.72, 0.80, -0.40, -0.40, 0.00, 0.00, -0.80, + -0.90, -0.68, 0.90, -0.16, -0.20, -0.16, -0.20, 0.68, + -0.90, -0.36, 0.50, -0.56, -0.80, 0.72, -0.90, 0.44, + -0.60, -0.48, -0.70, -0.16, 0.00, -1.11, 0.32, 0.00, + -1.07, 0.60, -0.80, -0.28, -0.40, -0.64, 0.00, 0.91, + 1.11, 0.64, -0.90, 0.76, -0.80, 0.00, 0.00, -0.76, + -0.80, 1.03, 0.00, -0.36, -0.64, -0.70, 0.36, -0.40, + + /* 3540-3667 */ + 1.07, 0.36, -0.50, -0.52, -0.70, 0.60, 0.00, 0.88, + 0.95, 0.00, 0.48, 0.16, -0.20, 0.60, 0.80, 0.16, + -0.20, -0.60, -0.80, 0.00, -1.00, 0.12, 0.20, 0.16, + -0.20, 0.68, 0.70, 0.59, -0.80, -0.99, -0.56, -0.60, + 0.36, -0.40, -0.68, -0.70, -0.68, -0.70, -0.36, -0.50, + -0.44, 0.60, 0.64, 0.70, -0.12, 0.10, -0.52, 0.60, + 0.36, 0.40, 0.00, 0.00, 0.95, -0.84, 0.00, 0.44, + 0.56, 0.60, 0.32, -0.30, 0.00, 0.00, 0.60, 0.70, + 0.00, 0.00, 0.60, 0.70, -0.12, -0.20, 0.52, -0.70, + 0.00, 0.00, 0.56, 0.70, -0.12, 0.10, -0.52, -0.70, + 0.00, 0.00, 0.88, -0.76, 0.00, -0.44, 0.00, 0.00, + -0.52, -0.70, 0.52, -0.70, 0.36, -0.40, -0.44, -0.50, + 0.00, 0.00, 0.60, 0.60, 0.84, 0.00, 0.12, -0.24, + 0.00, 0.80, -0.56, 0.60, -0.32, -0.30, 0.48, -0.50, + 0.28, -0.30, -0.48, -0.50, 0.12, 0.20, 0.48, -0.60, + 0.48, 0.60, -0.12, 0.20, 0.24, 0.00, 0.76, -0.52, + + /* 3668-3795 */ + -0.60, -0.52, 0.60, 0.48, -0.50, -0.24, -0.30, 0.12, + -0.10, 0.48, 0.60, 0.52, -0.20, 0.36, 0.40, -0.44, + 0.50, -0.24, -0.30, -0.48, -0.60, -0.44, -0.60, -0.12, + 0.10, 0.76, 0.76, 0.20, -0.20, 0.48, 0.50, 0.40, + -0.50, -0.24, -0.30, 0.44, -0.60, 0.44, -0.60, 0.36, + 0.00, -0.64, 0.72, 0.00, -0.12, 0.00, -0.10, -0.40, + -0.60, -0.20, -0.20, -0.44, 0.50, -0.44, 0.50, 0.20, + 0.20, -0.44, -0.50, 0.20, -0.20, -0.20, 0.20, -0.44, + -0.50, 0.64, 0.00, 0.32, -0.36, 0.50, -0.20, -0.30, + 0.12, -0.10, 0.48, 0.50, -0.12, 0.30, -0.36, -0.50, + 0.00, 0.00, 0.48, 0.50, -0.48, 0.50, 0.68, 0.00, + -0.12, 0.56, -0.40, 0.44, -0.50, -0.12, -0.10, 0.24, + 0.30, -0.40, 0.40, 0.64, 0.00, -0.24, 0.64, 0.00, + -0.20, 0.00, 0.00, 0.44, -0.50, 0.44, 0.50, -0.12, + 0.20, -0.36, -0.50, 0.12, 0.00, 0.64, -0.40, 0.50, + 0.00, 0.10, 0.00, 0.00, -0.40, 0.50, 0.00, 0.00, + + /* 3796-3923 */ + -0.40, -0.50, 0.56, 0.00, 0.28, 0.00, 0.10, 0.36, + 0.50, 0.00, -0.10, 0.36, -0.50, 0.36, 0.50, 0.00, + -0.10, 0.24, -0.20, -0.36, -0.40, 0.16, 0.20, 0.40, + -0.40, 0.00, 0.00, -0.36, -0.50, -0.36, -0.50, -0.32, + -0.50, -0.12, 0.10, 0.20, 0.20, -0.36, 0.40, -0.60, + 0.60, 0.28, 0.00, 0.52, 0.12, -0.10, 0.40, 0.40, + 0.00, -0.50, 0.20, -0.20, -0.32, 0.40, 0.16, 0.20, + -0.16, 0.20, 0.32, 0.40, 0.56, 0.00, -0.12, 0.32, + -0.40, -0.16, -0.20, 0.00, 0.00, 0.40, 0.40, -0.40, + -0.40, -0.40, 0.40, -0.36, 0.40, 0.12, 0.10, 0.00, + 0.10, 0.36, 0.40, 0.00, -0.10, 0.36, 0.40, -0.36, + 0.40, 0.00, 0.10, 0.32, 0.00, 0.44, 0.12, 0.20, + 0.28, -0.40, 0.00, 0.00, 0.36, 0.40, 0.32, -0.40, + -0.16, 0.12, 0.10, 0.32, -0.40, 0.20, 0.30, -0.24, + 0.30, 0.00, 0.10, 0.32, 0.40, 0.00, -0.10, -0.32, + -0.40, -0.32, 0.40, 0.00, 0.10, -0.52, -0.52, 0.52, + + /* 3924-4051 */ + 0.32, -0.40, 0.00, 0.00, 0.32, 0.40, 0.32, -0.40, + 0.00, 0.00, -0.32, -0.40, -0.32, 0.40, 0.32, 0.40, + 0.00, 0.00, 0.32, 0.40, 0.00, 0.00, -0.32, -0.40, + 0.00, 0.00, 0.32, 0.40, 0.16, 0.20, 0.32, -0.30, + -0.16, 0.00, -0.48, -0.20, 0.20, -0.28, -0.30, 0.28, + -0.40, 0.00, 0.00, 0.28, -0.40, 0.00, 0.00, 0.28, + -0.40, 0.00, 0.00, -0.28, -0.40, 0.28, 0.40, -0.28, + -0.40, -0.48, -0.20, 0.20, 0.24, 0.30, 0.44, 0.00, + 0.16, 0.24, 0.30, 0.16, -0.20, 0.24, 0.30, -0.12, + 0.20, 0.20, 0.30, -0.16, 0.20, 0.00, 0.00, 0.44, + -0.32, 0.30, 0.24, 0.00, -0.36, 0.36, 0.00, 0.24, + 0.12, -0.20, 0.20, 0.30, -0.12, 0.00, -0.28, 0.30, + -0.24, 0.30, 0.12, 0.10, -0.28, -0.30, -0.28, 0.30, + 0.00, 0.00, -0.28, -0.30, 0.00, 0.00, -0.28, -0.30, + 0.00, 0.00, 0.28, 0.30, 0.00, 0.00, -0.28, -0.30, + -0.28, 0.30, 0.00, 0.00, -0.28, -0.30, 0.00, 0.00, + + /* 4052-4179 */ + 0.28, 0.30, 0.00, 0.00, -0.28, 0.30, 0.28, -0.30, + -0.28, 0.30, 0.40, 0.40, -0.24, 0.30, 0.00, -0.10, + 0.16, 0.00, 0.36, -0.20, 0.30, -0.12, -0.10, -0.24, + -0.30, 0.00, 0.00, -0.24, 0.30, -0.24, 0.30, 0.00, + 0.00, -0.24, 0.30, -0.24, 0.30, 0.24, -0.30, 0.00, + 0.00, 0.24, -0.30, 0.00, 0.00, 0.24, 0.30, 0.24, + -0.30, 0.24, 0.30, -0.24, 0.30, -0.24, 0.30, -0.20, + 0.20, -0.16, -0.20, 0.00, 0.00, -0.32, 0.20, 0.00, + 0.10, 0.20, -0.30, 0.20, -0.20, 0.12, 0.20, -0.16, + 0.20, 0.16, 0.20, 0.20, 0.30, 0.20, 0.30, 0.00, + 0.00, -0.20, 0.30, 0.00, 0.00, 0.20, 0.30, -0.20, + -0.30, -0.20, -0.30, 0.20, -0.30, 0.00, 0.00, 0.20, + 0.30, 0.00, 0.00, 0.20, 0.30, 0.00, 0.00, 0.20, + 0.30, 0.00, 0.00, 0.20, 0.30, 0.00, 0.00, 0.20, + -0.30, 0.00, 0.00, -0.20, -0.30, 0.00, 0.00, -0.20, + 0.30, 0.00, 0.00, -0.20, 0.30, 0.00, 0.00, 0.36, + + /* 4180-4307 */ + 0.00, 0.00, 0.36, 0.12, 0.10, -0.24, 0.20, 0.12, + -0.20, -0.16, -0.20, -0.13, 0.10, 0.22, 0.21, 0.20, + 0.00, -0.28, 0.32, 0.00, -0.12, -0.20, -0.20, 0.12, + -0.10, 0.12, 0.10, -0.20, 0.20, 0.00, 0.00, -0.32, + 0.32, 0.00, 0.00, 0.32, 0.32, 0.00, 0.00, -0.24, + -0.20, 0.24, 0.20, 0.20, 0.00, -0.24, 0.00, 0.00, + -0.24, -0.20, 0.00, 0.00, 0.24, 0.20, -0.24, -0.20, + 0.00, 0.00, -0.24, 0.20, 0.16, -0.20, 0.12, 0.10, + 0.20, 0.20, 0.00, -0.10, -0.12, 0.10, -0.16, -0.20, + -0.12, -0.10, -0.16, 0.20, 0.20, 0.20, 0.00, 0.00, + -0.20, 0.20, -0.20, 0.20, -0.20, 0.20, -0.20, 0.20, + 0.20, -0.20, -0.20, -0.20, 0.00, 0.00, -0.20, 0.20, + 0.20, 0.00, -0.20, 0.00, 0.00, -0.20, 0.20, -0.20, + 0.20, -0.20, -0.20, -0.20, -0.20, 0.00, 0.00, 0.20, + 0.20, 0.20, 0.20, 0.12, -0.20, -0.12, -0.10, 0.28, + -0.28, 0.16, -0.20, 0.00, -0.10, 0.00, 0.10, -0.16, + + /* 4308-4435 */ + 0.20, 0.00, -0.10, -0.16, -0.20, 0.00, -0.10, 0.16, + -0.20, 0.16, -0.20, 0.00, 0.00, 0.16, 0.20, -0.16, + 0.20, 0.00, 0.00, 0.16, 0.20, 0.16, -0.20, 0.16, + -0.20, -0.16, 0.20, 0.16, -0.20, 0.00, 0.00, 0.16, + 0.20, 0.00, 0.00, 0.16, 0.20, 0.00, 0.00, -0.16, + -0.20, 0.16, -0.20, -0.16, -0.20, 0.00, 0.00, -0.16, + -0.20, 0.00, 0.00, -0.16, 0.20, 0.00, 0.00, 0.16, + -0.20, 0.16, 0.20, 0.16, 0.20, 0.00, 0.00, -0.16, + -0.20, 0.00, 0.00, -0.16, -0.20, 0.00, 0.00, 0.16, + 0.20, 0.16, 0.20, 0.00, 0.00, 0.16, 0.20, 0.16, + -0.20, 0.16, 0.20, 0.00, 0.00, -0.16, 0.20, 0.00, + 0.10, 0.12, -0.20, 0.12, -0.20, 0.00, -0.10, 0.00, + -0.10, 0.12, 0.20, 0.00, -0.10, -0.12, 0.20, -0.15, + 0.20, -0.24, 0.24, 0.00, 0.00, 0.24, 0.24, 0.12, + -0.20, -0.12, -0.20, 0.00, 0.00, 0.12, 0.20, 0.12, + -0.20, 0.12, 0.20, 0.12, 0.20, 0.12, 0.20, 0.12, + + /* 4436-4563 */ + -0.20, -0.12, 0.20, 0.00, 0.00, 0.12, 0.20, 0.12, + 0.00, -0.20, 0.00, 0.00, -0.12, -0.20, 0.12, -0.20, + 0.00, 0.00, 0.12, 0.20, -0.12, 0.20, -0.12, 0.20, + 0.12, -0.20, 0.00, 0.00, 0.12, 0.20, 0.20, 0.00, + 0.12, 0.00, 0.00, -0.12, 0.20, 0.00, 0.00, -0.12, + -0.20, 0.00, 0.00, -0.12, -0.20, -0.12, -0.20, 0.00, + 0.00, 0.12, -0.20, 0.12, -0.20, 0.12, 0.20, -0.12, + -0.20, 0.00, 0.00, 0.12, -0.20, 0.12, -0.20, 0.12, + 0.20, 0.12, 0.00, 0.20, -0.12, -0.20, 0.00, 0.00, + 0.12, 0.20, -0.16, 0.00, 0.16, -0.20, 0.20, 0.00, + 0.00, -0.20, 0.00, 0.00, -0.20, 0.20, 0.00, 0.00, + 0.20, 0.20, -0.20, 0.00, 0.00, -0.20, 0.12, 0.00, + -0.16, 0.20, 0.00, 0.00, 0.20, 0.12, -0.10, 0.00, + 0.10, 0.16, -0.16, -0.16, -0.16, -0.16, -0.16, 0.00, + 0.00, -0.16, 0.00, 0.00, -0.16, -0.16, -0.16, 0.00, + 0.00, -0.16, 0.00, 0.00, 0.16, 0.00, 0.00, 0.16, + + /* 4564-4691 */ + 0.00, 0.00, 0.16, 0.16, 0.00, 0.00, -0.16, 0.00, + 0.00, -0.16, -0.16, 0.00, 0.00, 0.16, 0.00, 0.00, + -0.16, -0.16, 0.00, 0.00, -0.16, -0.16, 0.12, 0.10, + 0.12, -0.10, 0.12, 0.10, 0.00, 0.00, 0.12, 0.10, + -0.12, 0.10, 0.00, 0.00, 0.12, 0.10, 0.12, -0.10, + 0.00, 0.00, -0.12, -0.10, 0.00, 0.00, 0.12, 0.10, + 0.12, 0.00, 0.00, 0.12, 0.00, 0.00, -0.12, 0.00, + 0.00, 0.12, 0.12, 0.12, 0.12, 0.12, 0.00, 0.00, + 0.12, 0.00, 0.00, 0.12, 0.12, 0.00, 0.00, 0.12, + 0.00, 0.00, 0.12, -0.12, -0.12, 0.12, 0.12, -0.12, + -0.12, 0.00, 0.00, 0.12, -0.12, 0.12, 0.12, -0.12, + -0.12, 0.00, 0.00, -0.12, -0.12, 0.00, 0.00, -0.12, + 0.12, 0.00, 0.00, 0.12, 0.00, 0.00, 0.12, 0.00, + 0.00, 0.12, -0.12, 0.00, 0.00, -0.12, 0.12, -0.12, + -0.12, 0.12, 0.00, 0.00, 0.12, 0.12, 0.12, -0.12, + 0.00, 0.00, -0.12, -0.12, -0.12, 0.00, 0.00, -0.12, + + /* 4692-NA */ + -0.12, 0.00, 0.00, 0.12, 0.12, 0.00, 0.00, -0.12, + -0.12, -0.12, -0.12, 0.12, 0.00, 0.00, 0.12, -0.12, + 0.00, 0.00, -0.12, -0.12, 0.00, 0.00, 0.12, -0.12, + -0.12, -0.12, -0.12, 0.12, 0.12, -0.12, -0.12, 0.00, + 0.00, -0.12, 0.00, 0.00, -0.12, 0.12, 0.00, 0.00, + 0.12, 0.00, 0.00, -0.12, -0.12, 0.00, 0.00, -0.12, + -0.12, 0.12, 0.00, 0.00, 0.12, 0.12, 0.00, 0.00, + 0.12, 0.00, 0.00, 0.12, 0.12, 0.08, 0.00, 0.04 + }; + +/* Number of amplitude coefficients */ + static const int NA = (int) (sizeof a / sizeof (double)); + +/* Amplitude usage: X or Y, sin or cos, power of T. */ + static const int jaxy[] = {0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}; + static const int jasc[] = {0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0}; + static const int japt[] = {0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4}; + +/* Miscellaneous */ + double t, w, pt[MAXPT+1], fa[14], xypr[2], xypl[2], xyls[2], arg, + sc[2]; + int jpt, i, j, jxy, ialast, ifreq, m, ia, jsc; + +/* ------------------------------------------------------------------ */ + +/* Interval between fundamental date J2000.0 and given date (JC). */ + t = ((date1 - DJ00) + date2) / DJC; + +/* Powers of T. */ + w = 1.0; + for (jpt = 0; jpt <= MAXPT; jpt++) { + pt[jpt] = w; + w *= t; + } + +/* Initialize totals in X and Y: polynomial, luni-solar, planetary. */ + for (jxy = 0; jxy < 2; jxy++) { + xypr[jxy] = 0.0; + xyls[jxy] = 0.0; + xypl[jxy] = 0.0; + } + +/* --------------------------------- */ +/* Fundamental arguments (IERS 2003) */ +/* --------------------------------- */ + +/* Mean anomaly of the Moon. */ + fa[0] = iauFal03(t); + +/* Mean anomaly of the Sun. */ + fa[1] = iauFalp03(t); + +/* Mean argument of the latitude of the Moon. */ + fa[2] = iauFaf03(t); + +/* Mean elongation of the Moon from the Sun. */ + fa[3] = iauFad03(t); + +/* Mean longitude of the ascending node of the Moon. */ + fa[4] = iauFaom03(t); + +/* Planetary longitudes, Mercury through Neptune. */ + fa[5] = iauFame03(t); + fa[6] = iauFave03(t); + fa[7] = iauFae03(t); + fa[8] = iauFama03(t); + fa[9] = iauFaju03(t); + fa[10] = iauFasa03(t); + fa[11] = iauFaur03(t); + fa[12] = iauFane03(t); + +/* General accumulated precession in longitude. */ + fa[13] = iauFapa03(t); + +/* -------------------------------------- */ +/* Polynomial part of precession-nutation */ +/* -------------------------------------- */ + + for (jxy = 0; jxy < 2; jxy++) { + for (j = MAXPT; j >= 0; j--) { + xypr[jxy] += xyp[jxy][j] * pt[j]; + } + } + +/* ---------------------------------- */ +/* Nutation periodic terms, planetary */ +/* ---------------------------------- */ + +/* Work backwards through the coefficients per frequency list. */ + ialast = NA; + for (ifreq = NFPL-1; ifreq >= 0; ifreq--) { + + /* Obtain the argument functions. */ + arg = 0.0; + for (i = 0; i < 14; i++) { + m = mfapl[ifreq][i]; + if (m != 0) arg += (double)m * fa[i]; + } + sc[0] = sin(arg); + sc[1] = cos(arg); + + /* Work backwards through the amplitudes at this frequency. */ + ia = nc[ifreq+NFLS]; + for (i = ialast; i >= ia; i--) { + + /* Coefficient number (0 = 1st). */ + j = i-ia; + + /* X or Y. */ + jxy = jaxy[j]; + + /* Sin or cos. */ + jsc = jasc[j]; + + /* Power of T. */ + jpt = japt[j]; + + /* Accumulate the component. */ + xypl[jxy] += a[i-1] * sc[jsc] * pt[jpt]; + } + ialast = ia-1; + } + +/* ----------------------------------- */ +/* Nutation periodic terms, luni-solar */ +/* ----------------------------------- */ + +/* Continue working backwards through the number of coefficients list. */ + for (ifreq = NFLS-1; ifreq >= 0; ifreq--) { + + /* Obtain the argument functions. */ + arg = 0.0; + for (i = 0; i < 5; i++) { + m = mfals[ifreq][i]; + if (m != 0) arg += (double)m * fa[i]; + } + sc[0] = sin(arg); + sc[1] = cos(arg); + + /* Work backwards through the amplitudes at this frequency. */ + ia = nc[ifreq]; + for (i = ialast; i >= ia; i--) { + + /* Coefficient number (0 = 1st). */ + j = i-ia; + + /* X or Y. */ + jxy = jaxy[j]; + + /* Sin or cos. */ + jsc = jasc[j]; + + /* Power of T. */ + jpt = japt[j]; + + /* Accumulate the component. */ + xyls[jxy] += a[i-1] * sc[jsc] * pt[jpt]; + } + ialast = ia-1; + } + +/* ------------------------------------ */ +/* Results: CIP unit vector components */ +/* ------------------------------------ */ + + *x = DAS2R * (xypr[0] + (xyls[0] + xypl[0]) / 1e6); + *y = DAS2R * (xypr[1] + (xyls[1] + xypl[1]) / 1e6); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/xys00a.c b/src/cpp/3rdparty/sofa/src/xys00a.c new file mode 100644 index 000000000..664cfd602 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/xys00a.c @@ -0,0 +1,183 @@ +#include "sofa.h" + +void iauXys00a(double date1, double date2, + double *x, double *y, double *s) +/* +** - - - - - - - - - - +** i a u X y s 0 0 a +** - - - - - - - - - - +** +** For a given TT date, compute the X,Y coordinates of the Celestial +** Intermediate Pole and the CIO locator s, using the IAU 2000A +** precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** x,y double Celestial Intermediate Pole (Note 2) +** s double the CIO locator s (Note 3) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The Celestial Intermediate Pole coordinates are the x,y +** components of the unit vector in the Geocentric Celestial +** Reference System. +** +** 3) The CIO locator s (in radians) positions the Celestial +** Intermediate Origin on the equator of the CIP. +** +** 4) A faster, but slightly less accurate result (about 1 mas for +** X,Y), can be obtained by using instead the iauXys00b function. +** +** Called: +** iauPnm00a classical NPB matrix, IAU 2000A +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS00 the CIO locator s, given X,Y, IAU 2000A +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3]; + + +/* Form the bias-precession-nutation matrix, IAU 2000A. */ + iauPnm00a(date1, date2, rbpn); + +/* Extract X,Y. */ + iauBpn2xy(rbpn, x, y); + +/* Obtain s. */ + *s = iauS00(date1, date2, *x, *y); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/xys00b.c b/src/cpp/3rdparty/sofa/src/xys00b.c new file mode 100644 index 000000000..b6a9f4baf --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/xys00b.c @@ -0,0 +1,183 @@ +#include "sofa.h" + +void iauXys00b(double date1, double date2, + double *x, double *y, double *s) +/* +** - - - - - - - - - - +** i a u X y s 0 0 b +** - - - - - - - - - - +** +** For a given TT date, compute the X,Y coordinates of the Celestial +** Intermediate Pole and the CIO locator s, using the IAU 2000B +** precession-nutation model. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** x,y double Celestial Intermediate Pole (Note 2) +** s double the CIO locator s (Note 3) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The Celestial Intermediate Pole coordinates are the x,y +** components of the unit vector in the Geocentric Celestial +** Reference System. +** +** 3) The CIO locator s (in radians) positions the Celestial +** Intermediate Origin on the equator of the CIP. +** +** 4) The present function is faster, but slightly less accurate (about +** 1 mas in X,Y), than the iauXys00a function. +** +** Called: +** iauPnm00b classical NPB matrix, IAU 2000B +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS00 the CIO locator s, given X,Y, IAU 2000A +** +** Reference: +** +** McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003), +** IERS Technical Note No. 32, BKG (2004) +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3]; + + +/* Form the bias-precession-nutation matrix, IAU 2000A. */ + iauPnm00b(date1, date2, rbpn); + +/* Extract X,Y. */ + iauBpn2xy(rbpn, x, y); + +/* Obtain s. */ + *s = iauS00(date1, date2, *x, *y); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/xys06a.c b/src/cpp/3rdparty/sofa/src/xys06a.c new file mode 100644 index 000000000..981009d13 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/xys06a.c @@ -0,0 +1,183 @@ +#include "sofa.h" + +void iauXys06a(double date1, double date2, + double *x, double *y, double *s) +/* +** - - - - - - - - - - +** i a u X y s 0 6 a +** - - - - - - - - - - +** +** For a given TT date, compute the X,Y coordinates of the Celestial +** Intermediate Pole and the CIO locator s, using the IAU 2006 +** precession and IAU 2000A nutation models. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: support function. +** +** Given: +** date1,date2 double TT as a 2-part Julian Date (Note 1) +** +** Returned: +** x,y double Celestial Intermediate Pole (Note 2) +** s double the CIO locator s (Note 3) +** +** Notes: +** +** 1) The TT date date1+date2 is a Julian Date, apportioned in any +** convenient way between the two arguments. For example, +** JD(TT)=2450123.7 could be expressed in any of these ways, +** among others: +** +** date1 date2 +** +** 2450123.7 0.0 (JD method) +** 2451545.0 -1421.3 (J2000 method) +** 2400000.5 50123.2 (MJD method) +** 2450123.5 0.2 (date & time method) +** +** The JD method is the most natural and convenient to use in +** cases where the loss of several decimal digits of resolution +** is acceptable. The J2000 method is best matched to the way +** the argument is handled internally and will deliver the +** optimum resolution. The MJD method and the date & time methods +** are both good compromises between resolution and convenience. +** +** 2) The Celestial Intermediate Pole coordinates are the x,y components +** of the unit vector in the Geocentric Celestial Reference System. +** +** 3) The CIO locator s (in radians) positions the Celestial +** Intermediate Origin on the equator of the CIP. +** +** 4) Series-based solutions for generating X and Y are also available: +** see Capitaine & Wallace (2006) and iauXy06. +** +** Called: +** iauPnm06a classical NPB matrix, IAU 2006/2000A +** iauBpn2xy extract CIP X,Y coordinates from NPB matrix +** iauS06 the CIO locator s, given X,Y, IAU 2006 +** +** References: +** +** Capitaine, N. & Wallace, P.T., 2006, Astron.Astrophys. 450, 855 +** +** Wallace, P.T. & Capitaine, N., 2006, Astron.Astrophys. 459, 981 +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + double rbpn[3][3]; + + +/* Form the bias-precession-nutation matrix, IAU 2006/2000A. */ + iauPnm06a(date1, date2, rbpn); + +/* Extract X,Y. */ + iauBpn2xy(rbpn, x, y); + +/* Obtain s. */ + *s = iauS06(date1, date2, *x, *y); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/zp.c b/src/cpp/3rdparty/sofa/src/zp.c new file mode 100644 index 000000000..be7d08344 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/zp.c @@ -0,0 +1,127 @@ +#include "sofa.h" + +void iauZp(double p[3]) +/* +** - - - - - - +** i a u Z p +** - - - - - - +** +** Zero a p-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Returned: +** p double[3] zero p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + p[0] = 0.0; + p[1] = 0.0; + p[2] = 0.0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/zpv.c b/src/cpp/3rdparty/sofa/src/zpv.c new file mode 100644 index 000000000..bcee7c00c --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/zpv.c @@ -0,0 +1,129 @@ +#include "sofa.h" + +void iauZpv(double pv[2][3]) +/* +** - - - - - - - +** i a u Z p v +** - - - - - - - +** +** Zero a pv-vector. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Returned: +** pv double[2][3] zero pv-vector +** +** Called: +** iauZp zero p-vector +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + iauZp(pv[0]); + iauZp(pv[1]); + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/3rdparty/sofa/src/zr.c b/src/cpp/3rdparty/sofa/src/zr.c new file mode 100644 index 000000000..14b207329 --- /dev/null +++ b/src/cpp/3rdparty/sofa/src/zr.c @@ -0,0 +1,133 @@ +#include "sofa.h" + +void iauZr(double r[3][3]) +/* +** - - - - - - +** i a u Z r +** - - - - - - +** +** Initialize an r-matrix to the null matrix. +** +** This function is part of the International Astronomical Union's +** SOFA (Standards Of Fundamental Astronomy) software collection. +** +** Status: vector/matrix support function. +** +** Returned: +** r double[3][3] r-matrix +** +** This revision: 2021 May 11 +** +** SOFA release 2021-05-12 +** +** Copyright (C) 2021 IAU SOFA Board. See notes at end. +*/ +{ + r[0][0] = 0.0; + r[0][1] = 0.0; + r[0][2] = 0.0; + r[1][0] = 0.0; + r[1][1] = 0.0; + r[1][2] = 0.0; + r[2][0] = 0.0; + r[2][1] = 0.0; + r[2][2] = 0.0; + +/* Finished. */ + +/*---------------------------------------------------------------------- +** +** Copyright (C) 2021 +** Standards Of Fundamental Astronomy Board +** of the International Astronomical Union. +** +** ===================== +** SOFA Software License +** ===================== +** +** NOTICE TO USER: +** +** BY USING THIS SOFTWARE YOU ACCEPT THE FOLLOWING SIX TERMS AND +** CONDITIONS WHICH APPLY TO ITS USE. +** +** 1. The Software is owned by the IAU SOFA Board ("SOFA"). +** +** 2. Permission is granted to anyone to use the SOFA software for any +** purpose, including commercial applications, free of charge and +** without payment of royalties, subject to the conditions and +** restrictions listed below. +** +** 3. You (the user) may copy and distribute SOFA source code to others, +** and use and adapt its code and algorithms in your own software, +** on a world-wide, royalty-free basis. That portion of your +** distribution that does not consist of intact and unchanged copies +** of SOFA source code files is a "derived work" that must comply +** with the following requirements: +** +** a) Your work shall be marked or carry a statement that it +** (i) uses routines and computations derived by you from +** software provided by SOFA under license to you; and +** (ii) does not itself constitute software provided by and/or +** endorsed by SOFA. +** +** b) The source code of your derived work must contain descriptions +** of how the derived work is based upon, contains and/or differs +** from the original SOFA software. +** +** c) The names of all routines in your derived work shall not +** include the prefix "iau" or "sofa" or trivial modifications +** thereof such as changes of case. +** +** d) The origin of the SOFA components of your derived work must +** not be misrepresented; you must not claim that you wrote the +** original software, nor file a patent application for SOFA +** software or algorithms embedded in the SOFA software. +** +** e) These requirements must be reproduced intact in any source +** distribution and shall apply to anyone to whom you have +** granted a further right to modify the source code of your +** derived work. +** +** Note that, as originally distributed, the SOFA software is +** intended to be a definitive implementation of the IAU standards, +** and consequently third-party modifications are discouraged. All +** variations, no matter how minor, must be explicitly marked as +** such, as explained above. +** +** 4. You shall not cause the SOFA software to be brought into +** disrepute, either by misuse, or use for inappropriate tasks, or +** by inappropriate modification. +** +** 5. The SOFA software is provided "as is" and SOFA makes no warranty +** as to its use or performance. SOFA does not and cannot warrant +** the performance or results which the user may obtain by using the +** SOFA software. SOFA makes no warranties, express or implied, as +** to non-infringement of third party rights, merchantability, or +** fitness for any particular purpose. In no event will SOFA be +** liable to the user for any consequential, incidental, or special +** damages, including any lost profits or lost savings, even if a +** SOFA representative has been advised of such damages, or for any +** claim by any third party. +** +** 6. The provision of any version of the SOFA software under the terms +** and conditions specified herein does not imply that future +** versions will also be made available under the same terms and +** conditions. +* +** In any published work or commercial product which uses the SOFA +** software directly, acknowledgement (see www.iausofa.org) is +** appreciated. +** +** Correspondence concerning SOFA software should be addressed as +** follows: +** +** By email: sofa@ukho.gov.uk +** By post: IAU SOFA Center +** HM Nautical Almanac Office +** UK Hydrographic Office +** Admiralty Way, Taunton +** Somerset, TA1 2DN +** United Kingdom +** +**--------------------------------------------------------------------*/ +} diff --git a/src/cpp/CMakeLists.txt b/src/cpp/CMakeLists.txt index 72ae79412..e7ffd8af6 100644 --- a/src/cpp/CMakeLists.txt +++ b/src/cpp/CMakeLists.txt @@ -1,47 +1,80 @@ -add_executable(pea +#set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "time -v") + +add_subdirectory(3rdparty/sofa) + + +add_library(ginan_core 3rdparty/enum.h + 3rdparty/EigenDenseBaseAddons.h 3rdparty/jpl/jpl_eph.cpp 3rdparty/jpl/jpl_eph.hpp 3rdparty/jpl/jpl_int.hpp - 3rdparty/sofa/sofa.cpp - 3rdparty/sofa/sofa.hpp - 3rdparty/sofa/sofam.hpp - 3rdparty/egm96/EGM96.c 3rdparty/egm96/EGM96.h 3rdparty/egm96/EGM96_data.h + + 3rdparty/slr/fcul_a.cpp + 3rdparty/slr/fcul_zd_hpa.cpp + 3rdparty/slr/read_crd.c - common/acsConfig.hpp - common/acsConfig.cpp + + pea/main.cpp + pea/minimumConstraints.cpp + pea/minimumConstraints.hpp + pea/networkEstimator.cpp + pea/networkEstimator.hpp + pea/pea_snx.cpp + pea/ppp.cpp + pea/ppppp.cpp + pea/ppp_obs.cpp + pea/ppp_ambres.cpp + pea/ppp_pseudoobs.cpp + pea/ppp_slr.cpp + pea/ppp_user.cpp + pea/ppp_network.cpp + pea/ppp.hpp + pea/preprocessor.cpp + pea/spp.cpp + + common/api.hpp + common/api.cpp common/ntripBroadcast.cpp common/ntripBroadcast.hpp common/acsQC.hpp common/acsQC.cpp - common/acsStream.cpp - common/acsStream.hpp common/algebra.cpp common/algebra_old.cpp common/algebra.hpp common/algebraTrace.cpp common/algebraTrace.hpp + common/attitude.cpp common/antenna.hpp common/antenna.cpp common/biasSINEX.hpp common/biasSINEXread.cpp common/biasSINEXwrite.cpp + common/binaryStore.cpp + common/binaryStore.hpp common/common.hpp common/common.cpp common/constants.hpp common/constants.cpp + common/cost.hpp + common/cost.cpp common/corrections.cpp common/debug.cpp common/debug.hpp common/eigenIncluder.hpp common/ephemeris.cpp common/ephemeris.hpp + common/ephBroadcast.cpp + common/ephKalman.cpp + common/ephPrecise.cpp + common/ephRemote.cpp + common/ephSSR.cpp common/enums.h common/erp.cpp common/erp.hpp @@ -51,10 +84,12 @@ add_executable(pea common/gpx.hpp common/gTime.cpp common/gTime.hpp + common/icdDecoder.hpp common/instrument.cpp common/instrument.hpp common/linearCombo.cpp common/linearCombo.hpp + #common/mqtt.cpp common/mongo.cpp common/mongo.hpp common/mongoRead.cpp @@ -67,16 +102,18 @@ add_executable(pea common/ntripSocket.hpp common/ntripTrace.cpp common/ntripTrace.hpp - common/ntripSourceTable.cpp - common/ntripSourceTable.hpp common/orbits.cpp common/orbits.hpp - common/preceph.cpp + common/packetStatistics.hpp + common/rinex.cpp + common/rinex.hpp common/rtsSmoothing.cpp common/rtcmDecoder.cpp common/rtcmDecoder.hpp common/rtcmEncoder.cpp common/rtcmEncoder.hpp + common/rtcmTrace.cpp + common/rtcmTrace.hpp common/satStat.hpp common/summary.cpp common/summary.hpp @@ -84,14 +121,20 @@ add_executable(pea common/satSys.hpp common/sinex.hpp common/sinex.cpp + common/sinexParser.cpp + common/sinexParser.hpp + common/station.cpp common/tropSinex.cpp common/sp3.cpp common/sp3Write.cpp common/sp3Write.hpp + common/orbex.cpp + common/orbexWrite.hpp + common/orbexWrite.cpp common/ssr.hpp common/station.hpp - common/streamTrace.cpp - common/streamTrace.hpp + common/trace.cpp + common/trace.hpp common/testUtils.cpp common/testUtils.hpp common/trigPosInterp.cpp @@ -101,16 +144,26 @@ add_executable(pea common/rinexNavWrite.hpp common/rinexObsWrite.cpp common/rinexObsWrite.hpp + common/ubxDecoder.cpp + common/ubxDecoder.hpp + common/walkthrough.cpp common/streamFile.hpp - common/streamNav.hpp common/streamNtrip.cpp common/streamNtrip.hpp common/streamObs.hpp common/streamRinex.hpp common/streamRtcm.hpp + common/streamSerial.cpp + common/streamSerial.hpp common/streamSp3.hpp + common/streamUbx.cpp + common/streamUbx.hpp + common/streamParser.cpp + common/streamParser.hpp + iono/geomagField.hpp + iono/geomagField.cpp iono/ionoMeas.cpp iono/ionoModel.cpp iono/ionoModel.hpp @@ -118,6 +171,7 @@ add_executable(pea iono/ionoSphericalCaps.cpp iono/ionoBSplines.cpp iono/ionexWrite.cpp + iono/ionoLocalSTEC.cpp ambres/GNSSambres.hpp ambres/GNSSambres.cpp @@ -127,39 +181,27 @@ add_executable(pea ambres/GinAR_main.cpp ambres/GinARoutpt.cpp - orbprop/forceModels.cpp - orbprop/forceModels.hpp - orbprop/gravity.cpp - orbprop/gravity.hpp - orbprop/jplEph.cpp - orbprop/jplEph.hpp - orbprop/forceModels.cpp - orbprop/forceModels.hpp - orbprop/satRefSys.hpp + slr/slrCom.cpp + slr/slrObs.cpp + slr/slrSat.cpp + slr/slrRec.cpp - pea/main.cpp - pea/minimumConstraints.cpp - pea/minimumConstraints.hpp - pea/networkEstimator.cpp - pea/networkEstimator.hpp - pea/pea_snx.cpp - pea/ppp.cpp - pea/ppppp.cpp - pea/ppppp_obs.cpp - pea/ppppp_ambres.cpp - pea/ppppp_pseudoobs.cpp - pea/ppp_user.cpp - pea/ppp_network.cpp - pea/ppp.hpp - pea/preprocessor.cpp - pea/spp.cpp + other_ssr/otherSSR.hpp + other_ssr/prototypeIgsSSRDecode.cpp + other_ssr/prototypeCmpSSRDecode.cpp + other_ssr/prototypeIgsSSREncode.cpp + + orbprop/acceleration.cpp + orbprop/coordinates.cpp + orbprop/iers2010.cpp + orbprop/planets.cpp + orbprop/oceanTide.cpp + orbprop/orbitProp.cpp + orbprop/staticField.cpp rtklib/ionex.cpp rtklib/lambda.cpp rtklib/lambda.h - rtklib/readtrop.cpp - rtklib/rinex.cpp - rtklib/rinex.hpp rtklib/rtkcmn.cpp rtklib/tides.cpp rtklib/tides.hpp @@ -169,23 +211,30 @@ add_executable(pea rtklib/vmf3.cpp rtklib/wancorr.cpp rtklib/wancorr.h + + common/acsConfig.hpp + common/acsConfig.cpp ) -target_include_directories(pea PUBLIC +target_include_directories(ginan_core PUBLIC 3rdparty 3rdparty/egm96 - 3rdparty/sofa + 3rdparty/sofa/src 3rdparty/jpl + 3rdparty/mqtt_cpp/ + 3rdparty/slr configurator ambres + slr common iono orbprop pea peaUploader rtklib + other_ssr ${EIGEN3_INCLUDE_DIRS} ${LAPACK_INCLUDE_DIRS} @@ -201,70 +250,17 @@ target_include_directories(pea PUBLIC "/usr/local/include/libbson-1.0" "/usr/local/lib" ) - -add_executable(brdc2sp3 - brdc2sp3/brdc2sp3_main.cpp - common/acsConfig.hpp - common/acsConfig.cpp - common/algebra_old.cpp - common/algebra.hpp - common/antenna.hpp - common/antenna.cpp - common/biasSINEX.hpp - common/biasSINEXread.cpp - common/common.hpp - common/common.cpp - common/constants.hpp - common/constants.cpp - common/gTime.cpp - common/gTime.hpp - common/navigation.hpp - common/satSys.cpp - common/satSys.hpp - common/streamTrace.cpp - common/streamTrace.hpp - 3rdparty/sofa/sofa.cpp #todo aaron get rid of these - rtklib/rinex.cpp - rtklib/rinex.hpp - rtklib/rtkcmn.cpp - rtklib/tides.hpp - ) - -target_include_directories(brdc2sp3 PUBLIC - pea - configurator - common - 3rdparty - 3rdparty/sofa #todo aaron get rid of these - orbprop - iono - ambres - rtklib - ${EIGEN3_INCLUDE_DIRS} - ${LAPACK_INCLUDE_DIRS} - ${OPENBLAS_INCLUDE_DIRS} - ${YAML_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} - ${LIBMONGOCXX_INCLUDE_DIR} - ${LIBBSONCXX_INCLUDE_DIR} - ${OPENSSL_INCLUDE_DIR} - "/usr/local/include/bsoncxx/v_noabi" - "/usr/local/include/libmongoc-1.0" - "/usr/local/include/libbson-1.0" - "/usr/local/lib" - ) + +target_compile_options(ginan_core PRIVATE -fpie) if(OpenMP_CXX_FOUND) - target_link_libraries(pea PUBLIC OpenMP::OpenMP_CXX) + target_link_libraries(ginan_core PUBLIC OpenMP::OpenMP_CXX) endif() -target_compile_definitions(pea PRIVATE +target_compile_definitions(ginan_core PRIVATE EIGEN_USE_BLAS=1 ) -target_compile_definitions(brdc2sp3 PRIVATE - EIGEN_USE_BLAS=1 - ) #================================================== # Ocean tide loading @@ -344,17 +340,18 @@ if(OpenMP_CXX_FOUND) endif() if(ENABLE_UNIT_TESTS) - target_compile_definitions(pea PRIVATE ENABLE_UNIT_TESTS=1) + target_compile_definitions(ginan_core PRIVATE ENABLE_UNIT_TESTS=1) endif() if(ENABLE_PARALLELISATION) - target_compile_definitions(pea PRIVATE ENABLE_PARALLELISATION=1) + target_compile_definitions(ginan_core PRIVATE ENABLE_PARALLELISATION=1) endif() -target_link_libraries(pea PUBLIC +target_link_libraries(ginan_core PUBLIC m pthread + sofa_lib ${Boost_LIBRARIES} ${BLAS_LIBRARIES} ${LAPACK_LIBRARIES} @@ -366,35 +363,39 @@ target_link_libraries(pea PUBLIC ${OPENSSL_LIBRARIES} ) -target_link_libraries(brdc2sp3 PUBLIC - m - pthread - ${Boost_LIBRARIES} - ${BLAS_LIBRARIES} - ${LAPACK_LIBRARIES} - ${YAML_CPP_LIBRARIES} - ${YAML_CPP_LIB} - mongo::mongocxx_shared - ${BLAS_LIBRARY_DIRS} - ${OPENSSL_LIBRARY_DIRS} - ${OPENSSL_LIBRARIES} - ) + +add_executable(ginan + gui/ginan.cpp + gui/anode.cpp + gui/beast.cpp) + +target_include_directories(ginan PUBLIC + 3rdparty/beast/ + ) + +target_link_libraries(ginan PRIVATE ginan_core) + +add_executable(pea + pea.cpp) + +target_include_directories(pea PUBLIC + ) + +target_link_libraries(pea PRIVATE ginan_core) -if(ENABLE_PARALLELISATION) - target_compile_definitions(pea PRIVATE ENABLE_PARALLELISATION=1) -endif() add_custom_target(peas) add_dependencies(peas pea - brdc2sp3 + ginan ) - + + if(BUILD_DOC) add_dependencies(peas docs ) endif() - - + + diff --git a/src/cpp/ambres/GNSSambres.cpp b/src/cpp/ambres/GNSSambres.cpp index 15fb7ca23..e9689e6e3 100644 --- a/src/cpp/ambres/GNSSambres.cpp +++ b/src/cpp/ambres/GNSSambres.cpp @@ -275,23 +275,90 @@ int Ztrans_reduction( } /** Integer bootstrapping */ +// int integer_bootst( +// Trace& trace, ///< Debug trace +// GinAR_mtx& mtrx, ///< Reference to structure containing float values and covariance +// GinAR_opt opt) ///< Object containing processing options +// { +// int info = Ztrans_reduction(trace, mtrx); + +// if (info < 0) +// return 0; + + + +// GinAR_mtx mtrx2; +// mtrx2.aflt = mtrx.zflt; + +// MatrixXd Z = mtrx.Ztrs; +// mtrx2.Paflt = Z*mtrx.Paflt*Z.transpose(); + +// int nfix = interat_round (trace, mtrx2, opt); + +// mtrx.Ztrs = mtrx2.Ztrs * Z; +// mtrx.zfix = mtrx2.zfix; + +// return nfix; +// } + int integer_bootst( Trace& trace, ///< Debug trace GinAR_mtx& mtrx, ///< Reference to structure containing float values and covariance GinAR_opt opt) ///< Object containing processing options { - int info = Ztrans_reduction(trace, mtrx); + LDLT ldlt_; + ldlt_.compute(mtrx.Paflt); - if (info < 0) + if (ldlt_.isPositive() == false) + { + tracepdeex(1, trace, "WARNING: LD decomposition error, ambiguity matrix may not positive definite\n"); return 0; + } + + MatrixXd L_ = ldlt_.matrixL(); + auto tr = ldlt_.transpositionsP (); + + int siz = mtrx.aflt.size(); + MatrixXd I0 = MatrixXd::Identity(siz, siz); + MatrixXd Zt = tr * I0; + VectorXd z_ = tr * mtrx.aflt; + + for (int j = siz - 2; j >= 0; j--) + { + for (int i = j + 1; i < siz; i++) + { + double mu = ROUND(L_(i, j)); + + if (mu != 0) + { + L_.row(i) -= mu * L_.row(j); + Zt.row(i) -= mu * Zt.row(j); + z_ (i) -= mu * z_ (j); + } + } + } + + MatrixXd Pz = Zt*mtrx.Paflt*Zt.transpose(); GinAR_mtx mtrx2; - mtrx2.aflt = mtrx.zflt; + mtrx2.aflt = z_; + mtrx2.Paflt = Pz; - MatrixXd Z = mtrx.Ztrs; - mtrx2.Paflt = Z*mtrx.Paflt*Z.transpose(); + if (AR_VERBO) + { + trace << std::endl << "x_=" << std::endl << mtrx.aflt.transpose() << std::endl; + trace << std::endl << "Px=" << std::endl << mtrx.Paflt << std::endl; + trace << std::endl << "Zt=" << std::endl << Zt << std::endl; + trace << std::endl << "z_=" << std::endl << z_.transpose() << std::endl; + trace << std::endl << "Pz=" << std::endl << Pz << std::endl; + } + + int nfix = interat_round (trace, mtrx2, opt); + + mtrx.Ztrs = mtrx2.Ztrs * Zt; + mtrx.zfix = mtrx2.zfix; - return interat_round (trace, mtrx2, opt); + return nfix; } /** Lambda algorithm and its variations (ILQ, Common set, BIE) */ @@ -300,8 +367,6 @@ int lambda_search( GinAR_mtx& mtrx, ///< Reference to structure containing float values and covariance GinAR_opt opt) ///< Object containing processing options { - TestStack ts(__FUNCTION__); - int info = Ztrans_reduction(trace, mtrx); if (info < 0) @@ -436,9 +501,6 @@ int lambda_search( MatrixXd Z = mtrx.Ztrs.bottomRows(zsiz); mtrx.Ztrs = Z; - TestStack::testMat("zfix0", zfix0); - TestStack::testMat("mtrx.Ztrs", mtrx.Ztrs); - switch (opt.mode) { case E_ARmode::LAMBDA: @@ -527,12 +589,10 @@ int GNSS_AR( GinAR_mtx& mtrx, ///< Reference to structure containing float values and covariance GinAR_opt opt) ///< Object containing processing options { - TestStack ts(__FUNCTION__); - switch (opt.mode) { case E_ARmode::OFF: return 0; - case E_ARmode::ROUND: return simple_round (trace, mtrx, opt); + case E_ARmode::ROUND: return simple_round (trace, mtrx, opt); case E_ARmode::ITER_RND: return interat_round (trace, mtrx, opt); case E_ARmode::BOOTST: return integer_bootst (trace, mtrx, opt); case E_ARmode::LAMBDA: return lambda_search (trace, mtrx, opt); diff --git a/src/cpp/ambres/GNSSambres.hpp b/src/cpp/ambres/GNSSambres.hpp index 267b5b0bf..bf958a28d 100644 --- a/src/cpp/ambres/GNSSambres.hpp +++ b/src/cpp/ambres/GNSSambres.hpp @@ -1,14 +1,14 @@ -#ifndef GNSS_AMB_RES_HPP -#define GNSS_AMB_RES_HPP + +#pragma once #include "eigenIncluder.hpp" #include "observations.hpp" -#include "streamTrace.hpp" #include "constants.hpp" #include "algebra.hpp" #include "station.hpp" #include "satSys.hpp" #include "common.hpp" +#include "trace.hpp" #define POSTAR_VAR 1e-6 #define FIXED_AMB_VAR 1e-8 @@ -116,9 +116,9 @@ struct GinAR_rec KFState kfState_fixed; - Vector3d snxPos_; - Vector3d fltPos_; - Vector3d fixPos_; + VectorEcef snxPos_; + VectorEcef fltPos_; + VectorEcef fixPos_; }; struct GinAR_sat @@ -144,14 +144,14 @@ extern map ARsatellites; extern map ARstations; extern map> sys_activ; extern map> elev_archive; -extern map> slip_archive; +extern map> slip_archive; /* main functions */ void config_AmbigResl(); /* Configures the ambiguity resolution algorithms */ int networkAmbigResl(Trace& trace, StationMap& stations, KFState& kfState); /* Ambiguity resolution for network solutions */ int enduserAmbigResl(Trace& trace, ObsList& obsList, KFState& kfState, Vector3d snxPos, double dop, string outfile); /* Ambiguity resolution for end user solutions */ int smoothdAmbigResl(KFState& kfState); /* Ambiguity resolution on smoothed KF*/ -bool sys_frq(short int sys, E_FType& frq1, E_FType& frq2, E_FType& frq3); + bool ARsol_ready(); KFState retrieve_last_ARcopy (); GinAR_sat* GinAR_sat_metadata(SatSys sat); @@ -159,10 +159,9 @@ GinAR_sat* GinAR_sat_metadata(SatSys sat); /* Output fuctions */ void gpggaout(string outfile, KFState& KfState, string recId, int solStat, int numSat, double hdop, bool lng); /* Alternative end user aoutput for ambiguity resolved solutions */ void artrcout(Trace& trace, GTime time, GinAR_opt opt ); -void arbiaout(Trace& trace, GTime time, GinAR_opt opt ); int arionout(Trace& trace, KFState& KfState, ObsList& obsList, GinAR_opt opt ); -bool queryBiasOutput(Trace& trace, SatSys sat, E_AmbTyp type, double& bias, double& variance); - +bool queryBiasWLNL(Trace& trace, SatSys sat, string rec, E_FType ft, double& bias, double& vari); + /* WL ambiguity functions */ void reset_WLfilt(Trace& trace, E_AmbTyp typ, GTime time, string rec, E_Sys sys); int retrv_WLambg(Trace& trace, E_AmbTyp typ, GTime time, string rec, SatSys sat); @@ -185,4 +184,3 @@ int GNSS_AR(Trace& trace, GinAR_mtx& mtrx, GinAR_opt opt); /* KF function to be deprecated */ void removeUnmeasuredAmbiguities( Trace& trace, KFState& kfState, map measuredStates); -#endif diff --git a/src/cpp/ambres/GinARNLamb.cpp b/src/cpp/ambres/GinARNLamb.cpp index 6584daa2a..8a7de49c6 100644 --- a/src/cpp/ambres/GinARNLamb.cpp +++ b/src/cpp/ambres/GinARNLamb.cpp @@ -1,3 +1,4 @@ +#include "testUtils.hpp" #include "GNSSambres.hpp" /** Comapring two Z-transformed ambiguities */ @@ -35,12 +36,12 @@ void chk_arch( for (auto& [key,coef] : Zambigty ) { E_AmbTyp typ = E_AmbTyp::NL12; - if ( opt.ionmod == +E_IonoMode::ESTIMATE ) + if (opt.ionmod == +E_IonoMode::ESTIMATE) { E_FType frq1; E_FType frq2; E_FType frq3; - sys_frq(key.Sat.sys, frq1, frq2, frq3); + satFreqs(key.Sat.sys, frq1, frq2, frq3); if (key.num == frq1) typ = E_AmbTyp::UCL1; if (key.num == frq2) typ = E_AmbTyp::UCL2; @@ -130,7 +131,7 @@ int updat_ambigt( KFState& kfState, ///< KF struct containing raw ambiguity measurements GinAR_opt opt ) ///< Ginan AR control options { - tracepdeex(ARTRCLVL,trace,"\n#ARES_NLAR Resolving ambiguities %s", kfState.time.to_string(0).c_str()); + tracepdeex(ARTRCLVL,trace,"\n#ARES_NLAR Resolving ambiguities %s", kfState.time.to_string().c_str()); auto& AR_mealist = ARstations[opt.recv].AR_meaMap; chk_arch( trace, kfState.time, opt ); @@ -146,19 +147,18 @@ int updat_ambigt( GinAR_mtx ambState; int nstates = 0; - SatSys sat0; - for (auto& [key,indx] : kfState.kfIndexMap) + for (auto& [key, indx] : kfState.kfIndexMap) { - SatSys sat = key.Sat; + SatSys Sat = key.Sat; string rec = key.str; - E_Sys sys = sat.sys; + E_Sys sys = Sat.sys; E_FType frq1; E_FType frq2; E_FType frq3; E_AmbTyp typ = E_AmbTyp::NL12; if (!opt.sys_solve[sys]) continue; - if (!sys_frq(sys, frq1, frq2, frq3)) continue; + if (!satFreqs(sys, frq1, frq2, frq3)) continue; if ( opt.ionmod == +E_IonoMode::ESTIMATE ) { if(key.num == frq1) typ = E_AmbTyp::UCL1; @@ -173,23 +173,24 @@ int updat_ambigt( else { if (key.type != KF::AMBIGUITY) continue; - if (SATpivlist[typ][sys].find(sat) == SATpivlist[typ][sys].end()) continue; + if (SATpivlist[typ][sys].find(Sat) == SATpivlist[typ][sys].end()) continue; } if (RECpivlist[typ][sys].find(rec) == RECpivlist[typ][sys].end()) continue; - KFKey key2 = {KF::AMBIGUITY, sat, rec, typ}; - if ( AR_mealist.find(key2) == AR_mealist.end() ) continue; - if ( AR_mealist[key2].sat_ele < opt.MIN_Elev_AR ) continue; + KFKey key2 = {KF::AMBIGUITY, Sat, rec, typ}; + if (AR_mealist.find(key2) == AR_mealist.end()) continue; + if (AR_mealist[key2].sat_ele < opt.MIN_Elev_AR) continue; if ( opt.ionmod == +E_IonoMode::IONO_FREE_LINEAR_COMBO ){ - int WLamb = retrv_WLambg(trace, E_AmbTyp::WL12,kfState.time,rec,sat); + int WLamb = retrv_WLambg(trace, E_AmbTyp::WL12,kfState.time,rec,Sat); if ( WLamb == INVALID_WLVAL ) { - tracepdeex(ARTRCLVL+2,trace,"\n#ARES_NLAR Failed to retrieve WL ambiguities for %s %s %s", kfState.time.to_string(0),rec,sat.id().c_str()); + tracepdeex(ARTRCLVL+2,trace,"\n#ARES_NLAR Failed to retrieve WL ambiguities for %s %s %s", kfState.time.to_string(),rec.c_str(),Sat.id().c_str()); continue; } double wlfct = opt.wlfact[sys]; - tracepdeex(ARTRCLVL+2,trace,"\n#ARES_NLAR Retrieved WL amb %s %s %s %d %f", kfState.time.to_string(0).c_str(),rec,sat.id().c_str(),WLamb,wlfct); + + tracepdeex(ARTRCLVL+2,trace,"\n#ARES_NLAR Retrieved WL amb %s %s %s %d %f", kfState.time.to_string().c_str(),rec.c_str(),Sat.id().c_str(),WLamb,wlfct); WLcorrMap[key2] = wlfct*WLamb; } else WLcorrMap[key2] = 0; @@ -198,13 +199,12 @@ int updat_ambigt( ambState.ambmap[nstates] = key; AmbList[key2] = nstates++; - sat0.sys = sys; - key2 = {KF::REC_SYS_BIAS, sat0, rec, typ}; + key2 = {KF::REC_SYS_BIAS, SatSys(Sat.sys), rec, typ}; RecList[key2] = 0; if ( !opt.endu ) { - key2 = {KF::PHASE_BIAS, sat, "", typ}; + key2 = {KF::PHASE_BIAS, Sat, "", typ}; SatList[key2] = 0; } } @@ -239,7 +239,7 @@ int updat_ambigt( /* ambiguity measurements */ xmea.head(nambig) = raw_xmea; Pmea.topLeftCorner(nambig,nambig) = raw_Pmea; - for (auto& [key,ind] : AmbList) + for (auto& [key, ind] : AmbList) { xmea(ind) -= WLcorrMap[key]; wmea(ind) = WLcorrMap[key]; @@ -249,8 +249,7 @@ int updat_ambigt( Hinv(ind,ind) = NLwavlng; - sat0.sys = key.Sat.sys; - KFKey key2 = {KF::REC_SYS_BIAS, sat0, key.str, key.num}; + KFKey key2 = {KF::REC_SYS_BIAS, SatSys(key.Sat.sys), key.str, key.num}; Hinv(ind,RecList[key2]) = NLwavlng; if (!opt.endu) @@ -340,7 +339,7 @@ int updat_ambigt( if (nfix <= 0) return 0; - tracepdeex(ARTRCLVL, trace, "\n#ARES_NLAR %s Solved %4d ambiguities out of %4d", kfState.time.to_string(0).c_str(), nfix, nambig); + tracepdeex(ARTRCLVL, trace, "\n#ARES_NLAR %s Solved %4d ambiguities out of %4d", kfState.time.to_string().c_str(), nfix, nambig); MatrixXd Ztrs = ambState.Ztrs; MatrixXd Sfix = Ztrs * ambState.Paflt * Ztrs.transpose(); /* Variance of z-transform of float ambiguities */ @@ -474,12 +473,17 @@ int apply_ambigt( map AmbList; int indH = 0; - for (auto& [Zamb, amb] : Zamb_list ) + for (auto& [Zamb, amb] : Zamb_list) { if ( (kfState.time-amb.mea_fin) > opt.Max_Hold_tim ) continue; - ObsKey obsKey = { sat0, "COMBIN", "Zamb", nind }; + KFKey obsKey; + obsKey.Sat = sat0; + obsKey.str = "COMBIN"; + obsKey.type = KF::Z_AMB; + obsKey.num = nind; + KFMeasEntry AmbMeas(&kfState, obsKey); AmbMeas.setValue(amb.flt_amb); @@ -551,16 +555,16 @@ int apply_ambigt( indZ = 0; if (opt.endu) - for (auto& [Zamb, amb] : Zapplied ) + for (auto& [Zamb, amb] : Zapplied) { - if(fabs(v_post(indZ)) > 0.5) + if (fabs(v_post(indZ)) > 0.5) { tracepdeex( ARTRCLVL, trace, "\n#ARES_NLAR High postfit residual for: " ); for (auto& [key,coef] : Zamb ) tracepdeex(ARTRCLVL, trace, "%+.2f x (%s,%s) ", coef, key.str.c_str(), key.Sat.id().c_str()); tracepdeex( ARTRCLVL, trace, "removing from list" ); - Zamb_list.erase(Zamb); + Zamb_list.erase(Zamb); //todo aaron, this is sketchy, cant erase while iterating } indZ++; } diff --git a/src/cpp/ambres/GinARWLamb.cpp b/src/cpp/ambres/GinARWLamb.cpp index 02534c024..831e0e900 100644 --- a/src/cpp/ambres/GinARWLamb.cpp +++ b/src/cpp/ambres/GinARWLamb.cpp @@ -59,7 +59,7 @@ void WL_newsect( amb.mea_fin = time; amb.int_amb = INVALID_WLVAL; - tracepdeex(ARTRCLVL+2, trace, "\n#ARES_WLAR New WL archive entry: %s %s %s %4d", rec.c_str(), sat.id().c_str(), time.to_string(0).c_str(), ind ); + tracepdeex(ARTRCLVL+2, trace, "\n#ARES_WLAR New WL archive entry: %s %s %s %4d", rec.c_str(), sat.id().c_str(), time.to_string().c_str(), ind ); WL_archive[key][ind] = amb; WL_arch_ind[key] = ind; @@ -142,7 +142,7 @@ void updat_WLfilt( } } - tracepdeex(ARTRCLVL, trace, "\n#ARES_WLAR Updating WL filter %s %s %s, nmea = %4d", time.to_string(0).c_str(), rec, sys._to_string(), amblst.size()); + tracepdeex(ARTRCLVL, trace, "\n#ARES_WLAR Updating WL filter %s %s %s, nmea = %4d", time.to_string().c_str(), rec, sys._to_string(), amblst.size()); /* Remove ambiguities for Unmeasured States */ for (auto [key, index] : WLambKF.kfIndexMap) @@ -168,7 +168,11 @@ void updat_WLfilt( /* Main measurements */ for (auto& [mkey,amb] : amblst) { - ObsKey obsKey = { mkey.Sat, mkey.str, "WLmea" }; + KFKey obsKey; + obsKey.Sat = mkey.Sat; + obsKey.str = mkey.str; + obsKey.type = KF::WL_MEAS; + KFMeasEntry WLmeas(&WLambKF, obsKey); WLmeas.setValue(amb.raw_amb); @@ -211,10 +215,15 @@ void updat_WLfilt( string rec = opt.recv; SatSys sat = RECpivlist[typ][sys][rec].pre_sat; int amb = RECpivlist[typ][sys][rec].sat_amb[sat]; - ObsKey obsKey = { sat, rec, "WLpiv" }; + KFKey obsKey; + obsKey.Sat = sat; + obsKey.str = rec; + obsKey.type = KF::WL_PIV; + KFMeasEntry WLmeas(&WLambKF, obsKey); WLmeas.setValue(amb); WLmeas.setNoise(FIXED_AMB_VAR); + KFKey kfKey = {KF::AMBIGUITY, sat, rec, typ}; init.Q = 0; WLmeas.addDsgnEntry( kfKey, 1, init); @@ -227,7 +236,12 @@ void updat_WLfilt( { if ( rec == AR_reflist[sys] ) { - ObsKey obsKey = { sat0, rec, "WLpiv" }; + KFKey obsKey; + + obsKey.Sat = sat0; + obsKey.str = rec; + obsKey.type = KF::WL_PIV; + KFMeasEntry WLmeas(&WLambKF, obsKey); WLmeas.setValue(0); WLmeas.setNoise(FIXED_AMB_VAR); @@ -244,8 +258,14 @@ void updat_WLfilt( { SatSys sat = RECpivlist[typ][sys][rec].pre_sat; double amb = RECpivlist[typ][sys][rec].sat_amb[sat]; - ObsKey obsKey = { sat, rec, "WLpiv" }; + + KFKey obsKey; + obsKey.Sat = sat; + obsKey.str = rec; + obsKey.type = KF::WL_PIV; + KFMeasEntry WLmeas(&WLambKF, obsKey); + WLmeas.setValue(amb); WLmeas.setNoise(FIXED_AMB_VAR); @@ -263,11 +283,18 @@ void updat_WLfilt( { string rec = SATpivlist[typ][sys][sat].pre_rec; double amb = SATpivlist[typ][sys][sat].rec_amb[rec]; - ObsKey obsKey = { sat, rec, "WLpiv" }; + + KFKey obsKey; + obsKey.Sat = sat; + obsKey.str = rec; + obsKey.type = KF::WL_PIV; + KFMeasEntry WLmeas(&WLambKF, obsKey); WLmeas.setValue(amb); WLmeas.setNoise(FIXED_AMB_VAR); + tracepdeex(ARTRCLVL+1, trace, "\n WLpiv %s %s %10.4f %13.4e", sat.id().c_str(), rec.c_str(), amb, FIXED_AMB_VAR); + KFKey kfKey = {KF::AMBIGUITY, sat, rec, typ}; init.Q = 0; WLmeas.addDsgnEntry( kfKey, 1, init); @@ -349,7 +376,7 @@ void reslv_WLambg( int nfix = GNSS_AR(trace, ambState, opt); - tracepdeex(ARTRCLVL, trace, "\n#ARES_WLAR Resolving WL ambiguities %s %s %s %4d %4d", time.to_string(0).c_str(), rec.c_str(), sys._to_string(), ambState.aflt.size(), nfix); + tracepdeex(ARTRCLVL, trace, "\n#ARES_WLAR Resolving WL ambiguities %s %s %s %4d %4d", time.to_string().c_str(), rec.c_str(), sys._to_string(), ambState.aflt.size(), nfix); KFState KFcopy = WLambKF; VectorXd fixX = ambState.zfix; @@ -361,7 +388,7 @@ void reslv_WLambg( for (int i = 0; i < nfix; i++) { - ObsKey obsKey; + KFKey obsKey; obsKey.str = "WLint "; obsKey.num = i; @@ -606,7 +633,7 @@ void dump_WLambg( { E_AmbTyp typs = E_AmbTyp::_from_integral(key.num); tracepdeex(ARTRCLVL, trace, "\n#ARES_WLAR archived ambiguity: %s %s %s", key.Sat.id().c_str(), key.str.c_str(), typs._to_string()); - tracepdeex(ARTRCLVL, trace, " %s %s %s",amb.sec_ini.to_string(0).c_str(),amb.mea_fin.to_string(0).c_str(),amb.fix_fin.to_string(0).c_str()); + tracepdeex(ARTRCLVL, trace, " %s %s %s",amb.sec_ini.to_string().c_str(),amb.mea_fin.to_string().c_str(),amb.fix_fin.to_string().c_str()); tracepdeex(ARTRCLVL, trace, " %4d %4d %5d", amb.hld_epc, ind, amb.int_amb); } } diff --git a/src/cpp/ambres/GinAR_main.cpp b/src/cpp/ambres/GinAR_main.cpp index c3eb9c47a..6c0d88f67 100644 --- a/src/cpp/ambres/GinAR_main.cpp +++ b/src/cpp/ambres/GinAR_main.cpp @@ -1,7 +1,9 @@ + + #include "GNSSambres.hpp" #include "testUtils.hpp" #include "acsConfig.hpp" -#include "tides.hpp" +#include "planets.hpp" #define SMP2RESET 20 @@ -18,7 +20,24 @@ map ARsatellites; map> elev_archive; -map> slip_archive; +map> slip_archive; + +map systemFreq1 = +{ + {E_Sys::GPS, FREQ1 }, + {E_Sys::GAL, FREQ1 }, + {E_Sys::BDS, FREQ1_CMP }, + {E_Sys::QZS, FREQ1 } +}; + +map systemFreq2 = +{ + {E_Sys::GPS, FREQ2 }, + {E_Sys::GAL, FREQ5 }, + {E_Sys::BDS, FREQ3_CMP }, + {E_Sys::QZS, FREQ1 } +}; + map defCodesL1 = { @@ -34,7 +53,7 @@ map defCodesL2 = {E_Sys::GPS, E_ObsCode::L2W}, {E_Sys::GLO, E_ObsCode::L2C}, {E_Sys::GAL, E_ObsCode::L5Q}, - {E_Sys::BDS, E_ObsCode::L7I}, + {E_Sys::BDS, E_ObsCode::L6I}, {E_Sys::QZS, E_ObsCode::L2S} }; @@ -43,58 +62,10 @@ map defCodesL3 = {E_Sys::GPS, E_ObsCode::L5X}, {E_Sys::GLO, E_ObsCode::L3Q}, {E_Sys::GAL, E_ObsCode::L7Q}, - {E_Sys::BDS, E_ObsCode::L6I}, + {E_Sys::BDS, E_ObsCode::L5P}, {E_Sys::QZS, E_ObsCode::L5Q} }; -/** Default frequencies for each system */ -bool sys_frq( - short int sys, ///< GNSS system e.g. GPS, GLO, GAL ... - E_FType& frq1, ///< frequency of first Carrier - E_FType& frq2, ///< frequency of second Carrier - E_FType& frq3) ///< frequency of third Carrier -{ - switch (sys) - { - case E_Sys::GPS: - frq1 = F1; - frq2 = F2; - frq3 = F5; - if (acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) - { - frq2 = F5; - frq3 = F2; - } - return true; - - case E_Sys::GLO: - frq1 = F1; - frq2 = F2; - frq3 = FTYPE_NONE; - return true; - - case E_Sys::GAL: - frq1 = F1; - frq2 = F5; - frq3 = F7; - return true; - - case E_Sys::QZS: - frq1 = F1; - frq2 = F2; - frq3 = F5; - return true; - - case E_Sys::BDS: - frq1 = B1; - frq2 = B2; - frq3 = B3; - return true; - } - - return false; -} - /** Retrieving satellte elevation at given time */ double retrv_elev( KFKey kfkey, ///< KFKey structure containing satelite and receiver @@ -105,7 +76,7 @@ double retrv_elev( auto elev_list = elev_archive[kfkey]; for (auto& [atim,elev] : elev_list) { - double dt = time-atim; + double dt = (time-atim).to_double(); if (dt > DTTOL) continue; if (dt < -acsConfig.ambrOpts.Max_Hold_time) return -1; return elev; @@ -119,17 +90,20 @@ void clean_obsolete( string recv) ///< Receiver { auto& AR_mealist = ARstations[recv].AR_meaMap; - for (auto it = AR_mealist.begin(); it != AR_mealist.end();) + for (auto it = AR_mealist.begin(); it != AR_mealist.end(); ) { + auto& [key, AR_mea] = *it; + if ( recv != "NETWORK" - && recv != it->first.str) + && recv != key.str) + { + it++; continue; + } - auto& AR_mea = it->second; - - if ( (time - AR_mea.mea_fin) > defAR_WL.Max_Hold_tim - || (time - AR_mea.mea_fin) < -DTTOL - || ( AR_mea.out_epc) > defAR_WL.Max_Hold_epc) + if ( (time - AR_mea.mea_fin) > defAR_WL.Max_Hold_tim + ||(time - AR_mea.mea_fin) < -DTTOL + ||( AR_mea.out_epc) > defAR_WL.Max_Hold_epc) { it = AR_mealist.erase(it); } @@ -148,12 +122,10 @@ GinAR_sat* GinAR_sat_metadata(SatSys sat) } double eclipse_safe( - Obs& obs) + GObs& obs) { - ERPValues erpv; - - Vector3d rSun; - sunmoonpos(gpst2utc(obs.time), erpv, &rSun); + VectorEcef rSun; + planetPosEcef(obs.time, E_ThirdBody::SUN, rSun); Vector3d rSat = obs.rSat; Vector3d vSat = obs.satVel; @@ -168,12 +140,12 @@ double eclipse_safe( /** Loading float ambiguity data from Observations (WL, cycle slip & elevation) */ void LoadFromObs( - Trace& trace, ///< Trace file to output to - ObsList& obslst, ///< Observation list - GTime time, ///< Observation time (usually from KF or solutions) - string recv) ///< Receiver network identifier + Trace& trace, ///< Trace file to output to + ObsList& obsList, ///< Observation list + GTime time, ///< Observation time (usually from KF or solutions) + string recv) ///< Receiver network identifier { - if (obslst.size() <= 0) + if (obsList.empty()) { RecBlackList[recv]+=100; return; @@ -185,8 +157,8 @@ void LoadFromObs( auto& AR_mealist = ARstations[recv].AR_meaMap; - tracepdeex(ARTRCLVL+1, trace, "\n#ARES_MEA Saving metadata for %s %s", time.to_string(0).c_str(), obslst.front().mount.c_str()); - for (auto& obs : obslst) + tracepdeex(ARTRCLVL+1, trace, "\n#ARES_MEA Saving metadata for %s %s", time.to_string().c_str(), recv.c_str()); + for (auto& obs : only(obsList)) { SatSys sat = obs.Sat; E_Sys sys = sat.sys; @@ -196,7 +168,7 @@ void LoadFromObs( E_FType frq1; E_FType frq2; E_FType frq3; - if (!sys_frq(sys, frq1, frq2, frq3)) continue; + if (!satFreqs(sys, frq1, frq2, frq3)) continue; double elev = obs.satStat_ptr->el; if (elev < acsConfig.elevation_mask) continue; @@ -261,19 +233,19 @@ void LoadFromObs( if ( defAR_WL.ionmod == +E_IonoMode::ESTIMATE) { - if (obs.satStat_ptr->sigStatMap[frq1].slip.any) + if (obs.satStat_ptr->sigStatMap[ft2string(frq1)].slip.any) { key.num = E_AmbTyp::UCL1; slip_archive[key].push_back(time); tracepdeex(ARTRCLVL+2, trace, "L1 slip "); } - if (obs.satStat_ptr->sigStatMap[frq2].slip.any) + if (obs.satStat_ptr->sigStatMap[ft2string(frq2)].slip.any) { key.num = E_AmbTyp::UCL2; slip_archive[key].push_back(time); tracepdeex(ARTRCLVL+2, trace, "L2 slip "); } - if (obs.satStat_ptr->sigStatMap[frq3].slip.any) + if (obs.satStat_ptr->sigStatMap[ft2string(frq3)].slip.any) { key.num = E_AmbTyp::UCL3; slip_archive[key].push_back(time); @@ -287,8 +259,8 @@ void LoadFromObs( if ( defAR_WL.ionmod == +E_IonoMode::IONO_FREE_LINEAR_COMBO) { bool slip = false; - if (obs.satStat_ptr->sigStatMap[frq1].slip.any // To do change from "any" to MW, GF && CDIA - || obs.satStat_ptr->sigStatMap[frq2].slip.any ) + if ( obs.satStat_ptr->sigStatMap[ft2string(frq1)].slip.any // todo change from "any" to MW, GF && CDIA + || obs.satStat_ptr->sigStatMap[ft2string(frq2)].slip.any) { key.num = E_AmbTyp::NL12; slip_archive[key].push_back(time); @@ -376,7 +348,7 @@ int LoadFromFlt( map Satlist; map Reclist; - tracepdeex(ARTRCLVL, trace, "\n#ARES_MEA Loading from KF: %s", time.to_string(0).c_str()); + tracepdeex(ARTRCLVL, trace, "\n#ARES_MEA Loading from KF: %s", time.to_string().c_str()); auto& AR_mealist = ARstations[recv].AR_meaMap; auto& AmbTyplist = ARstations[recv].AmbTypMap; @@ -392,7 +364,7 @@ int LoadFromFlt( if ( defAR_WL.endu && key.type != KF::PHASE_BIAS) continue; if (!defAR_WL.endu && key.type != KF::AMBIGUITY) continue; if (!sys_solve[sys]) continue; - if (!sys_frq(sys, frq1, frq2, frq3)) continue; + if (!satFreqs(sys, frq1, frq2, frq3)) continue; string rec = key.str; KFKey key2 = {KF::AMBIGUITY,sat,rec,0}; @@ -425,7 +397,7 @@ int LoadFromFlt( bool sig_slip = false; for(auto& slip_tim : slip_archive[key2]) { - double dt = time-slip_tim; + double dt = (time-slip_tim).to_double(); if (fabs(dt)>DTTOL) continue; @@ -486,7 +458,7 @@ int LoadFromFlt( } /** Loading configuration options from acsConfig */ -void config_AmbigResl(void) +void config_AmbigResl() { for (auto& [sys,act]: acsConfig.solve_amb_for) if (acsConfig.process_sys[sys]) @@ -540,7 +512,7 @@ void config_AmbigResl(void) && !(defAR_WL.ionmod == +E_IonoMode::ESTIMATE)) defAR_WL.ionmod = E_IonoMode::OFF; - defAR_WL.bias_update = acsConfig.ambrOpts.biasOutrate; + defAR_WL.bias_update = acsConfig.ambrOpts.code_output_interval; defAR_WL.type = E_AmbTyp::WL12; @@ -558,12 +530,14 @@ void config_AmbigResl(void) E_FType frq1 = F1; E_FType frq2 = F2; E_FType frq3 = F5; - sys_frq(sys, frq1, frq2, frq3); + satFreqs(sys, frq1, frq2, frq3); - if (acsConfig.ionoOpts.corr_mode == +E_IonoMode::IONO_FREE_LINEAR_COMBO) + if ( acsConfig.ionoOpts.corr_mode == +E_IonoMode::IONO_FREE_LINEAR_COMBO + && sys != +E_Sys::GLO) { - double lam1 = lam_carr[frq1]; - double lam2 = lam_carr[frq2]; + double lam1 = CLIGHT / systemFreq1[sys]; + double lam2 = CLIGHT / systemFreq2[sys]; + defAR_WL.wavlen[sys] = lam1*lam2/(lam2+lam1); defAR_WL.wlfact[sys] = lam1*defAR_WL.wavlen[sys]/(lam2-lam1); } @@ -597,7 +571,7 @@ int networkAmbigResl( GTime time = kfState.time; tracepdeex(ARTRCLVL, trace, "\n#ARES_MAIN Ambiguity Resolution on %3d Stations at %s", - stations.size(), time.to_string(0).c_str()); + stations.size(), time.to_string().c_str()); /* Clean obsolete measurements */ @@ -615,7 +589,7 @@ int networkAmbigResl( if (recOpts.exclude) continue; - LoadFromObs( trace, station.obsList, time, recv ); + LoadFromObs(trace, station.obsList, time, recv); } for (auto& [typ,sysmap] : RECpivlist) @@ -638,22 +612,22 @@ int networkAmbigResl( } } - if ( acsConfig.process_rts ) + if (acsConfig.process_rts) { - artrcout( trace, kfState.time, opt ); + artrcout(trace, kfState.time, opt); return 0; } - int nsat=0; - int nrec=0; - int namb = LoadFromFlt( trace, kfState, nsat, nrec, recv ); + int nsat = 0; + int nrec = 0; + int namb = LoadFromFlt(trace, kfState, nsat, nrec, recv); opt = defAR_NL; opt.recv = "NETWORK"; - for(auto& [typ,nmeas] : ARstations[recv].AmbTypMap) + for(auto& [type, nmeas] : ARstations[recv].AmbTypMap) { - opt.type = typ; + opt.type = type; updt_net_pivot(trace, time,opt); } @@ -667,18 +641,12 @@ int networkAmbigResl( nfix = apply_ambigt(trace, kfState, opt); - if (nfix > 0.6*namb) FIXREADY = true; - if (nfix < 0.4*namb) FIXREADY = false; + if (nfix > 0.6 * namb) FIXREADY = true; + if (nfix < 0.4 * namb) FIXREADY = false; artrcout(trace, kfState.time, opt); - if ( acsConfig.output_bias_sinex - && acsConfig.ambrOpts.biasOutrate > 0) - { - arbiaout(trace, kfState.time, opt); - } - - if ( acsConfig.process_ionosphere + if ( acsConfig.process_ionosphere && acsConfig.ionModelOpts.model != +E_IonoModel::NONE) for (auto& [rec,station] : stations) { @@ -687,13 +655,14 @@ int networkAmbigResl( if (recOpts.exclude) continue; - arionout( trace, kfState, station.obsList, opt ); + arionout(trace, kfState, station.obsList, opt); } if (AR_VERBO) kfState.outputStates(trace, "/AR"); ARcopy = kfState; + return nfix; } @@ -706,6 +675,7 @@ int enduserAmbigResl( double dop, ///< Horizontal dilution of precision string outfile) ///< solution filename { + if (acsConfig.ionoOpts.corr_mode != +E_IonoMode::IONO_FREE_LINEAR_COMBO) acsConfig.ambrOpts.WLmode = +E_ARmode::OFF; @@ -714,15 +684,12 @@ int enduserAmbigResl( if (obsList.empty()) return 0; GTime time = kfState_float.time; - string recv = obsList.front().mount; + string recv = obsList.front()->mount; GinAR_opt opt = defAR_WL; opt.recv = recv; ARstations[recv].kfState_fixed = kfState_float; - TestStack::testMat(recv + "fixedx0", ARstations[recv].kfState_fixed.x); - TestStack::testMat(recv + "fixedP0", ARstations[recv].kfState_fixed.P); - ARstations[recv].snxPos_ = snxPos; for (short i = 0; i < 3; i++) kfState_float.getKFValue({KF::REC_POS,{}, recv, i}, ARstations[recv].fltPos_[i]); @@ -730,7 +697,7 @@ int enduserAmbigResl( if (!ARstations[recv].AR_meaMap.empty()) clean_obsolete(time, recv); - tracepdeex(ARTRCLVL, trace, "\n#ARES_MAIN End user ambiguity resolution: %s %s", time.to_string(0).c_str(), recv.c_str()); + tracepdeex(ARTRCLVL, trace, "\n#ARES_MAIN End user ambiguity resolution: %s %s", time.to_string().c_str(), recv.c_str()); sys_activ[recv].clear(); LoadFromObs(trace, obsList, time, recv); @@ -770,9 +737,6 @@ int enduserAmbigResl( nfix = apply_ambigt(trace, ARstations[recv].kfState_fixed, opt); ARstations[recv].kfState_fixed.outputStates(trace, "/FIXED"); - - TestStack::testMat(recv + "fixed", ARstations[recv].kfState_fixed.x); - TestStack::testMat(recv + "fixedP", ARstations[recv].kfState_fixed.P); for (short i = 0; i < 3; i++) ARstations[recv].kfState_fixed.getKFValue({KF::REC_POS,{}, recv, i}, ARstations[recv].fixPos_[i]); @@ -791,12 +755,6 @@ int enduserAmbigResl( arionout(trace, ARstations[recv].kfState_fixed, obsList, opt); } - if ( acsConfig.output_bias_sinex - && acsConfig.ambrOpts.biasOutrate > 0 ) - { - arbiaout(trace, ARstations[recv].kfState_fixed.time, opt); - } - return nfix; } @@ -812,7 +770,7 @@ int smoothdAmbigResl( GTime time = kfState.time; - tracepdeex(ARTRCLVL, trace, "\n#ARES__RTS Ambiguity resolution on smoothed solutions %s", time.to_string(0).c_str()); + tracepdeex(ARTRCLVL, trace, "\n#ARES__RTS Ambiguity resolution on smoothed solutions %s", time.to_string().c_str()); string recv = "NETWORK"; if (defAR_WL.endu) @@ -855,12 +813,6 @@ int smoothdAmbigResl( if (nfix > 0.6 * namb) FIXREADY = true; if (nfix < 0.4 * namb) FIXREADY = false; - if ( acsConfig.output_bias_sinex - && acsConfig.ambrOpts.biasOutrate > 0 ) - { - arbiaout(trace, time, opt); - } - artrcout(trace, kfState.time, opt); if (AR_VERBO) diff --git a/src/cpp/ambres/GinARoutpt.cpp b/src/cpp/ambres/GinARoutpt.cpp index fa5774887..656622af8 100644 --- a/src/cpp/ambres/GinARoutpt.cpp +++ b/src/cpp/ambres/GinARoutpt.cpp @@ -1,5 +1,8 @@ + +#include "coordinates.hpp" #include "GNSSambres.hpp" #include "biasSINEX.hpp" + #include using std::setprecision; @@ -20,42 +23,38 @@ void gpggaout( double hdop, ///< Horizontal DOP bool lng) ///< Modified GPGGA format (false: GPGGA format according to NMEA 0183) { - double ep[6]; - time2epoch(kfState.time, ep); + GEpoch ep = kfState.time; std::ofstream fpar(outfile, std::ios::out | std::ios::app); if (fpar.tellp() == 0) tracepdeex(1,fpar,"!GPGGA, UTC time, Latitude, N/S, Longitude, E/W, State, # Sat, HDOP, Height, , Geoid,\n"); - double xyz_[3]; + VectorEcef ecef; for (short i = 0; i < 3; i++) - kfState.getKFValue({KF::REC_POS, {}, recId, i}, xyz_[i]); + kfState.getKFValue({KF::REC_POS, {}, recId, i}, ecef[i]); - double lla_[3]; - ecef2pos(xyz_, lla_); - lla_[0]*=R2D; - lla_[1]*=R2D; + VectorPos pos = ecef2pos(ecef); - double latint = floor(fabs(lla_[0])); - double lonint = floor(fabs(lla_[1])); + double latint = floor(fabs(pos.latDeg())); + double lonint = floor(fabs(pos.lonDeg())); - double latv = latint*100 + (fabs(lla_[0]) - latint)*60; - double lonv = lonint*100 + (fabs(lla_[1]) - lonint)*60; - char latc = lla_[0]>0?'N':'S'; - char lonc = lla_[1]>0?'E':'W'; + double latv = latint*100 + (fabs(pos.latDeg()) - latint)*60; + double lonv = lonint*100 + (fabs(pos.lonDeg()) - lonint)*60; + char latc = pos.latDeg()>0?'N':'S'; + char lonc = pos.lonDeg()>0?'E':'W'; if (lng) { tracepdeex(1,fpar,"$GPGGALONG,%02.0f%02.0f%05.2f,",ep[3],ep[4],ep[5]); tracepdeex(1,fpar,"%012.7f,%c,%013.7f,%c,", latv,latc, lonv,lonc); - tracepdeex(1,fpar,"%1d,%02d,%3.1f,%09.3f", solStat, numSat, hdop,lla_[2]); + tracepdeex(1,fpar,"%1d,%02d,%3.1f,%09.3f", solStat, numSat, hdop,pos.hgt()); } else { tracepdeex(1,fpar,"$GPGGA,%02.0f%02.0f%05.2f,",ep[3],ep[4],ep[5]); tracepdeex(1,fpar,"%09.4f,%c,%010.4f,%c,", latv,latc, lonv,lonc); - tracepdeex(1,fpar,"%1d,%02d,%3.1f,%08.2f", solStat, numSat, hdop,lla_[2]); + tracepdeex(1,fpar,"%1d,%02d,%3.1f,%08.2f", solStat, numSat, hdop,pos.hgt()); } tracepdeex(1,fpar,",M,0.0,M,,,\n"); } @@ -66,8 +65,8 @@ void artrcout( GTime time, ///< Solution time GinAR_opt opt ) ///< Ginan AR control options { - int week; - double tow = time2gpst(time,&week); + GTow tow = time; + GWeek week = time; map Nmeas; map Nfixd; @@ -78,7 +77,7 @@ void artrcout( continue; E_AmbTyp typs = E_AmbTyp::_from_integral(key.num); - tracepdeex(ARTRCLVL+1, trace, "\n#ARES_MEAS, %s", amb.mea_fin.to_string(0).c_str()); + tracepdeex(ARTRCLVL+1, trace, "\n#ARES_MEAS, %s", amb.mea_fin.to_string().c_str()); tracepdeex(ARTRCLVL+1, trace, ", %s, %s, %s", key.str.c_str(), key.Sat.id().c_str(), typs._to_string()); tracepdeex(ARTRCLVL+1, trace, ", %6.2f, %4d, %4d, %1d, %10.5f", amb.sat_ele*R2D, amb.hld_epc, amb.out_epc, amb.cyl_slp?1:0, amb.raw_amb); @@ -113,25 +112,15 @@ void artrcout( if (opt.endu) { - double latLonHt[3]; - ecef2pos(ARstations[opt.recv].snxPos_, latLonHt); + VectorPos pos = ecef2pos(ARstations[opt.recv].snxPos_); - double dXYZ_FL[3]; - double dXYZ_AR[3]; - for(short i = 0; i < 3; i++) - { - dXYZ_AR[i] = ARstations[opt.recv].fixPos_[i] - ARstations[opt.recv].snxPos_[i]; - dXYZ_FL[i] = ARstations[opt.recv].fltPos_[i] - ARstations[opt.recv].snxPos_[i]; - } - - double dENU_FL[3]; - double dENU_AR[3]; - ecef2enu(latLonHt, dXYZ_AR, dENU_AR); - ecef2enu(latLonHt, dXYZ_FL, dENU_FL); - - int week_; - double tow_ = time2gpst(time,&week_); - tracepdeex(2,trace, "\n#ARES_DPOS,%4d,%8.1f,",week_,tow_); + VectorEcef dXYZ_FL = ARstations[opt.recv].fltPos_ - ARstations[opt.recv].snxPos_; + VectorEcef dXYZ_AR = ARstations[opt.recv].fixPos_ - ARstations[opt.recv].snxPos_; + + VectorEnu dENU_FL = ecef2enu(pos, dXYZ_FL); + VectorEnu dENU_AR = ecef2enu(pos, dXYZ_AR); + + tracepdeex(2,trace, "\n#ARES_DPOS,%4d,%8.1f,",week,tow); tracepdeex(2,trace, "%8.4f,%8.4f,%8.4f,",dENU_AR[0],dENU_AR[1],dENU_AR[2]); tracepdeex(2,trace, "%8.4f,%8.4f,%8.4f,",dENU_FL[0],dENU_FL[1],dENU_FL[2]); } @@ -139,111 +128,6 @@ void artrcout( return; } -/** Output phase biases */ -void arbiaout( - Trace& trace, ///< Output stream - GTime time, ///< Solution time - GinAR_opt opt ) ///< Ginan AR control options -{ - int week; - double tow=time2gpst(time,&week); - - double tupdt = opt.bias_update; - if (tupdt==0) - return; - - for (auto& [typ,lst] : SATbialist) - for (auto& [sat,bia] : lst) - { - /* reflect the biases here (maybe save a time series) */ - tracepdeex(ARTRCLVL,trace,"\n#ARES_BIA %4d, %8.1f, %s, %s %8.4f, %8.4f, %11.4e", week, tow, typ._to_string(), sat.id().c_str(),bia.rawbias, bia.outbias, sqrt(bia.outvari)); - - E_FType frq1; - E_FType frq2; - E_FType frq3; - if (!sys_frq(sat.sys, frq1, frq2, frq3)) continue; - - E_ObsCode non = E_ObsCode::NONE; - E_ObsCode def1 = opt.defCodes[sat.sys][frq1]; - E_ObsCode def2 = opt.defCodes[sat.sys][frq2]; - E_ObsCode def3 = opt.defCodes[sat.sys][frq3]; - - if (typ == +E_AmbTyp::UCL1) outp_bias(trace,time,"", sat,def1,non,bia.outbias,bia.outvari,tupdt,PHAS); - if (typ == +E_AmbTyp::UCL2) outp_bias(trace,time,"", sat,def2,non,bia.outbias,bia.outvari,tupdt,PHAS); - if (typ == +E_AmbTyp::UCL3) outp_bias(trace,time,"", sat,def3,non,bia.outbias,bia.outvari,tupdt,PHAS); - if (typ == +E_AmbTyp::NL12) - { - if (SATbialist[E_AmbTyp::WL12].find(sat) == SATbialist[E_AmbTyp::WL12].end()) - continue; - - double NLbia = bia.outbias; - double NLvar = bia.outvari; - double WLbia = SATbialist[E_AmbTyp::WL12][sat].outbias; - double WLvar = SATbialist[E_AmbTyp::WL12][sat].outvari; - - double lam1 = lambdas[def1]; - double lam2 = lambdas[def2]; - - double c1 = lam1 / (lam2 - lam1); - double c2 = lam2 / (lam2 - lam1); - double L1bia = lam1 * (NLbia - c1 * WLbia); - double L2bia = lam2 * (NLbia - c2 * WLbia); - double L1var = lam1*lam1 * (NLvar + c1*c1 * WLvar); - double L2var = lam2*lam2 * (NLvar + c2*c2 * WLvar); - - outp_bias(trace,time,"",sat,def1,non,L1bia,L1var,tupdt,PHAS); - outp_bias(trace,time,"",sat,def2,non,L2bia,L2var,tupdt,PHAS); - } - } - - SatSys sat0 = {}; - for (auto& [typ,lst1] : RECbialist) - for (auto& [sys,lst2] : lst1) - for (auto& [rec,bia] : lst2) - { - /* reflect the biases here (maybe save a time series) */ - tracepdeex(ARTRCLVL+1,trace,"\n#ARES_BIA %4d, %8.1f, %s, %s, %s, %8.4f, %8.4f, %11.4e", week, tow, typ._to_string(), sys._to_string(), rec.c_str(), bia.rawbias, bia.outbias, sqrt(bia.outvari)); - - E_FType frq1; - E_FType frq2; - E_FType frq3; - if (!sys_frq(sys, frq1, frq2, frq3)) continue; - - E_ObsCode non = E_ObsCode::NONE; - E_ObsCode def1 = opt.defCodes[sys][frq1]; - E_ObsCode def2 = opt.defCodes[sys][frq2]; - E_ObsCode def3 = opt.defCodes[sys][frq3]; - - if (typ == +E_AmbTyp::UCL1) outp_bias(trace,time,rec,sat0,def1,non,bia.outbias,bia.outvari,tupdt,PHAS); - if (typ == +E_AmbTyp::UCL2) outp_bias(trace,time,rec,sat0,def2,non,bia.outbias,bia.outvari,tupdt,PHAS); - if (typ == +E_AmbTyp::UCL3) outp_bias(trace,time,rec,sat0,def3,non,bia.outbias,bia.outvari,tupdt,PHAS); - if (typ == +E_AmbTyp::NL12) - { - if (RECbialist[E_AmbTyp::WL12].find(sys) == RECbialist[E_AmbTyp::WL12].end()) continue; - if (RECbialist[E_AmbTyp::WL12][sys].find(rec) == RECbialist[E_AmbTyp::WL12][sys].end()) continue; - - double NLbia = bia.outbias; - double NLvar = bia.outvari; - double WLbia = RECbialist[E_AmbTyp::WL12][sys][rec].outbias; - double WLvar = RECbialist[E_AmbTyp::WL12][sys][rec].outvari; - - double lam1 = lambdas[def1]; - double lam2 = lambdas[def2]; - - double c1 = lam1 / (lam2 - lam1); - double c2 = lam2 / (lam2 - lam1); - double L1bia = lam1 * (NLbia - c1 * WLbia); - double L2bia = lam2 * (NLbia - c2 * WLbia); - double L1var = lam1*lam1 * (NLvar + c1*c1 * WLvar); - double L2var = lam2*lam2 * (NLvar + c2*c2 * WLvar); - - outp_bias(trace,time,rec,sat0,def1,non,L1bia,L1var,tupdt,PHAS); - outp_bias(trace,time,rec,sat0,def2,non,L2bia,L2var,tupdt,PHAS); - } - } - return; -} - /** Export AR Ionosphere measurments */ int arionout( Trace& trace, ///< Debug stream @@ -253,7 +137,7 @@ int arionout( { int nion=0; - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { KFKey key; if ( opt.ionmod == +E_IonoMode::ESTIMATE ) @@ -262,7 +146,7 @@ int arionout( double val; double var; if (!kfState.getKFValue(key,val,&var)) - continue; + continue; obs.STECsmth = val; obs.STECsmvr = var; @@ -271,10 +155,15 @@ int arionout( } else if ( opt.ionmod == +E_IonoMode::IONO_FREE_LINEAR_COMBO ) { - E_FType frq1 = F1; - E_FType frq2 = F2; + E_FType frq1; + E_FType frq2; + E_FType frq3; + if (!satFreqs(obs.Sat.sys, frq1, frq2, frq3)) + continue; int wlamb = retrv_WLambg(trace, E_AmbTyp::WL12,kfState.time,obs.mount,obs.Sat); + if ( wlamb == INVALID_WLVAL) + continue; if (opt.endu) key = {KF::PHASE_BIAS,obs.Sat, obs.mount, E_FType::FTYPE_IF12}; else key = {KF::AMBIGUITY ,obs.Sat, obs.mount, E_FType::FTYPE_IF12}; @@ -289,8 +178,6 @@ int arionout( frq2 = F5; } - if ( wlamb == INVALID_WLVAL) continue; - double lam1 = obs.satNav_ptr->lamMap[frq1]; double lam2 = obs.satNav_ptr->lamMap[frq2]; if ( lam1 == 0 || lam2 == 0) continue; @@ -312,14 +199,15 @@ int arionout( wlvari = satbias.outvari + recbias.outvari; } - double c2 = lam1*lam1/(lam2-lam1); - double c1 = c2/(lam2+lam1); - double c3 = lam1/lam2; - double s1 = c1*c1; - double s2 = c2*c2; - double s3 = c3*c3; + double alpha = SQR(CLIGHT)/40.30E16; + double c2 = alpha/(lam1-lam2); + double c1 = -c2/(lam1+lam2); + double c3 = alpha/lam1/lam2; + double s1 = SQR(c1); + double s2 = SQR(c2); + double s3 = SQR(c3); - obs.STECsmth = c1*(L2-L1) + c2*(wlamb + wlbias) - c3*val; + obs.STECsmth = c1*(L1-L2) + c2*(wlamb + wlbias) + c3*val; obs.STECsmvr = s1*(V2+V1) + s2*( wlvari) + s3*val; obs.STECtype = 2; nion++; @@ -329,91 +217,69 @@ int arionout( return nion; } -/* Querry satellite phase bias */ -bool queryBiasOutput( - Trace& trace, ///< Debug stream - SatSys sat, ///< GNSS satellite - E_AmbTyp type, ///< Ambiguity type UCL1, UCL2, UCL3, NL12, WL12 - double& bias, ///< Phase bias value - double& variance) ///< Phase bias variance +/** Querry Ginan 1.0 AR algorithms for phase biases, it does not check for specific codes just carrier frequencies +returns false if bias is not found */ +bool queryBiasWLNL( + Trace& trace, ///< debug stream + SatSys sat, ///< satellite (for receiver biases, sat.sys needs to be set to the appropriate system, and sat.prn must be 0) + string rec, ///< receiver (for satellite biases nees to be "") + E_FType ft, ///< Signal frequency + double& bias, ///< signal bias + double& vari) ///< bias variance { - tracepdeex(ARTRCLVL, trace, "\n#ARES_BIAS Searching for %s biases: ", sat.id().c_str()); + E_Sys sys = sat.sys; - if (SATbialist.find(E_AmbTyp::WL12)!=SATbialist.end() - && SATbialist.find(E_AmbTyp::NL12)!=SATbialist.end()) + E_FType frq1; + E_FType frq2; + E_FType frq3; + if (!satFreqs(sys, frq1, frq2, frq3)) + return false; + + if ( ft != frq1 + && ft != frq2) { - if(SATbialist[E_AmbTyp::WL12].find(sat) == SATbialist[E_AmbTyp::WL12].end()) - { - tracepdeex(ARTRCLVL, trace, "WL not found\n"); - return false; - } - - if(SATbialist[E_AmbTyp::NL12].find(sat) == SATbialist[E_AmbTyp::NL12].end()) - { - tracepdeex(ARTRCLVL, trace, "NL not found\n"); - return false; - } + return false; + } + + double lam_ = nav.satNavMap[sat].lamMap[ft]; + double lam1 = nav.satNavMap[sat].lamMap[frq1]; + double lam2 = nav.satNavMap[sat].lamMap[frq2]; + + /* satellite bias */ + if (rec.empty()) + { + if (SATbialist[E_AmbTyp::WL12].find(sat) == SATbialist[E_AmbTyp::WL12].end()) return false; + if (SATbialist[E_AmbTyp::NL12].find(sat) == SATbialist[E_AmbTyp::NL12].end()) return false; double WLbia = SATbialist[E_AmbTyp::WL12][sat].outbias; double WLvar = SATbialist[E_AmbTyp::WL12][sat].outvari; double NLbia = SATbialist[E_AmbTyp::NL12][sat].outbias; double NLvar = SATbialist[E_AmbTyp::NL12][sat].outvari; - tracepdeex(ARTRCLVL, trace, "WL: %.4f + NL:%.4f\n", WLbia, NLbia); - - double lam1 = CLIGHT/FREQ1; - double lam2 = CLIGHT/FREQ2; - - if (sat.sys == +E_Sys::GAL) - lam2 = CLIGHT/FREQ5; - - if (type == +E_AmbTyp::UCL1) - { - double c = lam1 / (lam2-lam1); - bias = lam1 * (NLbia - c*WLbia); - variance = lam1*lam1 * (NLvar + c*c*WLvar); - return true; - } - - if (type == +E_AmbTyp::UCL2) - { - double c = lam2 / (lam2-lam1); - bias = lam2 * (NLbia - c*WLbia); - variance = lam2*lam2 * (NLvar + c*c*WLvar); - return true; - } + double c1 = lam_ / (lam2 - lam1); + bias = lam_ * (NLbia - c1 * WLbia); + vari = lam_*lam_ * (NLvar + c1*c1 * WLvar); + return true; } - if (SATbialist.find(type) == SATbialist.end()) + /* receiver bias */ + if (sat.prn==0) { - tracepdeex(ARTRCLVL, trace, "%s not found\n",type._to_string()); - return false; - } - if(SATbialist[type].find(sat) == SATbialist[type].end()) - return false; - - - double lam1 = CLIGHT/FREQ1; - if (type == +E_AmbTyp::UCL2) - { - if(sat.sys == +E_Sys::GAL) - lam1 = CLIGHT/FREQ5; - else - lam1 = CLIGHT/FREQ2; - } - - if (type == +E_AmbTyp::UCL3) - { - if(sat.sys == +E_Sys::GAL) - lam1 = CLIGHT/FREQ7; - else - lam1 = CLIGHT/FREQ5; + if (RECbialist[E_AmbTyp::WL12].find(sat.sys) == RECbialist[E_AmbTyp::WL12].end()) return false; + if (RECbialist[E_AmbTyp::WL12][sat.sys].find(rec) == RECbialist[E_AmbTyp::WL12][sys].end()) return false; + if (RECbialist[E_AmbTyp::NL12].find(sat.sys) == RECbialist[E_AmbTyp::NL12].end()) return false; + if (RECbialist[E_AmbTyp::NL12][sat.sys].find(rec) == RECbialist[E_AmbTyp::NL12][sys].end()) return false; + + double WLbia = RECbialist[E_AmbTyp::WL12][sat.sys][rec].outbias; + double WLvar = RECbialist[E_AmbTyp::WL12][sat.sys][rec].outvari; + double NLbia = RECbialist[E_AmbTyp::NL12][sat.sys][rec].outbias; + double NLvar = RECbialist[E_AmbTyp::NL12][sat.sys][rec].outvari; + + double c1 = lam_ / (lam2 - lam1); + bias = lam_ * (NLbia - c1 * WLbia); + vari = lam_*lam_ * (NLvar + c1*c1 * WLvar); + return true; } - bias = SATbialist[type][sat].outbias*lam1; - variance = SATbialist[type][sat].outvari*lam1*lam1; - - tracepdeex(ARTRCLVL, trace, ".4f",bias); - - return true; -} + return false; /* Ginan 1.0 does not support hybrid biases */ +} diff --git a/src/cpp/ambres/GinARpivot.cpp b/src/cpp/ambres/GinARpivot.cpp index 9cc0b468a..37c3f96be 100644 --- a/src/cpp/ambres/GinARpivot.cpp +++ b/src/cpp/ambres/GinARpivot.cpp @@ -348,7 +348,7 @@ int Reset_rec( for (auto& [sat,piv] : SATpivlist[typ][sys]) { key.Sat=sat; - if ( piv.pre_rec == "") continue; + if ( piv.pre_rec.empty()) continue; if (AR_mealist.find(key) == AR_mealist.end()) continue; if (AR_mealist[key].out_epc > 0 ) continue; @@ -717,7 +717,7 @@ void updt_net_pivot( if (recpivlst.find(key.str) == recpivlst.end()) disc_rec[key.str] = E_SigWarning::SIG_OUTG; if (recpivlst[key.str].pre_sat.prn <= 0) disc_rec[key.str] = E_SigWarning::SIG_OUTG; if (satpivlst.find(key.Sat) == satpivlst.end()) disc_sat[key.Sat] = E_SigWarning::SIG_OUTG; - if (satpivlst[key.Sat].pre_rec == "") disc_sat[key.Sat] = E_SigWarning::SIG_OUTG; + if (satpivlst[key.Sat].pre_rec.empty()) disc_sat[key.Sat] = E_SigWarning::SIG_OUTG; } Check_rec(trace,sys,typ,sysref,0); diff --git a/src/cpp/brdc2sp3/brdc2sp3_main.cpp b/src/cpp/brdc2sp3/brdc2sp3_main.cpp deleted file mode 100644 index 94e18bd89..000000000 --- a/src/cpp/brdc2sp3/brdc2sp3_main.cpp +++ /dev/null @@ -1,849 +0,0 @@ -#include -#include -#include -using std::string; - -#include -#include - -#include "streamTrace.hpp" -#include "navigation.hpp" -#include "constants.hpp" -#include "station.hpp" -#include "antenna.hpp" -#include "satSys.hpp" -#include "tides.hpp" -#include "rinex.hpp" -#include "gTime.hpp" - -#define J2_GLO 1.0826257E-3 /* 2nd zonal harmonic of geopot ref [2] */ - -#define OMGE_GLO 7.292115E-5 /* earth angular velocity (rad/s) ref [2] */ -#define OMGE_GAL 7.2921151467E-5 /* earth angular velocity (rad/s) ref [7] */ -#define OMGE_CMP 7.292115E-5 /* earth angular velocity (rad/s) ref [9] */ - -#define RTOL_KEPLER 1E-14 /* relative tolerance for Kepler equation */ -#define MAX_ITER_KEPLER 30 /* max number of iteration of Kelpler */ -#define GLOSTEP 60.0 - -#define SIN_5 -0.0871557427476582 /* sin(-5.0 deg) */ -#define COS_5 0.9961946980917456 /* cos(-5.0 deg) */ - -Navigation nav = {}; -string GNSSinp="GE"; -map BS_Satel_List; -int BS_Start_Week = 0; -double BS_Start_TOW = 0.0; -double BS_Start_Epoc[6] = {0}; -int BS_Epoch_Num = 0; -double BS_Epoch_Inter = 900.0; -map BS_Max_Dtime; -map BS_Est_Delay; -map BS_Err_Thres; - -void helpstring(void) -{ - fprintf(stdout, " brdc2sp3 -antx -rinx [options]\n"); - fprintf(stdout, " Options [default]:\n"); - fprintf(stdout, " -gnss string GNSS to be processed: G: GPS, R:GLONASS, E:Galileo, C: Beidou, J: QZSS, A: all [GE]\n"); - fprintf(stdout, " -intr float Time spacing of SP3 entries [900.0]\n"); - fprintf(stdout, " -outf string File name for SP3 output [BS_orbits.sp3]\n"); - fprintf(stdout, " -*dte max_dt set max diference-to-TOE for constellation (*: 'G','R','E','J' or 'C') \n"); - fprintf(stdout, " -*chk max_dt set max differece-to-median for ephemeris message check (for each constellation)\n"); - fprintf(stdout, " -clst Select ephemeris with closest Toe (within max_dt seconds) [Latest valid ephemeris]\n"); - fprintf(stdout, " -inav I/NAV only for Galileo [use both F/NAV and I/NAV]\n"); - fprintf(stdout, " -fnav F/NAV only for Galileo [use both F/NAV and I/NAV]\n"); - fprintf(stdout, " -frst Filter out satellites with no/bad data in first epoc [not filtered]\n"); -} - -int BS_satantoff( GTime time, SatSys Sat, Vector3d& rs, Vector3d& dant, int gloind = 0) -{ - double lam1, lam2; - - char id[5]; - Sat.getId(id); - - E_FType j = F1; - E_FType k = F2; - double glonfrq1 = FREQ1_GLO + DFRQ1_GLO*gloind; - double glonfrq2 = FREQ2_GLO + DFRQ2_GLO*gloind; - switch (Sat.sys) - { - case E_Sys::GPS: lam1 = CLIGHT/FREQ1; lam2 = CLIGHT/FREQ2; break; - case E_Sys::GLO: lam1 = CLIGHT/glonfrq1; lam2 = CLIGHT/glonfrq2; break; - case E_Sys::QZS: lam1 = CLIGHT/FREQ1; lam2 = CLIGHT/FREQ2; break; - case E_Sys::GAL: lam1 = CLIGHT/FREQ1; lam2 = CLIGHT/FREQ5; k=F5; break; - case E_Sys::BDS: lam1 = CLIGHT/FREQ1_CMP; lam2 = CLIGHT/FREQ2_CMP; break; - default: return -2; - } - - /* sun position in ecef */ - Vector3d rsun; - double gmst; - ERPValues erpv; - sunmoonpos(gpst2utc(time), erpv, &rsun, nullptr, &gmst); - - /* unit vectors of satellite fixed coordinates */ - Vector3d r = -rs; - Vector3d ez = r.normalized(); - r = rsun - rs; - Vector3d es = r.normalized(); - r = ez.cross(es); - Vector3d ey = r.normalized(); - Vector3d ex = ey.cross(ez); - - double gamma = lam2*lam2/lam1/lam1; - double C1 = gamma / (gamma - 1); - double C2 = -1 / (gamma - 1); - - /* iono-free LC */ - for (int i = 0; i < 3; i++) - { - /* ENU to NEU */ - Vector3d pcoJ = antPco(Sat.id(), Sat.sys, j, time); - Vector3d pcoK = antPco(Sat.id(), Sat.sys, k, time); - double dant1 = pcoJ[1] * ex(i) - + pcoJ[0] * ey(i) - + pcoJ[2] * ez(i); //todo aaron, matrix - double dant2 = pcoK[1] * ex(i) - + pcoK[0] * ey(i) - + pcoK[2] * ez(i); - - // fprintf( stdout,"\n ATX: %s %11.6f %11.6f %11.6f %11.6f %11.6f %11.6f", Sat.id().c_str(), pcoJ[0], pcoJ[1], pcoJ[2], pcoK[0], pcoK[1], pcoK[2]); - - //dant(i) = C1 * dant1 - // + C2 * dant2; - dant(i) = dant1; - } - return 0; -} - -Eph* BS_seleph( GTime time, SatSys Sat, int iode, Navigation& nav_, int opt=0) -{ - // double valid = double valid = BS_Max_Dtime[Sat.sys]; - - // switch (Sat.sys) - // { - // case E_Sys::QZS: valid = MAXDTOE_QZS + 1; break; - // case E_Sys::GAL: valid = MAXDTOE_GAL + 1; break; - // case E_Sys::BDS: valid = MAXDTOE_CMP + 1; break; - // default: valid = MAXDTOE + 1; break; - // } - - auto& ephList = nav_.ephMap[Sat]; - Eph* chosen = nullptr; - Eph* closest = nullptr; - GTime latestToe = GTime::noTime(); - double max_dtime = 86400; - GTime teph = time - BS_Est_Delay[Sat.sys]; - double max_dtime2 = BS_Max_Dtime[Sat.sys]; - for (auto& [dummy, eph] : ephList) - { - if ( iode >= 0 ) - { - if(iode == eph.iode) return &eph; - else continue; - } - - if (eph.svh == SVH_UNHEALTHY) - continue; - - double dtime= fabs(eph.toe - time); - - if ( max_dtime > dtime) - { - closest = &eph; - max_dtime = dtime; - } - - // if (dtime > valid) - // continue; - - double dtime2=(teph - eph.toe); - - if (dtime2 < 0) - continue; - - if (dtime2 <= max_dtime2) - { - chosen = &eph; - max_dtime2 = dtime2; - } - } - - if (!chosen - && opt==1) - chosen = closest; - - return chosen; -} - -Geph* BS_selgeph( GTime time, SatSys Sat, int iode, Navigation& nav_, int opt=0) -{ - // double valid = MAXDTOE_GLO + 1; - // double valid = BS_Max_Dtime[E_Sys::GLO]; - - auto& gephList = nav_.gephMap[Sat]; - Geph* chosen = nullptr; - Geph* closest = nullptr; - GTime latestToe = GTime::noTime(); - double max_dtime = 86400; - GTime teph = time - BS_Est_Delay[E_Sys::GLO]; - double max_dtime2 = BS_Max_Dtime[E_Sys::GLO]; - for (auto& [dummy, geph] : gephList) - { - if ( iode >= 0 ) - { - if(iode == geph.iode) return &geph; - else continue; - } - - if (geph.svh == SVH_UNHEALTHY) - continue; - - double dtime = fabs(geph.toe - time); - if ( max_dtime > dtime) - { - closest = &geph; - max_dtime = dtime; - } - - // if (dtime > valid) - // continue; - - double dtime2=(teph - geph.toe); - - if (dtime2 < 0) - continue; - - if (dtime2 <= max_dtime2) - { - chosen = &geph; - max_dtime2 = dtime2; - } - } - - if (!chosen - && opt==1) - chosen = closest; - - return chosen; -} - -/* glonass orbit differential equations --------------------------------------*/ -void deq(const double* x, double* xdot, Vector3d& acc) -{ - double a, b, c, r2 = dot(x, x, 3), r3 = r2 * sqrt(r2), omg2 = OMGE_GLO*OMGE_GLO; - - if (r2 <= 0.0) - { - xdot[0] = xdot[1] = xdot[2] = xdot[3] = xdot[4] = xdot[5] = 0.0; - return; - } - - /* ref [2] A.3.1.2 with bug fix for xdot[4],xdot[5] */ - a = 1.5 * J2_GLO * MU_GLO * RE_GLO*RE_GLO / r2 / r3; /* 3/2*J2*mu*Ae^2/r^5 */ - b = 5.0 * x[2] * x[2] / r2; /* 5*z^2/r^2 */ - c = -MU_GLO / r3 - a * (1.0 - b); /* -mu/r^3-a(1-b) */ - xdot[0] = x[3]; - xdot[1] = x[4]; - xdot[2] = x[5]; - xdot[3] = (c + omg2) * x[0] + 2.0 * OMGE_GLO * x[4] + acc[0]; - xdot[4] = (c + omg2) * x[1] - 2.0 * OMGE_GLO * x[3] + acc[1]; - xdot[5] = (c - 2.0 * a) * x[2] + acc[2]; -} - -/* glonass position and velocity by numerical integration --------------------*/ -void glorbit(double t, double* x, Vector3d& acc) -{ - double k1[6], k2[6], k3[6], k4[6], w[6]; - int i; - - deq(x, k1, acc); for (i = 0; i < 6; i++) w[i] = x[i] + k1[i] * t / 2; - deq(w, k2, acc); for (i = 0; i < 6; i++) w[i] = x[i] + k2[i] * t / 2; - deq(w, k3, acc); for (i = 0; i < 6; i++) w[i] = x[i] + k3[i] * t; - deq(w, k4, acc); - - for (i = 0; i < 6; i++) - x[i] += (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]) * t / 6; -} - -int BS_geph2pos( GTime time, Geph* geph, Vector3d& rs, double* dts) -{ - double t = time - geph->toe; - *dts = geph->taun - + geph->gamn * t; - - double x[6] = {0}; - for (int i = 0; i < 3; i++) - { - x[i ] = geph->pos[i]; - x[i+3] = geph->vel[i]; - } - - for (double tt = t < 0 ? -GLOSTEP : GLOSTEP; fabs(t) > 1E-9; t -= tt) - { - if (fabs(t) < GLOSTEP) tt=t; - glorbit(tt, x, geph->acc); - } - - for (int i = 0; i < 3; i++) rs(i) = x[i]; - - return 0; -} - -int BS_eph2pos( GTime time, Eph* eph, Vector3d& rs, double* dts) { - - if (eph->A <= 0) return -1; - - double tk = time - eph->toe; - int prn = eph->Sat.prn; - int sys = eph->Sat.sys; - - double mu; - double omge; - switch (sys) - { - case E_Sys::GAL: mu = MU_GAL; omge = OMGE_GAL; break; - case E_Sys::BDS: mu = MU_CMP; omge = OMGE_CMP; break; - default: mu = MU_GPS; omge = OMGE; break; - } - - double M = eph->M0 + (sqrt(mu / (eph->A * eph->A * eph->A)) + eph->deln) * tk; - - double E = M; - double Ek = 0; - int n; - for (n = 0; fabs(E - Ek) > RTOL_KEPLER && n < MAX_ITER_KEPLER; n++) - { - Ek = E; - E -= (E - eph->e * sin(E) - M) / (1 - eph->e * cos(E)); - } - - if (n >= MAX_ITER_KEPLER) - { - fprintf(stderr,"WARNING for %s ephemeris: iteration divergent", eph->Sat.id().c_str()); - return -1; - } - - double sinE = sin(E); - double cosE = cos(E); - double u = atan2(sqrt(1 - eph->e * eph->e) * sinE, cosE - eph->e) + eph->omg; - double r = eph->A * (1 - eph->e * cosE); - double i = eph->i0 + eph->idot * tk; - double sin2u = sin(2 * u); - double cos2u = cos(2 * u); - - u += eph->cus * sin2u + eph->cuc * cos2u; - r += eph->crs * sin2u + eph->crc * cos2u; - i += eph->cis * sin2u + eph->cic * cos2u; - - double x = r * cos(u); - double y = r * sin(u); - double cosi = cos(i); - - /* beidou geo satellite, prn range may change in the future */ - if (sys == +E_Sys::BDS && (prn <= 5 || prn >= 59)) - { - double O = eph->OMG0 - + eph->OMGd * tk - - omge * eph->toes; - double sinO = sin(O); - double cosO = cos(O); - double xg = x * cosO - y * cosi * sinO; - double yg = x * sinO + y * cosi * cosO; - double zg = y * sin(i); - double sino = sin(omge * tk); - double coso = cos(omge * tk); - rs(0) = +xg * coso + yg * sino * COS_5 + zg * sino * SIN_5; - rs(1) = -xg * sino + yg * coso * COS_5 + zg * coso * SIN_5; - rs(2) = -yg * SIN_5 + zg * COS_5; - } - else - { - double O = eph->OMG0 - + (eph->OMGd - omge) * tk - - omge * eph->toes; - double sinO = sin(O); - double cosO = cos(O); - rs(0) = x * cosO - y * cosi * sinO; - rs(1) = x * sinO + y * cosi * cosO; - rs(2) = y * sin(i); - } - - tk = time - eph->toc; - *dts = eph->f0 - + eph->f1 * tk - + eph->f2 * tk * tk; - return 0; -} - -void median_check(GTime tstart, GTime tfinsh, map satList ) -{ - GTime midEpoch = tstart + (tstart-tfinsh)/2; - for(auto& [sat,nephs] : satList) - if(BS_Err_Thres[sat.sys]>0) - { - double dts; - - if(sat.sys == +E_Sys::GLO) - { - int ind=0; - map mid_posX; - map mid_posY; - map mid_posZ; - vector midX; - vector midY; - vector midZ; - - map eph_time; - - for(auto& [teph, geph] : nav.gephMap[sat]) - { - Vector3d rs(0,0,0); - - BS_geph2pos( midEpoch, &geph, rs, &dts); - eph_time[ind] = teph; - mid_posX[ind] = rs[0]; - mid_posY[ind] = rs[1]; - mid_posZ[ind] = rs[2]; - midX.push_back(rs[0]); - midY.push_back(rs[1]); - midZ.push_back(rs[2]); - ind++; - } - std::sort(midX.begin(),midX.end()); - std::sort(midY.begin(),midY.end()); - std::sort(midZ.begin(),midZ.end()); - double Xmedian=midX[(ind/2)]; - double Ymedian=midY[(ind/2)]; - double Zmedian=midZ[(ind/2)]; - for (int i=0; iBS_Err_Thres[sat.sys]) - { - nav.gephMap[sat].erase(eph_time[i]); - fprintf(stdout, "\nDiscarding geph for %s Toe:%s dX=%13.3f",sat.id().c_str(),eph_time[i].to_string(0).c_str(),dX); - } - } - } - else - { - int ind=0; - map mid_posX; - map mid_posY; - map mid_posZ; - vector midX; - vector midY; - vector midZ; - - map eph_time; - - for(auto& [teph, eph] : nav.ephMap[sat]) - { - Vector3d rs(0,0,0); - - BS_eph2pos( midEpoch, &eph, rs, &dts); - eph_time[ind] = teph; - mid_posX[ind] = rs[0]; - mid_posY[ind] = rs[1]; - mid_posZ[ind] = rs[2]; - midX.push_back(rs[0]); - midY.push_back(rs[1]); - midZ.push_back(rs[2]); - ind++; - } - std::sort(midX.begin(),midX.end()); - std::sort(midY.begin(),midY.end()); - std::sort(midZ.begin(),midZ.end()); - int indi=ind/2; - double Xmedian = midX[ind/2]; - double Ymedian = midY[ind/2]; - double Zmedian = midZ[ind/2]; - - for (int i=0; i BS_Err_Thres[sat.sys]) - { - nav.ephMap[sat].erase(eph_time[i]); - fprintf(stdout, "\nDiscarding eph for %s Toe:%s dX= %13.3f",sat.id().c_str(),eph_time[i].to_string(0).c_str(), dX); - continue; - } - } - } - } -} - -void print_SP3header(FILE* fpout) -{ - /* line one */ - fprintf(fpout,"#dP%4.0f %2.0f %2.0f %2.0f %2.0f %11.8f ", BS_Start_Epoc[0], BS_Start_Epoc[1], BS_Start_Epoc[2], BS_Start_Epoc[3], BS_Start_Epoc[4], BS_Start_Epoc[5]); - fprintf(fpout,"%7d ORBIT WGS84 BCT GA", BS_Epoch_Num); - - /* Line two */ - double mjdate = 7.0*BS_Start_Week + BS_Start_TOW/86400.0 + 44244.0; - fprintf(fpout,"\n## %4d %15.8f %5.0f %15.13f", BS_Start_Week, BS_Start_TOW, mjdate, mjdate-floor(mjdate)); - - /* satellite lines */ - int NumSatLeft = 85, satind=0, satinline=0; - if(BS_Satel_List.size()>85) NumSatLeft = BS_Satel_List.size(); - auto it = BS_Satel_List.begin(); - while(satind < NumSatLeft || satinline > 0) - { - if(satind == 0) fprintf(fpout, "\n+ %3d ", (int)BS_Satel_List.size()); - else if(satinline == 0) fprintf(fpout, "\n+ "); - - if(it==BS_Satel_List.end()) fprintf(fpout, " 0"); - else - { - fprintf(fpout,"%s",it->first.id().c_str()); - it++; - } - - satind++; - if(satinline<16) satinline++; - else satinline = 0; - } - - /* accuracy lines */ - satind = 0; - satinline = 0; - while(satind 1) fprintf(fpout, "\n%%c M "); - else fprintf(fpout, "\n%%c %s ", GNSSinp.c_str()); - fprintf(fpout, " cc GPS ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc"); - fprintf(fpout, "\n%%c cc cc GPS ccc cccc cccc cccc cccc ccccc ccccc ccccc ccccc"); - - /* float variable lines */ - fprintf(fpout, "\n%%f 1.2500000 1.025000000 0.00000000000 0.000000000000000"); - fprintf(fpout, "\n%%f 0.0000000 0.000000000 0.00000000000 0.000000000000000"); - - /* float variable lines */ - fprintf(fpout, "\n%%i 0 0 0 0 0 0 0 0 0"); - fprintf(fpout, "\n%%i 0 0 0 0 0 0 0 0 0"); - - fprintf(fpout, "\n/* Created using Ginan at: %s. ", timeget().to_string(0).c_str()); - fprintf(fpout, "\n/* WARNING: For Geoscience Australia's internal use only"); -} - -void print_SP3epoch(FILE* fpout, GTime tsync, map>& temp_eph) -{ - double ep[6]; - time2epoch(tsync, ep); - fprintf(fpout,"\n* %4.0f %2.0f %2.0f %2.0f %2.0f %11.8f ", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); - - for(auto& [sat, neph] : BS_Satel_List){ - if(temp_eph.find(sat) == temp_eph.end()) - fprintf(fpout, "\nP%s%14.6f%14.6f%14.6f 999999.999999 ", sat.id().c_str(), 0.0, 0.0, 0.0); - else - { - auto vect = temp_eph[sat]; - fprintf(fpout, "\nP%s%14.6f%14.6f%14.6f%14.6f ", sat.id().c_str(), vect[0]/1000, vect[1]/1000, vect[2]/1000, vect[3]*1e6); - } - } -} - - -int main(int argc, char **argv) -{ - boost::log::core::get()->set_filter (boost::log::trivial::severity >= boost::log::trivial::info); - string atxfile = "igs14.atx"; - vector navfiles; - int GALSelection = 7; - /* Argument parsing */ - string inpfile; - string outfile = "BS_orbits.sp3"; - bool fstreq = false; - BS_Max_Dtime[E_Sys::GPS] = 14400; - BS_Max_Dtime[E_Sys::GLO] = 3600; - BS_Max_Dtime[E_Sys::GAL] = 3600; - BS_Max_Dtime[E_Sys::QZS] = 3600; - BS_Max_Dtime[E_Sys::BDS] = 7200; - - BS_Est_Delay[E_Sys::GPS] = -7200.0; - BS_Est_Delay[E_Sys::GLO] = -900; - BS_Est_Delay[E_Sys::GAL] = 660; - BS_Est_Delay[E_Sys::QZS] = 0; - BS_Est_Delay[E_Sys::BDS] = 0; - - BS_Err_Thres[E_Sys::GPS] = 3000; - BS_Err_Thres[E_Sys::GLO] = 9000; - BS_Err_Thres[E_Sys::GAL] = 15000; - BS_Err_Thres[E_Sys::QZS] = 9000; - BS_Err_Thres[E_Sys::BDS] = 9000; - - int ephopt = 0; - for (int i = 1; i < argc; i++) - { - if (!strcmp(argv[i], "-rinx") && i+1 < argc) - { - inpfile.assign(argv[++i]); - navfiles.push_back(inpfile); - } - else if (!strcmp(argv[i], "-outf") && i+1 GNSS_on; - if (GNSSinp.find("A") != std::string::npos) GNSSinp = "GRECJ"; //All constellations - if (GNSSinp.find("G") != std::string::npos) GNSS_on[E_Sys::GPS] = true; //GPS - if (GNSSinp.find("R") != std::string::npos) GNSS_on[E_Sys::GLO] = true; //GLONASS - if (GNSSinp.find("E") != std::string::npos) GNSS_on[E_Sys::GAL] = true; //Galileo - if (GNSSinp.find("C") != std::string::npos) GNSS_on[E_Sys::BDS] = true; //Beidou - if (GNSSinp.find("J") != std::string::npos) GNSS_on[E_Sys::QZS] = true; //QZSS - if (GNSS_on.empty()) - { - fprintf(stderr, "No GNSS selected\n"); - exit(0); - } - std::cout << "Processed GNSS " << GNSSinp << std::endl; - - char type = 'N'; - ObsList obsList; - RinexStation sta; - double version = 0; - E_Sys sys; - int tsys; - map> sysCodeTypes; - int nfil = 0; - - for (auto& file : navfiles) - { - std::ifstream inputStream; - inputStream.open(file, std::ifstream::in); - int info = readrnx(inputStream, type , obsList, nav, &sta, version, sys, tsys, sysCodeTypes); - if (info == false) - { - std::cout << "ERROR: invalid BRDC file " << file.c_str() << std::endl; - } - else{ - std::cout << "Processed file " << file << " " << type << " " << version << " " << std::endl; - nfil++; - info = readrnx(inputStream, type , obsList, nav, &sta, version, sys, tsys, sysCodeTypes); - } - } - - if(nfil == 0) - { - std::cout << "No valid Nav. files" << std::endl; - exit(0); - } - - FILE* sp3fp=fopen(outfile.c_str(),"wt"); - if(!sp3fp) - { - std::cout << "Cannot open output file: " << outfile << std::endl; - exit(0); - } - std::cout << "Output file: " << outfile << std::endl; - - GTime tstart = GTime::noTime(); - GTime tfinsh = GTime::noTime(); - - for(auto& [satint,ephlist] : nav.ephMap) - { - SatSys sat; - sat.fromHash(satint); - if(!GNSS_on[sat.sys]) continue; - int neph = 0; - for(auto it = nav.ephMap[satint].begin(); it != nav.ephMap[satint].end();) - { - auto [dummy, eph] = *it; - double dtoc = eph.toe - eph.toc; - double dttm = eph.toe - eph.ttm; - bool alert = false; - - if (dtoc !=0.0) alert = true; - if (fabs(dttm)>10000.0) alert = true; - if (eph.svh == SVH_UNHEALTHY) alert = true; - - if(sys == +E_Sys::GAL && !(eph.code & GALSelection)) alert=true; /* INAVs messages, change from 5 to 2 for FNAVs (we dont want to mix the two) */ - - if(alert) - { - it=nav.ephMap[satint].erase(it); - } - else - { - neph++; - if (tstart == GTime::noTime() || tstart > eph.toe) tstart = eph.toe; - if (tfinsh == GTime::noTime() || tfinsh < eph.toe) tfinsh = eph.toe; - it++; - } - } - if(neph>0) - BS_Satel_List[sat]=neph; - } - - if(GNSS_on[E_Sys::GLO]) for(auto& [satint,gephlist] : nav.gephMap) - { - SatSys sat; - sat.fromHash(satint); - int neph = 0; - for(auto it = nav.gephMap[satint].begin(); it != nav.gephMap[satint].end();){ - auto& [dummy, geph] = *it; - double dtoc = geph.toe - geph.tof; - bool alert = false; - - //if(dtoc !=0.0) alert=true; - //if(fabs(dttm)>10000.0) alert=true; - if (geph.svh == SVH_UNHEALTHY) alert = true; - - if(alert){ - it = nav.gephMap[satint].erase(it); - continue; - } - //fprintf(stdout, "%s %s %d, %.1f, %d\n", sat.id().c_str(), geph.toe.to_string(0).c_str(), geph.iode, dtoc, geph.svh); - - neph++; - if (tstart == GTime::noTime() || tstart > geph.toe ) tstart = geph.toe; - if (tfinsh == GTime::noTime() || tfinsh < geph.toe ) tfinsh = geph.toe; - it++; - } - - if (neph > 0) - BS_Satel_List[sat] = neph; - } - - double StarTow = time2gpst(tstart, &BS_Start_Week); - //BS_Start_TOW = BS_Epoch_Inter*floor(StarTow/BS_Epoch_Inter); - BS_Start_TOW = 3600.0 * floor(StarTow / 3600.0); - GTime tsync = gpst2time(BS_Start_Week, BS_Start_TOW); - BS_Epoch_Num = (int)(floor((tfinsh - tsync)/BS_Epoch_Inter) + 1); - time2epoch(tsync, BS_Start_Epoc); - - fprintf(stdout, "\nTstart= %s, Tini= %s, Nepoc=%d\n", tstart.to_string(0).c_str(), tsync.to_string(0).c_str(), BS_Epoch_Num); - - median_check(tstart, tfinsh, BS_Satel_List ); - - if(fstreq)for(auto it = BS_Satel_List.begin(); it != BS_Satel_List.end();) - { - SatSys sat = it->first; - bool nofst = false; - Vector3d rs(0, 0, 0); - Vector3d dant(0, 0, 0); - double dts; - if(sat.sys == +E_Sys::GLO) - { - Geph* gephp=BS_selgeph( tsync, sat, -1, nav); - if(!gephp) nofst = true; - else if(BS_geph2pos( tsync, gephp, rs, &dts) < 0) nofst = true; - else if(rs.norm() < RE_WGS84) nofst = true; - else if(BS_satantoff( tsync, sat, rs, dant, gephp->frq ) < 0) nofst = true; - else nofst = false; - } - else - { - Eph* ephp=BS_seleph( tsync, sat, -1, nav); - if(!ephp) nofst = true; - else if(BS_eph2pos( tsync, ephp, rs, &dts) < 0) nofst = true; - else if(rs.norm() < RE_WGS84) nofst = true; - else if(BS_satantoff( tsync, sat, rs, dant, 0 ) < 0) nofst = true; - else nofst = false; - } - - if(nofst){ - it = BS_Satel_List.erase(it); - } - else{ - ++it; - } - } - - print_SP3header(sp3fp); - - for(int epc=0; epc> temp_eph; - for(auto& [sat,neph] : BS_Satel_List){ - Vector3d rs(0, 0, 0); - Vector3d dant(0, 0, 0); - double dts; - - if(sat.sys == +E_Sys::GLO){ - Geph* gephp=BS_selgeph( tsync, sat, -1, nav, ephopt); - if(!gephp) continue; - if(BS_geph2pos( tsync, gephp, rs, &dts) < 0) continue; - if(rs.norm() < RE_WGS84) continue; - if(BS_satantoff( tsync, sat, rs, dant, gephp->frq ) < 0) continue; - fprintf(stdout, " %s ", sat.id().c_str()); - } - else{ - Eph* ephp=BS_seleph( tsync, sat, -1, nav, ephopt); - if(!ephp) continue; - if(BS_eph2pos( tsync, ephp, rs, &dts) < 0) continue; - if(rs.norm() < RE_WGS84) continue; - if(BS_satantoff( tsync, sat, rs, dant, 0 ) < 0) continue; - fprintf(stdout, " %s ", sat.id().c_str()); - } - - vector sateph; - sateph.push_back(rs(0) - dant(0)); - sateph.push_back(rs(1) - dant(1)); - sateph.push_back(rs(2) - dant(2)); - sateph.push_back(dts); - - //fprintf(stdout, "\n%s %11.6f %11.6f %11.6f", sat.id().c_str(), dant(0),dant(1),dant(2)); - - temp_eph[sat] = sateph; - } - - if (temp_eph.size() > 0) - print_SP3epoch(sp3fp, tsync, temp_eph); - - tsync = tsync + BS_Epoch_Inter; - } - - fprintf(sp3fp, "\nEOF"); - fprintf( stdout,"\n"); - return(EXIT_SUCCESS); -} diff --git a/src/cpp/common/acsConfig.cpp b/src/cpp/common/acsConfig.cpp index 8346477c9..c1b1cf84f 100644 --- a/src/cpp/common/acsConfig.cpp +++ b/src/cpp/common/acsConfig.cpp @@ -6,9 +6,11 @@ #include #include #include +#include #include using std::stringstream; +using std::lock_guard; using std::unique_ptr; using std::multimap; using std::string; @@ -27,6 +29,7 @@ using std::map; #include "peaCommitVersion.h" #include "constants.hpp" #include "acsConfig.hpp" +#include "debug.hpp" ACSConfig acsConfig = {}; @@ -100,8 +103,9 @@ void tryAddRootToPath( string& root, ///< Root path string& path) ///< Filename to prepend root path to { - if (path.empty()) { return; } - if (root == "./") { return; } + if (path.empty()) { return; } + if (root == "./") { return; } + if (path.find(':') != string::npos) { return; } if (root[0] == '~') { @@ -121,7 +125,7 @@ void tryAddRootToPath( } if (root.back() != '/') { - root = root + '/'; + root += '/'; } path = root + path; @@ -139,6 +143,103 @@ void tryAddRootToPath( } } +bool checkGlob( + string str1, + string str2) +{ + vector tokens; + + std::stringstream strstream(str1); + string bit; + while (getline(strstream, bit, '*')) + { + tokens.push_back(bit); + } + + bool first = true; + int start = 0; + for (auto& token : tokens) + { + auto pos = str2.find(token, start); + + if ( first + &&pos != 0) + { + return false; + } + else if (pos == string::npos) + { + return false; + } + + start = pos + token.size(); + first = false; + } + + if (tokens.back() == "") + { + return true; + } + + int strlen = str2.size(); + if (start != strlen) + { + return false; + } + return true; +} + +void globber( + vector& files) +{ + vector newFiles; + + for (auto& fileName : files) + { + if (fileName.find('*') == string::npos) + { + newFiles.push_back(fileName); + continue; + } + + boost::filesystem::path filePath(fileName); + boost::filesystem::path searchDir = filePath.parent_path(); + string searchGlob = filePath.filename().string(); + + if (boost::filesystem::is_directory(searchDir) == false) + { + BOOST_LOG_TRIVIAL(error) + << "Error: Invalid input directory " + << searchDir; + + continue; + } + + vector globFiles; + + for (auto dir_file : boost::filesystem::directory_iterator(searchDir)) + { + // Skip if not a file + if (boost::filesystem::is_regular_file(dir_file) == false) + continue; + + string dir_fileName = dir_file.path().filename().string(); + + if (checkGlob(searchGlob, dir_fileName)) + { + globFiles.push_back(dir_file.path().string()); + } + } + + std::sort(globFiles.begin(), globFiles.end()); + + newFiles.insert(newFiles.end(), globFiles.begin(), globFiles.end()); + } + + + files = newFiles; +} + void tryPatchPaths( string& rootDir, string& fileDir, @@ -154,20 +255,20 @@ void tryPatchPaths( void dumpConfig( Trace& trace) { - trace << "+FILE/RAW_CONFIG" << std::endl; + for (auto& filename : acsConfig.configFilenames) + { + Block block(trace, (string)"FILE/RAW_CONFIG " + filename); - std::ifstream config(acsConfig.configFilename); + std::ifstream config(filename); - string str; - while (std::getline(config, str)) - { - trace << str << std::endl; + string str; + while (std::getline(config, str)) + { + trace << str << std::endl; + } } - - trace << "-FILE/RAW_CONFIG" << std::endl; } - string stringify( string value) { @@ -178,9 +279,10 @@ template string stringify( TYPE value) { - string output; - output += std::to_string(value); - return output; + std::stringstream ss; + ss << std::boolalpha << value; + + return ss.str(); } template @@ -286,7 +388,8 @@ void outputDefaultSiblings( //do this one, and bump the iterator { auto& [stack, defaultVals] = *it; - auto& [defaultVal, comment] = defaultVals; + auto& defaultVal = defaultVals.defaultValue; + auto& comment = defaultVals.comment; it++; @@ -366,8 +469,8 @@ void outputDefaultSiblings( { html << std::endl << htmlIndentor++ << ""; @@ -453,43 +556,50 @@ bool configure( // Do not set default values here, as this will overide the configuration file opitions!!! desc.add_options() - ("help,h", "Help") - ("quiet,q", "Less output") - ("verbose,v", "More output") - ("very-verbose,V", "Much more output") - ("yaml-defaults,Y", "Print complete set of parsed parameters and their default values, and generate configurator.html for visual editing of yaml files") - ("config,y", boost::program_options::value(), "Configuration file") - ("config_description,d", boost::program_options::value(), "Configuration description") - ("trace_level,l", boost::program_options::value(), "Trace level") - ("fatal_message_level,L", boost::program_options::value(), "Fatal error level") - ("elevation_mask,e", boost::program_options::value(), "Elevation Mask") - ("max_epochs,n", boost::program_options::value(), "Maximum Epochs") - ("epoch_interval,i", boost::program_options::value(), "Epoch Interval") - ("user,u", boost::program_options::value(), "Username for RTCM streams") - ("pass,p", boost::program_options::value(), "Password for RTCM streams") - ("atx_files", boost::program_options::value(), "ANTEX file") - ("nav_files", boost::program_options::value(), "Navigation file") - ("snx_files", boost::program_options::value(), "SINEX files") - ("sp3_files", boost::program_options::value(), "Orbit (SP3) files") - ("clk_files", boost::program_options::value(), "Clock (CLK) files") - ("dcb_files", boost::program_options::value(), "Code Bias (DCB) files") - ("bsx_files", boost::program_options::value(), "Bias Sinex (BSX) files") - ("ion_files", boost::program_options::value(), "Ionosphere (IONEX) files") - ("pod_files", boost::program_options::value(), "Orbits (POD) files") - ("blq_files", boost::program_options::value(), "BLQ (Ocean loading) files") - ("erp_files", boost::program_options::value(), "ERP files") - ("rnx_files", boost::program_options::value(), "RINEX station files") - ("rtcm_files", boost::program_options::value(), "RTCM station files") - ("egm_files", boost::program_options::value(), "Earth gravity model coefficients file") -// ("jpl_files", boost::program_options::value(), "JPL planetary and lunar ephemerides file") - ("root_input_directory", boost::program_options::value(), "Directory containg the input data") - ("root_output_directory", boost::program_options::value(), "Output directory") - ("start_epoch", boost::program_options::value(), "Start date/time") - ("end_epoch", boost::program_options::value(), "Stop date/time") - ("run_rts_only", boost::program_options::value(), "RTS filename (without _xxxxx suffix)") - ("dump-config-only", "Dump the configuration and exit") - ("input_persistance", "Begin with previously stored filter and navigation states") - ("output_persistance", "Store filter and navigation states for restarting") + + ("help,h", "Help") + ("quiet,q", "Less output") + ("verbose,v", "More output") + ("very-verbose,V", "Much more output") + ("yaml-defaults,Y", "Print complete set of parsed parameters and their default values, and generate configurator.html for visual editing of yaml files") + ("config_description,d", boost::program_options::value(), "Configuration description") + ("level,l", boost::program_options::value(), "Trace level") + ("fatal_message_level,L", boost::program_options::value(), "Fatal error level") + ("elevation_mask,e", boost::program_options::value(), "Elevation Mask") + ("max_epochs,n", boost::program_options::value(), "Maximum Epochs") + ("epoch_interval,i", boost::program_options::value(), "Epoch Interval") + ("user,u", boost::program_options::value(), "Username for RTCM streams") + ("pass,p", boost::program_options::value(), "Password for RTCM streams") + ("config,y", boost::program_options::value>()->multitoken(), "Configuration file") + ("atx_files", boost::program_options::value>()->multitoken(), "ANTEX files") + ("nav_files", boost::program_options::value>()->multitoken(), "Navigation files") + ("snx_files", boost::program_options::value>()->multitoken(), "SINEX files") + ("sp3_files", boost::program_options::value>()->multitoken(), "Orbit (SP3) files") + ("clk_files", boost::program_options::value>()->multitoken(), "Clock (CLK) files") + ("obx_files", boost::program_options::value>()->multitoken(), "ORBEX (OBX) files") + ("dcb_files", boost::program_options::value>()->multitoken(), "Code Bias (DCB) files") + ("bsx_files", boost::program_options::value>()->multitoken(), "Bias Sinex (BSX) files") + ("ion_files", boost::program_options::value>()->multitoken(), "Ionosphere (IONEX) files") + ("igrf_files", boost::program_options::value>()->multitoken(), "Geomagnetic field coefficients (IGRF) file") + ("orb_files", boost::program_options::value>()->multitoken(), "Orbits (POD) files") + ("blq_files", boost::program_options::value>()->multitoken(), "BLQ (Ocean loading) files") + ("erp_files", boost::program_options::value>()->multitoken(), "ERP files") + ("rnx_inputs,r", boost::program_options::value>()->multitoken(), "RINEX station inputs") + ("ubx_inputs", boost::program_options::value>()->multitoken(), "UBX station inputs") + ("rtcm_inputs", boost::program_options::value>()->multitoken(), "RTCM station inputs") + ("egm_files", boost::program_options::value>()->multitoken(), "Earth gravity model coefficients file") + ("crd_files", boost::program_options::value>()->multitoken(), "SLR CRD file") +// ("slr_inputs", boost::program_options::value>()->multitoken(), "Tabular SLR OBS station file") + ("jpl_files", boost::program_options::value>()->multitoken(), "JPL planetary and lunar ephemerides file") +// ("root_input_directory", boost::program_options::value(), "Directory containg the input data") +// ("root_output_directory", boost::program_options::value(), "Output directory") + ("start_epoch", boost::program_options::value(), "Start date/time") + ("end_epoch", boost::program_options::value(), "Stop date/time") +// ("run_rts_only", boost::program_options::value(), "RTS filename (without _xxxxx suffix)") + ("dump-config-only", "Dump the configuration and exit") +// ("input_persistance", "Begin with previously stored filter and navigation states") +// ("output_persistance", "Store filter and navigation states for restarting") + ("walkthrough", "Run demonstration code interactively with commentary") ; boost::program_options::variables_map vm; @@ -506,6 +616,12 @@ bool configure( exit(EXIT_SUCCESS); } + + if (vm.count("walkthrough")) + { + walkthrough(); + exit(EXIT_SUCCESS); + } if (vm.count("very-verbose")) { boost::log::core::get()->set_filter (boost::log::trivial::severity >= boost::log::trivial::debug); } if (vm.count("verbose")) { boost::log::core::get()->set_filter (boost::log::trivial::severity >= boost::log::trivial::info); } @@ -513,21 +629,23 @@ bool configure( if (vm.count("yaml-defaults")) { - acsConfig.parse("", vm); + acsConfig.parse({""}, vm); exit(EXIT_SUCCESS); } if (vm.count("config")) { - string config = vm["config"].as(); + vector configs = vm["config"].as>(); - bool pass = acsConfig.parse(config, vm); + globber(configs); + + bool pass = acsConfig.parse(configs, vm); if (!pass) { BOOST_LOG_TRIVIAL(error) - << "Error: Configuration from " << config << " aborted"; + << "Error: Configuration aborted"; return false; } @@ -542,15 +660,21 @@ bool configure( valid &= checkValidFiles(acsConfig.nav_files, "navfiles"); valid &= checkValidFiles(acsConfig.sp3_files, "orbit"); valid &= checkValidFiles(acsConfig.clk_files, "clock file (CLK file)"); + valid &= checkValidFiles(acsConfig.obx_files, "orbex file (OBX file)"); valid &= checkValidFiles(acsConfig.blq_files, "ocean loading information (Blq file)"); valid &= checkValidFiles(acsConfig.erp_files, "earth rotation parameter file (ERP file)"); valid &= checkValidFiles(acsConfig.dcb_files, "code Biases file (DCB file)"); valid &= checkValidFiles(acsConfig.bsx_files, "bias Sinex file (BSX file)"); valid &= checkValidFiles(acsConfig.ion_files, "Ionosphere (IONEX file)"); + valid &= checkValidFiles(acsConfig.igrf_files, "geomagnetic field coefficients (IGRF file)"); valid &= checkValidFiles(acsConfig.atx_files, "antenna information (ANTEX file)"); valid &= checkValidFiles(acsConfig.orb_files, "orbit determination (pod file)"); valid &= checkValidFiles(acsConfig.egm_files, "Earth gravity model coefficients (egm file)"); valid &= checkValidFiles(acsConfig.jpl_files, "JPL planetary and lunar ephemerides (jpl file)"); + valid &= checkValidFiles(acsConfig.tide_files, "Ocean tide file FES (tide file)"); + valid &= checkValidFiles(acsConfig.sid_files, "satellite ID list"); + valid &= checkValidFiles(acsConfig.com_files, "centre-of-mass (com file)"); + valid &= checkValidFiles(acsConfig.crd_files, "SLR observation files (crd file)"); valid &= checkValidFile (acsConfig.model.trop.gpt2grid, "grid"); if (acsConfig.snx_files.empty()) @@ -580,51 +704,64 @@ void ACSConfig::info( ss << "Configuration...\n"; ss << "===============================\n"; ss << "Inputs:\n"; - ss << "\tnav_files: "; for (auto& a : nav_files) ss << a << " "; ss << "\n"; - ss << "\tsnx_files: "; for (auto& a : snx_files) ss << a << " "; ss << "\n"; - ss << "\tatx_files: "; for (auto& a : atx_files) ss << a << " "; ss << "\n"; - ss << "\tdcb_files: "; for (auto& a : dcb_files) ss << a << " "; ss << "\n"; - ss << "\tclk_files: "; for (auto& a : clk_files) ss << a << " "; ss << "\n"; - ss << "\tbsx_files: "; for (auto& a : bsx_files) ss << a << " "; ss << "\n"; - ss << "\tion_files: "; for (auto& a : ion_files) ss << a << " "; ss << "\n"; - ss << "\tblq_files: "; for (auto& a : blq_files) ss << a << " "; ss << "\n"; - ss << "\terp_files: "; for (auto& a : erp_files) ss << a << " "; ss << "\n"; - ss << "\tsp3_files: "; for (auto& a : sp3_files) ss << a << " "; ss << "\n"; - ss << "\torb_files: "; for (auto& a : orb_files) ss << a << " "; ss << "\n"; - ss << "\tegm_files: "; for (auto& a : egm_files) ss << a << " "; ss << "\n"; -// ss << "\tjpl_files: "; for (auto& a : jpl_files) ss << a << " "; ss << "\n"; - ss << "\trnx_files: "; for (auto& a : rnx_files) ss << a << " "; ss << "\n"; - ss << "\trtcm_files: "; for (auto& a : obs_rtcm_files) ss << a << " "; ss << "\n"; - ss << "\tvmf3dir: " << model.trop.vmf3dir << "\n"; - ss << "\torography: " << model.trop.orography << "\n"; - ss << "\tgrid: " << model.trop.gpt2grid << "\n"; - ss << "\ttestfiles: " << test_filename << "\n"; - ss << "\n"; + if (!nav_files .empty()) { ss << "\tnav_files: "; for (auto& a : nav_files) ss << a << " "; ss << "\n"; } + if (!snx_files .empty()) { ss << "\tsnx_files: "; for (auto& a : snx_files) ss << a << " "; ss << "\n"; } + if (!atx_files .empty()) { ss << "\tatx_files: "; for (auto& a : atx_files) ss << a << " "; ss << "\n"; } + if (!dcb_files .empty()) { ss << "\tdcb_files: "; for (auto& a : dcb_files) ss << a << " "; ss << "\n"; } + if (!clk_files .empty()) { ss << "\tclk_files: "; for (auto& a : clk_files) ss << a << " "; ss << "\n"; } + if (!bsx_files .empty()) { ss << "\tbsx_files: "; for (auto& a : bsx_files) ss << a << " "; ss << "\n"; } + if (!ion_files .empty()) { ss << "\tion_files: "; for (auto& a : ion_files) ss << a << " "; ss << "\n"; } + if (!igrf_files .empty()) { ss << "\tigrf_files: "; for (auto& a : igrf_files) ss << a << " "; ss << "\n"; } + if (!blq_files .empty()) { ss << "\tblq_files: "; for (auto& a : blq_files) ss << a << " "; ss << "\n"; } + if (!erp_files .empty()) { ss << "\terp_files: "; for (auto& a : erp_files) ss << a << " "; ss << "\n"; } + if (!sp3_files .empty()) { ss << "\tsp3_files: "; for (auto& a : sp3_files) ss << a << " "; ss << "\n"; } + if (!obx_files .empty()) { ss << "\tobx_files: "; for (auto& a : obx_files) ss << a << " "; ss << "\n"; } + if (!orb_files .empty()) { ss << "\torb_files: "; for (auto& a : orb_files) ss << a << " "; ss << "\n"; } + if (!egm_files .empty()) { ss << "\tegm_files: "; for (auto& a : egm_files) ss << a << " "; ss << "\n"; } + if (!jpl_files .empty()) { ss << "\tjpl_files: "; for (auto& a : jpl_files) ss << a << " "; ss << "\n"; } + if (!tide_files .empty()) { ss << "\ttide_files: "; for (auto& a : tide_files) ss << a << " "; ss << "\n"; } + if (!sid_files .empty()) { ss << "\tsid_files: "; for (auto& a : sid_files) ss << a << " "; ss << "\n"; } + if (!vmf_files .empty()) { ss << "\tvmf_files: "; for (auto& a : vmf_files) ss << a << " "; ss << "\n"; } + if (!com_files .empty()) { ss << "\tcom_files: "; for (auto& a : com_files) ss << a << " "; ss << "\n"; } + if (!crd_files .empty()) { ss << "\tcrd_files: "; for (auto& a : crd_files) ss << a << " "; ss << "\n"; } + if (!rnx_inputs .empty()) { ss << "\trnx_inputs: "; for (auto& a : rnx_inputs) ss << a << " "; ss << "\n"; } + if (!pseudo_sp3_inputs .empty()) { ss << "\tsp3_inputs: "; for (auto& a : pseudo_sp3_inputs) ss << a << " "; ss << "\n"; } + if (!pseudo_snx_inputs .empty()) { ss << "\tsnx_inputs: "; for (auto& a : pseudo_snx_inputs) ss << a << " "; ss << "\n"; } + if (!obs_rtcm_inputs .empty()) { ss << "\trtcm_inputs: "; for (auto& a : obs_rtcm_inputs) ss << a << " "; ss << "\n"; } + if (!nav_rtcm_inputs .empty()) { ss << "\trtcm_inputs: "; for (auto& a : nav_rtcm_inputs) ss << a << " "; ss << "\n"; } + + if (!model.trop.orography .empty()) ss << "\torography: " << model.trop.orography << "\n"; + if (!model.trop.gpt2grid .empty()) ss << "\tgrid: " << model.trop.gpt2grid << "\n"; + if (!test_filename .empty()) ss << "\ttestfiles: " << test_filename << "\n"; + ss << "\n"; ss << "Outputs:\n"; - if (1) { ss << "\ttrace level: " << trace_level << "\n"; } - if (output_station_trace) { ss << "\tstation trace filename: " << station_trace_filename << "\n"; } - if (output_network_trace) { ss << "\tnetwork trace filename: " << network_trace_filename << "\n"; } - if (output_clocks) { ss << "\tclocks filename: " << clocks_filename << "\n"; } - if (output_ionex) { ss << "\tionex filename: " << ionex_filename << "\n"; } - if (output_ionstec) { ss << "\tionstec filename: " << ionstec_filename << "\n"; } - if (output_bias_sinex) { ss << "\tbias sinex filename: " << bias_sinex_filename << "\n"; } - if (output_trop_sinex) { ss << "\ttrop sinex filename: " << trop_sinex_filename << "\n"; } - if (output_gpx) { ss << "\tgpx filename: " << gpx_filename << "\n"; } - if (output_decoded_rtcm_json) { ss << "\tdecoded rtcm json filename: " << decoded_rtcm_json_filename << "\n"; } - if (output_encoded_rtcm_json) { ss << "\tencoded rtcm json filename: " << encoded_rtcm_json_filename << "\n"; } + if (1) { ss << "\ttrace level: " << trace_level << "\n"; } + if (output_satellite_trace) { ss << "\tsatellite trace filename: " << satellite_trace_filename << "\n"; } + if (output_station_trace) { ss << "\tstation trace filename: " << station_trace_filename << "\n"; } + if (output_json_trace) { ss << "\tjson trace filename: " << station_trace_filename << "\n"; } + if (output_network_trace) { ss << "\tnetwork trace filename: " << network_trace_filename << "\n"; } + if (output_clocks) { ss << "\tclocks filename: " << clocks_filename << "\n"; } + if (output_ionex) { ss << "\tionex filename: " << ionex_filename << "\n"; } + if (output_ionstec) { ss << "\tionstec filename: " << ionstec_filename << "\n"; } + if (output_bias_sinex) { ss << "\tbias sinex filename: " << bias_sinex_filename << "\n"; } + if (output_cost) { ss << "\tcost filename: " << cost_filename << "\n"; } + if (output_trop_sinex) { ss << "\ttrop sinex filename: " << trop_sinex_filename << "\n"; } + if (output_gpx) { ss << "\tgpx filename: " << gpx_filename << "\n"; } + if (output_decoded_rtcm_json) { ss << "\tdecoded rtcm json filename: " << decoded_rtcm_json_filename << "\n"; } + if (output_encoded_rtcm_json) { ss << "\tencoded rtcm json filename: " << encoded_rtcm_json_filename << "\n"; } ss << "\n"; ss << "Process Modes:\n"; ss << "\tPreprocessor: " << process_preprocessor << "\n"; + ss << "\tSPP " << process_spp << "\n"; ss << "\tUser: " << process_user << "\n"; ss << "\tNetwork: " << process_network << "\n"; ss << "\tMinimum Constraints: " << process_minimum_constraints << "\n"; ss << "\tIonospheric: " << process_ionosphere << "\n"; ss << "\tRTS Smoothing: " << process_rts << "\n"; ss << "\tPPP: " << process_ppp << "\n"; - ss << "\tOrbits: " << process_orbits << "\n"; ss << "\n"; ss << "Systems:\n"; @@ -632,8 +769,10 @@ void ACSConfig::info( ss << "\tGLONASS: " << process_sys[E_Sys::GLO] << "\n"; ss << "\tGALILEO: " << process_sys[E_Sys::GAL] << "\n"; ss << "\tBEIDOU: " << process_sys[E_Sys::BDS] << "\n"; + ss << "\tQZSS: " << process_sys[E_Sys::QZS] << "\n"; + ss << "\tLEO: " << process_sys[E_Sys::LEO] << "\n"; ss << "\n"; - + ss << "Elevation_mask: " << elevation_mask * R2D << "\n"; ss << "\n"; @@ -643,18 +782,37 @@ void ACSConfig::info( if (!start_epoch .is_not_a_date_time()) { ss << "\tepoch start: " << start_epoch << "\n"; } if (!end_epoch .is_not_a_date_time()) { ss << "\tepoch end: " << end_epoch << "\n"; } - ss << "\n"; - ss << "Stations:\n"; - for (auto& filename : station_files) - { - ss << "\t" << root_stations_dir << filename << "\n"; - } - ss << "\n"; ss << "===============================\n"; ss << "...End Configuration\n"; ss << "===============================\n"; ss << "\n"; + + if (process_user) BOOST_LOG_TRIVIAL(warning) << "Warning: 'process_modes: user:' is being deprecated. Consider using ppp mode instead"; + if (process_network) BOOST_LOG_TRIVIAL(warning) << "Warning: 'process_modes: network:' is being deprecated. Consider using ppp mode instead"; +} + +void addAvailableOptions( + string stack) +{ + auto& available = acsConfig.availableOptions[nonNumericStack(stack)]; + + if (available) + { + //already recursed this bit + return; + } + + available = true; + + auto pos = stack.find_last_of(':', stack.size() - 2); + + if (pos == string::npos) + { + return; + } + + addAvailableOptions(stack.substr(0, pos + 1)); } /** Get an object within a hierarchy of yaml structure using a vector of nodes. @@ -678,24 +836,36 @@ NodeStack stringsToYamlObject( for (int i = 0; i < yamlNodeDescriptor.size(); i++) { auto& desc = yamlNodeDescriptor[i]; + + if (desc.empty()) + { + continue; + } string shortDesc = nonNumericStack(desc, false); + bool test = false; + if (currentNode[shortDesc]) + test = true; + currentNode.reset(currentNode[shortDesc]); stack += desc + ":"; +// string test = currentNode.Scalar(); + if (acsConfig.yamlDefaults.find(stack) == acsConfig.yamlDefaults.end()) { if (i == yamlNodeDescriptor.size() - 1) acsConfig.yamlDefaults[stack] = {defaultValue, comment}; else acsConfig.yamlDefaults[stack] = {"", ""}; + acsConfig.yamlDefaults[stack].found = test; } } + addAvailableOptions(stack); + return {currentNode, stack}; } - - /** Set an output from yaml object if found */ template @@ -707,11 +877,17 @@ bool trySetFromYaml( { auto [optNode, stack] = stringsToYamlObject(yamlBase, yamlNodeDescriptor, comment, stringify(output)); - acsConfig.availableOptions[nonNumericStack(stack)] = true; + addAvailableOptions(stack); + auto& yamlDefault = acsConfig.yamlDefaults[stack]; try { + yamlDefault.foundValue = yamlDefault.defaultValue; + output = optNode.template as(); + + yamlDefault.foundValue = stringify(output); + yamlDefault.found = true; return true; } catch (...) @@ -767,18 +943,20 @@ bool trySetFromAny( /** Set an enum from yaml, decoding strings to ints */ template -void trySetEnumOpt( - ENUM& out, ///< Variable to output to - NodeStack yamlBase, ///< Yaml node to search within - vector yamlNodeDescriptor, ///< List of strings of keys to trace hierarcy - ENUM (&_from_string)(const char*), ///< Function to decode enum strings - string comment = "") ///< Description to provide to user for automatic documentation +bool trySetEnumOpt( + ENUM& out, ///< Variable to output to + NodeStack yamlBase, ///< Yaml node to search within + vector yamlNodeDescriptor, ///< List of strings of keys to trace hierarcy + ENUM (&_from_string_nocase)(const char*), ///< Function to decode enum strings + string comment = "") ///< Description to provide to user for automatic documentation { string enumOptions = " {"; + auto names = ENUM::_names(); for (int i = 0; i < ENUM::_size(); i++) { - string enumOption = ENUM::_names() [i]; boost::algorithm::to_lower(enumOption); + string enumOption = boost::algorithm::to_lower_copy((string) names[i]); + if (i != 0) enumOptions += ","; enumOptions += enumOption; @@ -787,7 +965,7 @@ void trySetEnumOpt( auto [optNode, stack] = stringsToYamlObject(yamlBase, yamlNodeDescriptor, comment + enumOptions, out._to_string()); - acsConfig.availableOptions[nonNumericStack(stack)] = true; + addAvailableOptions(stack); string value; try @@ -796,12 +974,14 @@ void trySetEnumOpt( } catch (...) { - return; +// std::cout << stack << " not found\n"; + return false; } try { - out = _from_string(value.c_str()); + out = _from_string_nocase(value.c_str()); + return true; } catch (...) { @@ -817,37 +997,79 @@ void trySetEnumOpt( } } +template +bool trySetEnumVec( + vector& enumVector, + NodeStack yamlBase, ///< Yaml node to search within + vector yamlNodeDescriptor, ///< List of strings of keys to trace hierarcy + string comment = "") ///< Description to provide to user for automatic documentation +{ + vector enumStrings; + bool found = trySetFromYaml(enumStrings, yamlBase, yamlNodeDescriptor, comment); + if (found == false) + return false; + + enumVector.clear(); + + for (auto& enumString : enumStrings) + { + try + { + auto a = ENUM::_from_string_nocase(enumString.c_str()); + enumVector.push_back(a); + } + catch (...) + { + continue; + } + } + + return true; +} + /** Set the variables associated with kalman filter states from yaml */ void trySetKalmanFromYaml( - KalmanModel& output, ///< Variable to output to - NodeStack& yaml, ///< Yaml node to search within - string key, ///< Key of yaml object - string comment = "") ///< Description to provide to user for automatic documentation + KalmanModel& output, ///< Variable to output to + NodeStack& yaml, ///< Yaml node to search within + string key, ///< Key of yaml object + string comment = "", ///< Description to provide to user for automatic documentation + bool skippable = false) ///< Optionally skip this when yaml object not found in file { auto newYaml = stringsToYamlObject(yaml, {key}, comment); + auto& [optNode, stack] = newYaml; + + if ( skippable + && !optNode) + { + return; + } + E_Period proc_noise_dt = E_Period::SECOND; - trySetFromYaml(output.estimate, newYaml, {"0 estimated" }, "[bools] Estimate state in kalman filter"); - trySetEnumOpt(proc_noise_dt, newYaml, {"2 proc_noise_dt" }, E_Period::_from_string_nocase, "(enum) Time unit for process noise - sqrt_sec, sqrt_day etc."); - - trySetFromYaml(output.sigma, newYaml, {"1 sigma" }, "[floats] Apriori sigma values - if zero, will be initialised using least squares"); - trySetFromYaml(output.apriori_val, newYaml, {"3 apriori_val" }, "[floats] Apriori state values"); - bool found = trySetFromYaml(output.proc_noise, newYaml, {"2 proc_noise" }, "[floats] Process noise sigmas"); - bool foundTau = trySetFromYaml(output.tau, newYaml, {"tau" }, "[floats] Correlation times for gauss markov noise, defaults to -1 -> inf (Random Walk)"); - trySetFromYaml(output.mu, newYaml, {"mu" }, "[floats] Desired mean value for gauss markov states"); - if (found) + setInited(output, output.estimate, trySetFromYaml(output.estimate, newYaml, {"0 estimated" }, "[bools] Estimate state in kalman filter")); + trySetEnumOpt(proc_noise_dt, newYaml, {"2 proc_noise_dt" }, E_Period::_from_string_nocase, "(enum) Time unit for process noise - sqrt_sec, sqrt_day etc."); + + setInited(output, output.sigma, trySetFromYaml(output.sigma, newYaml, {"1 sigma" }, "[floats] Apriori sigma values - if zero, will be initialised using least squares")); + setInited(output, output.apriori_val, trySetFromYaml(output.apriori_val, newYaml, {"3 apriori_val" }, "[floats] Apriori state values")); + setInited(output, output.proc_noise, trySetFromYaml(output.proc_noise, newYaml, {"2 proc_noise" }, "[floats] Process noise sigmas")); + setInited(output, output.tau, trySetFromYaml(output.tau, newYaml, {"tau" }, "[floats] Correlation times for gauss markov noise, defaults to -1 -> inf (Random Walk)")); + setInited(output, output.mu, trySetFromYaml(output.mu, newYaml, {"mu" }, "[floats] Desired mean value for gauss markov states")); + setInited(output, output.comment, trySetFromYaml(output.comment, newYaml, {"comment" }, "[strings] Comment to apply to the state")); + + if (isInited(output, output.proc_noise)) { for (auto& proc : output.proc_noise) { proc /= sqrt((int)proc_noise_dt); } } - if (foundTau) + + if (isInited(output, output.tau)) { for (auto& tau : output.tau) { - tau *= proc_noise_dt; + tau *= (int)proc_noise_dt; } } } @@ -855,31 +1077,50 @@ void trySetKalmanFromYaml( /** Set the variables associated with an output stream */ void tryGetStreamFromYaml( - SsrBroadcast& outStreamData, ///< Variable to output to - NodeStack yamlBase, ///< Yaml node to search within - string id) ///< Label associated with the stream + SsrBroadcast& outStreamData, ///< Variable to output to + NodeStack& yaml, ///< Yaml node to search within + string id) ///< Label associated with the stream { - auto outStreamsYaml = stringsToYamlObject(yamlBase, {id}); + auto outStreamsYaml = stringsToYamlObject(yaml, {id}); trySetFromYaml(outStreamData.url, outStreamsYaml, {"0 url"}, "(string) Url of caster to send messages to"); - auto [messagesNode, messagesString] = stringsToYamlObject(outStreamsYaml, {"1 messages"}, "[int] List of message types to output for this stream"); - - for (auto outMessage : messagesNode) + for (auto msgType : RtcmMessageType::_values()) { - try + if (msgType == +RtcmMessageType::IGS_SSR) + for (auto subType : IgsSSRSubtype::_values()) { - int messNum = outMessage.as(); - outStreamData.rtcmMessagesTypes.insert(RtcmMessageType::_from_integral(messNum)); + string str = (boost::format("rtcm_%4d_%03d") % msgType._to_integral() % subType._to_integral()).str(); + + auto msgOptions = stringsToYamlObject(outStreamsYaml, {"0 messages", str}, "(int) Message type to output"); + + bool found = trySetFromYaml(outStreamData.rtcmMsgOptsMap[msgType].igs_udi[subType], msgOptions, {"0 udi"}, "(int) Update interval"); + if (found) + outStreamData.rtcmMsgOptsMap[msgType].udi = 1; } - catch (std::exception& e) + + else if (msgType == +RtcmMessageType::COMPACT_SSR) + for (auto subType : CompactSSRSubtype::_values()) { - BOOST_LOG_TRIVIAL(error) << "Error defining output stream message for label : " << id; - continue; + string str = (boost::format("rtcm_%4d_%02d") % msgType._to_integral() % subType._to_integral()).str(); + + auto msgOptions = stringsToYamlObject(outStreamsYaml, {"0 messages", str}, "(int) Message type to output"); + + bool found = trySetFromYaml(outStreamData.rtcmMsgOptsMap[msgType].comp_udi[subType], msgOptions, {"0 udi"}, "(int) Update interval"); + if (found) + outStreamData.rtcmMsgOptsMap[msgType].udi = 1; + } + + else + { + string str = "rtcm_" + std::to_string(msgType); + + auto msgOptions = stringsToYamlObject(outStreamsYaml, {"0 messages", str}, "(int) Message type to output"); + + trySetFromYaml(outStreamData.rtcmMsgOptsMap[msgType].udi, msgOptions, {"0 udi"}, "(int) Update interval"); } } - trySetFromYaml(outStreamData.update_interval, outStreamsYaml, {"2 update_interval" }); trySetFromYaml(outStreamData.message_timeout, outStreamsYaml, {"message_timeout" }); trySetFromYaml(outStreamData.itrf_datum, outStreamsYaml, {"itrf_datum" }); trySetFromYaml(outStreamData.provider_id, outStreamsYaml, {"provider_id" }); @@ -898,21 +1139,37 @@ void getFromYaml( trySetKalmanFromYaml(satOpts.clk, satNode, "clk", "Clocks"); trySetKalmanFromYaml(satOpts.clk_rate, satNode, "clk_rate", "Clock rates"); - trySetKalmanFromYaml(satOpts.clk_rate_gauss_markov, satNode, "clk_rate_gauss_markov", "Clock rates (gauss markov dynamics)"); trySetKalmanFromYaml(satOpts.pos, satNode, "pos", "Position (experimental, use orb)"); trySetKalmanFromYaml(satOpts.pos_rate, satNode, "pos_rate", "Velocity (experimental, use orb)"); trySetKalmanFromYaml(satOpts.orb, satNode, "orb", "Orbit corrections"); trySetKalmanFromYaml(satOpts.srp, satNode, "srp", "Solar radiation pressure (experimental, use orb)"); trySetKalmanFromYaml(satOpts.pco, satNode, "pco", "Phase Center Offsets (experimental)"); trySetKalmanFromYaml(satOpts.ant, satNode, "ant", "Antenna offsets (experimental)"); + trySetKalmanFromYaml(satOpts.orbit, satNode, "orbit", "Orbital state"); + trySetKalmanFromYaml(satOpts.ion_model, satNode, "ion_model", "Ionosphere models"); trySetKalmanFromYaml(satOpts.code_bias, satNode, "code_bias", "Code bias (experimental)"); trySetKalmanFromYaml(satOpts.phase_bias, satNode, "phase_bias", "Phase bias (experiemental)"); - - trySetFromYaml(satOpts.exclude, satNode, {"0 exclude"}); + trySetKalmanFromYaml(satOpts.emp_dyb_0, satNode, "emp_dyb_0", "emp bias "); + trySetKalmanFromYaml(satOpts.emp_dyb_1c, satNode, "emp_dyb_1c", "emp 1 per rev cosine term "); + trySetKalmanFromYaml(satOpts.emp_dyb_1s, satNode, "emp_dyb_1s", "emp 1 per rev sine term "); + trySetKalmanFromYaml(satOpts.emp_dyb_2c, satNode, "emp_dyb_2c", "emp 2 per rev cosine term "); + trySetKalmanFromYaml(satOpts.emp_dyb_2s, satNode, "emp_dyb_2s", "emp 2 per rev sine term "); + trySetKalmanFromYaml(satOpts.emp_dyb_3c, satNode, "emp_dyb_3c", "emp 3 per rev cosine term "); + trySetKalmanFromYaml(satOpts.emp_dyb_3s, satNode, "emp_dyb_3s", "emp 3 per rev sine term "); + trySetKalmanFromYaml(satOpts.emp_dyb_4c, satNode, "emp_dyb_4c", "emp 4 per rev cosine term "); + trySetKalmanFromYaml(satOpts.emp_dyb_4s, satNode, "emp_dyb_4s", "emp 4 per rev sine term "); + + setInited(satOpts, satOpts.exclude, trySetFromYaml(satOpts.exclude, satNode, {"0 exclude"})); + setInited(satOpts, satOpts.code_sigmas, trySetFromYaml(satOpts.code_sigmas, satNode, {"0 code_sigmas" }, "[floats] Standard deviation of code measurements")); + setInited(satOpts, satOpts.phas_sigmas, trySetFromYaml(satOpts.phas_sigmas, satNode, {"0 phase_sigmas" }, "[floats] Standard deviation of phase measurmeents")); + setInited(satOpts, satOpts.laser_sigmas, trySetFromYaml(satOpts.laser_sigmas, satNode, {"laser_sigmas" }, "[floats] Standard deviation of SLR laser measurements")); satOpts._initialised = true; } +const string estimation_parameters_str = "4 estimation_parameters"; +const string processing_options_str = "2 processing_options"; + /** Set receiver options from yaml */ void getFromYaml( @@ -924,164 +1181,266 @@ void getFromYaml( trySetKalmanFromYaml(recOpts.clk, recNode, "clk", "Clocks"); trySetKalmanFromYaml(recOpts.clk_rate, recNode, "clk_rate", "Clock rates"); - trySetKalmanFromYaml(recOpts.clk_rate_gauss_markov, recNode, "clk_rate_gauss_markov", "Clock rates (gauss markov dynamics)"); - trySetKalmanFromYaml(recOpts.pos, recNode, "pos", "Position corrections"); + trySetKalmanFromYaml(recOpts.pos, recNode, "pos", "Position"); + trySetKalmanFromYaml(recOpts.heading, recNode, "heading", "Heading"); trySetKalmanFromYaml(recOpts.pos_rate, recNode, "pos_rate", "Velocity"); + trySetKalmanFromYaml(recOpts.orbit, recNode, "orbit", "Orbital state"); + trySetKalmanFromYaml(recOpts.strain_rate, recNode, "strain_rate", "Velocity (large gain, for geodetic timescales)"); trySetKalmanFromYaml(recOpts.amb, recNode, "amb", "Integer phase ambiguities"); trySetKalmanFromYaml(recOpts.pco, recNode, "pco", "Phase Center Offsets (experimental)"); trySetKalmanFromYaml(recOpts.ant, recNode, "ant", "Antenna offsets (experimental)"); trySetKalmanFromYaml(recOpts.code_bias, recNode, "code_bias", "Code bias (experimental)"); trySetKalmanFromYaml(recOpts.phase_bias, recNode, "phase_bias", "Phase bias (experiemental)"); - trySetKalmanFromYaml(recOpts.ion, recNode, "ion", "Ionosphere (experimental)"); + trySetKalmanFromYaml(recOpts.ion_stec, recNode, "ion_stec", "Ionosphere (experimental)"); + trySetKalmanFromYaml(recOpts.slr_range_bias, recNode, "slr_range_bias", "Satellite Laser Ranging range bias"); + trySetKalmanFromYaml(recOpts.slr_time_bias, recNode, "slr_time_bias", "Satellite Laser Ranging time bias"); trySetKalmanFromYaml(recOpts.trop, recNode, "trop", "Troposphere corrections"); trySetKalmanFromYaml(recOpts.trop_grads, recNode, "trop_grads", "Troposphere gradients"); - trySetKalmanFromYaml(recOpts.trop_gauss_markov, recNode, "trop_gauss_markov", "Troposphere corrections (gauss markov dynamics)"); - trySetKalmanFromYaml(recOpts.trop_grads_gauss_markov, recNode, "trop_grads_gauss_markov", "Troposphere gradients (gauss markov dynamics)"); - - trySetFromYaml (recOpts.exclude, recNode, {"1 exclude" }); - trySetEnumOpt (recOpts.error_model, recNode, {"0 error_model" }, E_NoiseModel::_from_string_nocase); - trySetFromYaml (recOpts.code_sigmas, recNode, {"0 code_sigmas" }, "[floats] Standard deviation of code measurements"); - trySetFromYaml (recOpts.phas_sigmas, recNode, {"0 phase_sigmas" }, "[floats] Standard deviation of phase measurmeents"); - recOpts._initialised = true; + setInited(recOpts, recOpts.exclude, trySetFromYaml (recOpts.exclude, recNode, {"1 exclude" })); + setInited(recOpts, recOpts.error_model, trySetEnumOpt (recOpts.error_model, recNode, {"0 error_model" }, E_NoiseModel::_from_string_nocase)); + setInited(recOpts, recOpts.spp_sigma_scaling, trySetFromYaml (recOpts.spp_sigma_scaling, recNode, {"spp_sigma_scaling" }, "(floats) Amount to scale sigmas for SPP")); + setInited(recOpts, recOpts.code_sigmas, trySetFromYaml (recOpts.code_sigmas, recNode, {"0 code_sigmas" }, "[floats] Standard deviation of code measurements")); + setInited(recOpts, recOpts.phas_sigmas, trySetFromYaml (recOpts.phas_sigmas, recNode, {"0 phase_sigmas" }, "[floats] Standard deviation of phase measurmeents")); + setInited(recOpts, recOpts.laser_sigmas, trySetFromYaml (recOpts.laser_sigmas, recNode, {"laser_sigmas" }, "[floats] Standard deviation of SLR laser measurements")); } -const string estimation_parameters_str = "4 estimation_parameters"; -const string processing_options_str = "2 processing_options"; /** Set satellite options for a specific satellite using a hierarchy of sources */ SatelliteOptions& ACSConfig::getSatOpts( - SatSys& Sat) ///< Satellite to search for options for + SatSys Sat, ///< Satellite to search for options for + vector suffixes) ///< Optional suffix to get more specific versions { - auto& satOpts = satOptsMap[Sat.id()]; + lock_guard guard(configMutex); + + string fullId = Sat.id(); + for (auto& suffix : suffixes) + { + fullId += suffix; + } + + auto& satOpts = satOptsMap[fullId]; //return early if possible if (satOpts._initialised) return satOpts; + + satOpts._initialised = true; - //initialise the options for this satellite - auto& blockOpts = satOptsMap[Sat.blockType()]; - if (blockOpts._initialised == false) + vector aliases; + + aliases.push_back(""); + aliases.push_back("global"); + + for (int i = 0; i < yamls.size(); i++) { - //find it's parent - auto& sysOpts = satOptsMap[Sat.sys._to_string()]; - if (sysOpts._initialised == false) + auto& yaml = yamls[i]; + + vector yamlAliases; + trySetFromYaml(yamlAliases, {yaml, ""}, {"satellite_options", Sat.id(), "aliases"}, "[string] Aliases for this satellite"); + + for (auto& alias : yamlAliases) { - //find it's parent - auto& globalOpts = satOptsMap["GLOBAL"]; - if (globalOpts._initialised == false) - { - //get specifics from config file - getFromYaml(globalOpts, {yaml, ""}, {estimation_parameters_str, "0 satellites"}); - globalOpts._initialised = true; - } + aliases.push_back(alias); + } + } + + //add global and this id on either side of the aliases + aliases .push_back(Sat.sysName()); + if (Sat.blockType() .empty() == false) aliases .push_back(Sat.blockType()); + aliases .push_back(Sat.id()); + if (Sat.svn() .empty() == false) aliases .push_back("SVN_" + Sat.svn()); + + for (int i = 0; i < yamls .size(); i++) { auto& yaml = yamls[i]; + for (auto& alias : aliases) + for (int S = 0; S <= suffixes .size(); S++) + { + string aliasName = std::to_string(i) + alias; + + for (int s = 0; s < S; s++) + { + aliasName += suffixes[s]; + } + + auto& aliasOpts = satOptsMap[aliasName]; + + if (aliasOpts._initialised) + { + satOpts += aliasOpts; + continue; + } + + aliasOpts._initialised = true; + + vector descriptorVec = {estimation_parameters_str, "0 satellites", alias}; + for (int s = 0; s < S; s++) + { + descriptorVec.push_back(suffixes[s]); + } + + getFromYaml(aliasOpts, {yaml, ""}, descriptorVec); - if (Sat.sys == +E_Sys::NONE) + if (alias.empty() == false) + { + vector antenna_boresight; + vector antenna_azimuth; + + descriptorVec = {estimation_parameters_str, "satellite_options", alias}; + for (int s = 0; s < S; s++) { - return globalOpts; + descriptorVec.push_back(suffixes[s]); } - //initialise from its parent - sysOpts = globalOpts; - - //get specifics from config file - string sys = "SYS_" + Sat.sysName(); - getFromYaml(sysOpts, {yaml, ""}, {estimation_parameters_str, "overrides", "satellites", sys}); + { auto vec = descriptorVec; vec.push_back("antenna_boresight"); trySetFromYaml (antenna_boresight, {yaml, ""}, vec, "[floats] Antenna boresight (Up) in satellite body-fixed frame"); } + { auto vec = descriptorVec; vec.push_back("antenna_azimuth"); trySetFromYaml (antenna_azimuth, {yaml, ""}, vec, "[floats] Antenna azimuth (North) in satellite body-fixed frame"); } + + if (antenna_boresight .size() == 3) { aliasOpts.antenna_boresight = Vector3d(antenna_boresight.data()); setInited(aliasOpts, aliasOpts.antenna_boresight); } + if (antenna_azimuth .size() == 3) { aliasOpts.antenna_azimuth = Vector3d(antenna_azimuth .data()); setInited(aliasOpts, aliasOpts.antenna_azimuth); } } - - //initialise from its parent - blockOpts = sysOpts; - - //get specifics from config file - string block = Sat.blockType(); - getFromYaml(blockOpts, {yaml, ""}, {estimation_parameters_str, "overrides", "satellites", block}); - } - - //initialise from its parent - satOpts = blockOpts; - - //get specifics from config file - string prn = Sat.id(); - string svn = "SVN_" + Sat.svn(); - getFromYaml(satOpts, {yaml, ""}, {estimation_parameters_str, "overrides", "satellites", svn}); - getFromYaml(satOpts, {yaml, ""}, {estimation_parameters_str, "overrides", "satellites", prn}); - + + satOpts += aliasOpts; + }} + return satOpts; } /** Set receiver options for a specific receiver using a hierarchy of sources */ ReceiverOptions& ACSConfig::getRecOpts( - string id) ///< Receiver to search for options for + string id, ///< Receiver to search for options for + vector suffixes) ///< Optional suffix to get more specific versions { - auto& recOpts = recOptsMap[id]; - - //return early if possible - if (recOpts._initialised) - return recOpts; + lock_guard guard(configMutex); - //initialise the options for this receiver - auto& globalOpts = recOptsMap[""]; - if (globalOpts._initialised == false) + string fullId = id; + for (auto& suffix : suffixes) { - //get specifics from config file - getFromYaml(globalOpts, {yaml, ""}, {estimation_parameters_str, "0 stations"}); - globalOpts._initialised = true; + fullId += suffix; } - - //initialise from its parent - recOpts = globalOpts; - - //get specifics from config file - getFromYaml(recOpts, {yaml, ""}, {estimation_parameters_str, "overrides", "stations", id}); - - return recOpts; -} - -/** Set minimum constraint options for a specific receiver using a hierarchy of sources -*/ -MinimumStationOptions& ACSConfig::getMinConOpts( - string id) ///< Receiver to search for options for -{ - auto& recOpts = minCOpts.stationMap[id]; + + auto& recOpts = recOptsMap[fullId]; //return early if possible if (recOpts._initialised) return recOpts; + + recOpts._initialised = true; - //initialise the options for this receiver - auto& globalOpts = minCOpts.stationMap[""]; - if (globalOpts._initialised == false) + vector aliases; + + aliases.push_back(""); + aliases.push_back("global"); + + for (int i = 0; i < yamls.size(); i++) { - //get specifics from config file - trySetFromYaml(globalOpts.noise, {yaml, ""}, {processing_options_str, "minimum_constraints", "default_station_noise"}, "(float) Sigma applied to all stations for weighting in transformation estimation. (Lower is stronger weighting, Negative is unweighted)"); - globalOpts._initialised = true; + auto& yaml = yamls[i]; + + vector yamlAliases; + trySetFromYaml(yamlAliases, {yaml, ""}, {"station_options", id, "aliases"}, "[string] Aliases for this station"); + + for (auto& alias : yamlAliases) + { + aliases.push_back(alias); + } } + + //add global and this id on either side of the aliases + aliases.push_back(id); - //initialise from its parent - recOpts = globalOpts; - - //get specifics from config file - trySetFromYaml(recOpts.noise, {yaml, ""}, {processing_options_str, "minimum_constraints", "station_noise", id}, "(float) Override sigma to adjust weighting of transformation estimation"); - - return recOpts; -} - -/** Set and scale a variable according to yaml options -*/ -template + for (int i = 0; i < yamls .size(); i++) { auto& yaml = yamls[i]; + for (auto& alias : aliases) + for (int S = 0; S <= suffixes .size(); S++) + { + string aliasName = std::to_string(i) + alias; + + for (int s = 0; s < S; s++) + { + aliasName += suffixes[s]; + } + + auto& aliasOpts = recOptsMap[aliasName]; + + if (aliasOpts._initialised) + { + recOpts += aliasOpts; + continue; + } + + aliasOpts._initialised = true; + + vector descriptorVec = {estimation_parameters_str, "0 stations", alias}; + for (int s = 0; s < S; s++) + { + descriptorVec.push_back(suffixes[s]); + } + + getFromYaml(aliasOpts, {yaml, ""}, descriptorVec); + + if (alias.empty() == false) + { + vector eccentricity; + vector apriori_pos; + vector antenna_boresight; + vector antenna_azimuth; + + setInited(aliasOpts, aliasOpts.minConNoise, trySetFromYaml(aliasOpts.minConNoise, {yaml, ""}, {processing_options_str, "minimum_constraints", "station_noise", alias}, "(float) Sigma applied to all stations for weighting in transformation estimation. (Lower is stronger weighting, Negative is unweighted, in ENU frame)")); + + descriptorVec = {"station_options", alias}; + for (int s = 0; s < S; s++) + { + descriptorVec.push_back(suffixes[s]); + } + + { auto vec = descriptorVec; vec.push_back("receiver_type"); setInited(aliasOpts, aliasOpts.receiver_type, trySetFromYaml (aliasOpts.receiver_type, {yaml, ""}, vec, "(string) ")); } + { auto vec = descriptorVec; vec.push_back("antenna_type"); setInited(aliasOpts, aliasOpts.antenna_type, trySetFromYaml (aliasOpts.antenna_type, {yaml, ""}, vec, "(string) Antenna type and radome in 20 character string as per sinex")); } + { auto vec = descriptorVec; vec.push_back("eccentricity"); trySetFromYaml (eccentricity, {yaml, ""}, vec, "[floats] Antenna offset in ENU frame");} + { auto vec = descriptorVec; vec.push_back("apriori_position"); trySetFromYaml (apriori_pos, {yaml, ""}, vec, "[floats] Apriori position in XYZ ECEF frame");} + { auto vec = descriptorVec; vec.push_back("antenna_boresight"); trySetFromYaml (antenna_boresight, {yaml, ""}, vec, "[floats] Antenna boresight (Up) in receiver body-fixed frame");} + { auto vec = descriptorVec; vec.push_back("antenna_azimuth"); trySetFromYaml (antenna_azimuth, {yaml, ""}, vec, "[floats] Antenna azimuth (North) in receiver body-fixed frame");} + + if (eccentricity .size() == 3) { aliasOpts.eccentricity = Vector3d(eccentricity .data()); setInited(aliasOpts, aliasOpts.eccentricity); } + if (apriori_pos .size() == 3) { aliasOpts.apriori_pos = Vector3d(apriori_pos .data()); setInited(aliasOpts, aliasOpts.apriori_pos); } + if (antenna_boresight .size() == 3) { aliasOpts.antenna_boresight = Vector3d(antenna_boresight.data()); setInited(aliasOpts, aliasOpts.antenna_boresight); } + if (antenna_azimuth .size() == 3) { aliasOpts.antenna_azimuth = Vector3d(antenna_azimuth .data()); setInited(aliasOpts, aliasOpts.antenna_azimuth); } + + for (int i = E_Sys::GPS; E_Sys::_values()[i] < +E_Sys::SUPPORTED; i++) + for (E_ObsCode2 obsCode2 : E_ObsCode2::_values()) + { + E_Sys sys = E_Sys::_values()[i]; + + auto& rinex3Code = aliasOpts.rinex23Conv.codeConv[sys][obsCode2]; + auto& rinex3Phas = aliasOpts.rinex23Conv.phasConv[sys][obsCode2]; + + string sysName = boost::algorithm::to_lower_copy((string) sys._to_string()); + + { auto vec = descriptorVec; vec.push_back("rnx_code_conversions"); trySetEnumOpt(rinex3Code, stringsToYamlObject( {yaml, ""}, vec), {sysName, obsCode2._to_string()}, E_ObsCode::_from_string_nocase);} + { auto vec = descriptorVec; vec.push_back("rnx_phase_conversions"); trySetEnumOpt(rinex3Phas, stringsToYamlObject( {yaml, ""}, vec), {sysName, obsCode2._to_string()}, E_ObsCode::_from_string_nocase);} + } + } + + recOpts += aliasOpts; + }} + + return recOpts; +} + +/** Set and scale a variable according to yaml options +*/ +template void trySetScaledFromYaml( - double& output, ///< Variable to output to - NodeStack node, ///< Yaml node to search within - vector number_parameter, ///< List of keys of the hierarchy to the value to be set - vector scale_parameter, ///< List of keys of the hierarchy to the scale to be applied - ENUM (&_from_string)(const char*)) ///< Function to decode scale enum strings + double& output, ///< Variable to output to + NodeStack node, ///< Yaml node to search within + vector number_parameter, ///< List of keys of the hierarchy to the value to be set + vector scale_parameter, ///< List of keys of the hierarchy to the scale to be applied + ENUM (&_from_string_nocase)(const char*)) ///< Function to decode scale enum strings { - double number = 0; + double number = output; ENUM number_units = ENUM::_from_integral(1); - trySetFromYaml(number, node, number_parameter); - trySetEnumOpt(number_units, node, scale_parameter, _from_string); - number *= number_units; + + trySetFromYaml (number, node, number_parameter); + trySetEnumOpt (number_units, node, scale_parameter, _from_string_nocase); + + number *= (int)number_units; if (number != 0) { output = number; @@ -1107,7 +1466,10 @@ bool replaceString( && warn) { BOOST_LOG_TRIVIAL(warning) - << "Warning: " << subStr << " is used in config but is not defined"; + << "Warning: " << subStr << " is used in config but is not defined, clearing..."; + + str.clear(); + return true; } str.erase (index, subStr.size()); @@ -1120,16 +1482,18 @@ bool replaceString( } /** Replace macros for times with configured values. -* Available replacements are " " +* Available replacements are " " */ void replaceTags( string& str) ///< String to replace macros within { - replaceString(str, "", acsConfig.config_description); - replaceString(str, "", acsConfig.stream_user); - replaceString(str, "", acsConfig.stream_pass); - replaceString(str, "", GINAN_BRANCH_NAME); - replaceString(str, "", GINAN_COMMIT_HASH); + replaceString(str, "", acsConfig.config_description); + replaceString(str, "", acsConfig.stream_user); + replaceString(str, "", acsConfig.stream_pass); + replaceString(str, "", GINAN_BRANCH_NAME); + replaceString(str, "", GINAN_COMMIT_HASH); + replaceString(str, "", acsConfig.analysis_agency); + replaceString(str, "", acsConfig.analysis_program.substr(0,3)); } /** Replace macros for times with numeric values. @@ -1218,94 +1582,10 @@ void replaceTimes( } } -bool checkGlob( - string str1, - string str2) -{ - vector tokens; - - std::stringstream strstream(str1); - string bit; - while (getline(strstream, bit, '*')) - { - tokens.push_back(bit); - } - - bool first = true; - int start = 0; - for (auto& token : tokens) - { - auto pos = str2.find(token, start); - - if ( first - &&pos != 0) - { - return false; - } - else if (pos == string::npos) - { - return false; - } - - start = pos + token.size(); - first = false; - } - - int strlen = str2.size(); - if (start != strlen) - { - return false; - } - return true; -} - -void globber( - vector& files) -{ - vector newFiles; - - for (auto& fileName : files) - { - if ( fileName.find('*') != string::npos) - { - boost::filesystem::path filePath(fileName); - boost::filesystem::path searchDir = filePath.parent_path(); - string searchGlob = filePath.filename().string(); - - if (boost::filesystem::is_directory(searchDir) == false) - { - BOOST_LOG_TRIVIAL(error) - << "Error: Invalid input directory " - << searchDir; - - continue; - } - - for (auto dir_file : boost::filesystem::directory_iterator(searchDir)) - { - // Skip if not a file - if (boost::filesystem::is_regular_file(dir_file) == false) - continue; - - string dir_fileName = dir_file.path().filename().string(); - - if (checkGlob(searchGlob, dir_fileName)) - { - newFiles.push_back(dir_file.path().string()); - } - } - } - else - { - newFiles.push_back(fileName); - } - } - files = newFiles; -} - void ACSConfig::recurseYaml( YAML::Node node, - string stack) + string stack, + string aliasStack) { for (YAML::const_iterator it = node.begin(); it != node.end(); it++) { @@ -1313,418 +1593,554 @@ void ACSConfig::recurseYaml( // std::cout << key << std::endl; - string newStack = stack + key + ":"; - - if (newStack == "estimation_parameters:overrides:") continue; - if (newStack == "processing_options:minimum_constraints:station_noise:") continue; - if (newStack == "outputs:streams:") continue; + string newStack = stack + key + ":"; + string newAliasStack = aliasStack + key + ":"; - if (node[key].IsMap() == false) + if (availableOptions.find(newAliasStack) == availableOptions.end()) { - if (availableOptions.find(newStack) != availableOptions.end()) + if ( (stack == "estimation_parameters:stations:") + ||(stack == "estimation_parameters:satellites:") + ||(stack == "processing_options:minimum_constraints:station_noise:") + ||(stack == "outputs:streams:") + ||(stack == "station_options:")) { -// BOOST_LOG_TRIVIAL(debug) -// << newStack << " is a valid yaml option"; - + newAliasStack = stack + "global" + ":"; + + if (availableOptions.find(newAliasStack) == availableOptions.end()) + { + BOOST_LOG_TRIVIAL(warning) + << "Warning: " << newStack << " is not a valid yaml option"; + + continue; + } + } + else + { + BOOST_LOG_TRIVIAL(warning) + << "Warning: " << newStack << " is not a valid yaml option"; + continue; } - - BOOST_LOG_TRIVIAL(warning) - << "Warning: " << newStack << " is not a valid yaml option"; - - continue; } - - recurseYaml(node[key], newStack); + +// BOOST_LOG_TRIVIAL(debug) +// << newStack << " is a valid yaml option"; + + if (node[key].IsMap()) + { + recurseYaml(node[key], newStack, newAliasStack); + } } } bool ACSConfig::parse() { - return parse(configFilename, commandOpts); + return parse(configFilenames, commandOpts); } /** Parse options to set acsConfig values. * Command line options will override any values set in config files, which will themselves override any program default values. */ bool ACSConfig::parse( - string filename, ///< Path to yaml based config file + vector filenames, ///< Path to yaml based config file boost::program_options::variables_map& newCommandOpts) ///< Variable map object of command line options { - configFilename = filename; + configFilenames = filenames; + + bool modified = false; + for (auto& filename : filenames) if (filename != "") { boost::filesystem::path filePath(filename); auto currentConfigModifyTime = boost::filesystem::last_write_time(filePath); - if (currentConfigModifyTime == configModifyTimeMap["CONFIG"]) + if (currentConfigModifyTime != configModifyTimeMap[filename]) { - return false; + modified = true; } - - configModifyTimeMap["CONFIG"] = currentConfigModifyTime; + + configModifyTimeMap[filename] = currentConfigModifyTime; + } + else + { + modified = true; + } + + if (modified == false) + { + return false; } - commandOpts = newCommandOpts; - BOOST_LOG_TRIVIAL(info) - << "Loading configuration from file " << filename; //clear old saved parameters satOptsMap.clear(); recOptsMap.clear(); defaultOutputOptions(); - for (int i = 1; i < E_Sys::SUPPORTED; i++) + for (int i = E_Sys::GPS; i < E_Sys::SUPPORTED; i++) { E_Sys sys = E_Sys::_values()[i]; code_priorities[sys] = code_priorities_default; } - try - { - yaml.reset(); - yaml = YAML::LoadFile(filename); - } - catch (const YAML::BadFile &e) - { - if (commandOpts.count("yaml-defaults")) - { - //we expect to break, continue parsing - } - else - { - BOOST_LOG_TRIVIAL(error) << "Error: \nFailed to parse configuration file " << filename; - BOOST_LOG_TRIVIAL(error) << e.msg << std::endl; - return false; - } - } - catch (const YAML::ParserException& e) - { - BOOST_LOG_TRIVIAL(error) << "Error: \nFailed to parse configuration. Check for errors as described near the below:\n"; - BOOST_LOG_TRIVIAL(error) << e.what() << std::endl << std::endl; - return false; - } + yamls.resize(filenames.size()); - string root_output_directory = "./"; + string root_output_directory = "./"; + string root_input_directory = "./"; + + for (int i = 0; i < filenames.size(); i++) { - auto outputs = stringsToYamlObject({yaml, ""}, {"1 outputs"}, "Configuration for types of files to output"); - - trySetFromYaml(root_output_directory, outputs, {"0 root_directory" }); - - { - auto metadata = stringsToYamlObject(outputs, {"metadata"}); - - trySetFromAny (config_description, commandOpts, metadata, {"config_description" }, "(string) ID for this config, used to replace tags in other options"); - trySetFromAny (stream_user, commandOpts, metadata, {"user" }, "(string) Username for connecting to NTRIP casters"); - trySetFromAny (stream_pass, commandOpts, metadata, {"pass" }, "(string) Password for connecting to NTRIP casters"); - trySetFromYaml(analysis_agency, metadata, {"analysis_agency" }); - trySetFromYaml(analysis_center, metadata, {"analysis_center" }); - trySetFromYaml(analysis_program, metadata, {"analysis_program" }); - trySetFromYaml(rinex_comment, metadata, {"rinex_comment" }); - trySetFromYaml(reference_system, metadata, {"reference_system" }, "(string) Terrestrial Reference System Code"); - trySetFromYaml(time_system, metadata, {"time_system" }, "(string) Time system - e.g. \"G\", \"UTC\""); - trySetFromYaml(ocean_tide_loading_model, metadata, {"ocean_tide_loading_model" }, "(string) Ocean tide loading model applied"); - trySetFromYaml(atmospheric_tide_loading_model, metadata, {"atmospheric_tide_loading_model" }, "(string) Atmospheric tide loading model applied"); - trySetFromYaml(geoid_model, metadata, {"geoid_model" }, "(string) Geoid model name for undulation values"); - trySetFromYaml(gradient_mapping_function, metadata, {"gradient_mapping_function" }, "(string) Name of mapping function used for mapping horizontal troposphere gradients"); - } - - { - auto trace = stringsToYamlObject(outputs, {"0 trace"}); - - trySetFromYaml(output_station_trace, trace, {"0 output_stations" }, "(bool) "); - trySetFromYaml(output_network_trace, trace, {"0 output_network" }, "(bool) "); - trySetFromYaml(trace_directory, trace, {"directory" }); - trySetFromYaml(station_trace_filename, trace, {"1 station_filename" }); - trySetFromYaml(network_trace_filename, trace, {"1 network_filename" }); - trySetFromAny(trace_level, commandOpts, trace, {"level" }, "(int) Threshold level for printing messages (0-5)"); - - trySetFromYaml(output_residual_chain, trace, {"output_residual_chain" }, "(bool) "); - trySetFromYaml(output_residuals, trace, {"output_residuals" }, "(bool) "); - trySetFromYaml(output_config, trace, {"output_config" }, "(bool) "); - } - - { - auto output_rotation = stringsToYamlObject(outputs, {"output_rotation"}); - - trySetScaledFromYaml(rotate_period, output_rotation, {"period" }, {"period_units" }, E_Period::_from_string_nocase); - } - - { - auto bias_sinex = stringsToYamlObject(outputs, {"bias_sinex"}); - - trySetFromYaml(output_bias_sinex, bias_sinex, {"0 output" }, "(bool) "); - trySetFromYaml(bias_sinex_directory, bias_sinex, {"directory" }); - trySetFromYaml(bias_sinex_filename, bias_sinex, {"filename" }); - trySetFromYaml(ambrOpts.biasOutrate, bias_sinex, {"output_interval" }); - } - - { - auto clocks = stringsToYamlObject(outputs, {"clocks"}); - - trySetFromYaml(output_clocks, clocks, {"0 output" }, "(bool) "); - trySetFromYaml(clocks_directory, clocks, {"directory" }); - trySetFromYaml(clocks_filename, clocks, {"filename" }); - trySetFromYaml(output_ar_clocks, clocks, {"output_ar_clocks" }, "(bool) "); - trySetEnumOpt(clocks_receiver_source, clocks, {"receiver_source" }, E_Ephemeris::_from_string_nocase); - trySetEnumOpt(clocks_satellite_source, clocks, {"satellite_source" }, E_Ephemeris::_from_string_nocase); - } - - { - auto decoded_rtcm = stringsToYamlObject(outputs, {"decoded_rtcm"}); - - trySetFromYaml(output_decoded_rtcm_json, decoded_rtcm, {"0 output" }, "(bool) Enable exporting decoded RTCM data to file"); - trySetFromYaml(decoded_rtcm_json_directory, decoded_rtcm, {"directory" }, "(string) Directory to export decoded RTCM data"); - trySetFromYaml(decoded_rtcm_json_filename, decoded_rtcm, {"filename" }, "(string) Decoded RTCM data filename"); - - } - - { - auto encoded_rtcm = stringsToYamlObject(outputs, {"encoded_rtcm"}); - - trySetFromYaml(output_encoded_rtcm_json, encoded_rtcm, {"0 output" }, "(bool) Enable exporting encoded RTCM data to file"); - trySetFromYaml(encoded_rtcm_json_directory, encoded_rtcm, {"directory" }, "(string) Directory to export encoded RTCM data"); - trySetFromYaml(encoded_rtcm_json_filename, encoded_rtcm, {"filename" }, "(string) Encoded RTCM data filename"); - } - - { - auto erp = stringsToYamlObject(outputs, {"erp"}); - - trySetFromYaml(output_erp, erp, {"0 output" }, "(bool) "); - trySetFromYaml(erp_directory, erp, {"directory" }); - trySetFromYaml(erp_filename, erp, {"filename" }); - } - - { - auto ionex = stringsToYamlObject(outputs, {"ionex"}); - - trySetFromYaml(output_ionex, ionex, {"0 output" }, "(bool) "); - trySetFromYaml(ionex_directory, ionex, {"directory" }); - trySetFromYaml(ionex_filename, ionex, {"filename" }); - trySetFromYaml(ionexGrid.lat_center, ionex, {"grid", "lat_center" }); - trySetFromYaml(ionexGrid.lon_center, ionex, {"grid", "lon_center" }); - trySetFromYaml(ionexGrid.lat_width, ionex, {"grid", "lat_width" }); - trySetFromYaml(ionexGrid.lon_width, ionex, {"grid", "lon_width" }); - trySetFromYaml(ionexGrid.lat_res, ionex, {"grid", "lat_resolution" }); - trySetFromYaml(ionexGrid.lon_res, ionex, {"grid", "lon_resolution" }); - trySetFromYaml(ionexGrid.time_res, ionex, {"grid", "time_resolution" }); - - } - - { - auto ionstec = stringsToYamlObject(outputs, {"ionstec"}); - - trySetFromYaml(output_ionstec, ionstec, {"0 output" }, "(bool) "); - trySetFromYaml(ionstec_directory, ionstec, {"directory" }); - trySetFromYaml(ionstec_filename, ionstec, {"filename" }); - } - - { - auto sinex = stringsToYamlObject(outputs, {"sinex"}); - - trySetFromYaml(output_sinex, sinex, {"0 output" }, "(bool) "); - trySetFromYaml(sinex_directory, sinex, {"directory" }); - trySetFromYaml(sinex_filename, sinex, {"filename" }); - } - - { - auto log = stringsToYamlObject(outputs, {"log"}); //todo - - trySetFromYaml(output_log, log, {"0 output" }, "(bool) "); - trySetFromYaml(log_directory, log, {"directory" }); - trySetFromYaml(log_filename, log, {"filename" }); - } - - { - auto gpx = stringsToYamlObject(outputs, {"gpx"}); - - trySetFromYaml(output_gpx, gpx, {"0 output" }, "(bool) "); - trySetFromYaml(gpx_directory, gpx, {"directory" }); - trySetFromYaml(gpx_filename, gpx, {"filename" }); - } - - { - auto network_statistics = stringsToYamlObject(outputs, {"network_statistics"}); - - trySetFromYaml(output_network_statistics_json, network_statistics, {"0 output" }, "(bool) Enable exporting network statistics data to file"); - trySetFromYaml(network_statistics_json_directory, network_statistics, {"directory" }, "(string) Directory to export network statistics data"); - trySetFromYaml(network_statistics_json_filename, network_statistics, {"filename" }, "(string) Network statistics data filename"); - } - - { - auto sp3 = stringsToYamlObject(outputs, {"sp3"}); - //sp3 - trySetFromYaml(output_orbits, sp3, {"0 output" }, "(bool) "); - trySetFromYaml(output_orbit_velocities, sp3, {"output_velocities" }, "(bool) "); - trySetFromYaml(orbits_directory, sp3, {"directory" }); - trySetFromYaml(orbits_filename, sp3, {"filename" }); - trySetEnumOpt(orbits_data_source, sp3, {"data_source" },E_Ephemeris::_from_string_nocase); - } - - { - auto ppp_sol = stringsToYamlObject(outputs, {"ppp_sol"}); - - trySetFromYaml(output_ppp_sol, ppp_sol, {"0 output" }, "(bool) "); - trySetFromYaml(ppp_sol_directory, ppp_sol, {"directory" }); - trySetFromYaml(ppp_sol_filename, ppp_sol, {"filename" }); - } - - { - auto rinex_nav = stringsToYamlObject(outputs, {"rinex_nav"}); - - trySetFromYaml(output_rinex_nav, rinex_nav, {"0 output" }, "(bool) "); - trySetFromYaml(rinex_nav_directory, rinex_nav, {"directory" }); - trySetFromYaml(rinex_nav_filename, rinex_nav, {"filename" }); - trySetFromYaml(rinex_nav_version, rinex_nav, {"version" }); - } - - { - auto rinex_obs = stringsToYamlObject(outputs, {"rinex_obs"}); - - trySetFromYaml(output_rinex_obs, rinex_obs, {"0 output" }, "(bool) "); - trySetFromYaml(rinex_obs_directory, rinex_obs, {"directory" }); - trySetFromYaml(rinex_obs_print_C_code, rinex_obs, {"output_pseudorange" }, "(bool) "); - trySetFromYaml(rinex_obs_print_L_code, rinex_obs, {"output_phase_range" }, "(bool) "); - trySetFromYaml(rinex_obs_print_D_code, rinex_obs, {"output_doppler" }, "(bool) "); - trySetFromYaml(rinex_obs_print_S_code, rinex_obs, {"output_signal_to_noise" }, "(bool) "); - trySetFromYaml(rinex_obs_filename, rinex_obs, {"filename" }); - trySetFromYaml(rinex_obs_version, rinex_obs, {"version" }); - } - + auto& filename = filenames [i]; + auto& yaml = yamls [i]; + + BOOST_LOG_TRIVIAL(info) + << "Loading configuration from file " << filename; + + try { - auto rtcm_nav = stringsToYamlObject(outputs, {"rtcm_nav"}); - - trySetFromYaml(record_rtcm_nav, rtcm_nav, {"0 output" }, "(bool) "); - trySetFromYaml(rtcm_nav_directory, rtcm_nav, {"directory" }); - trySetFromYaml(rtcm_nav_filename, rtcm_nav, {"filename" }); + yaml.reset(); + yaml = YAML::LoadFile(filename); } - + catch (const YAML::BadFile &e) { - auto rtcm_obs = stringsToYamlObject(outputs, {"rtcm_obs"}); - - trySetFromYaml(record_rtcm_obs, rtcm_obs, {"0 output" }, "(bool) "); - trySetFromYaml(rtcm_obs_directory, rtcm_obs, {"directory" }); - trySetFromYaml(rtcm_obs_filename, rtcm_obs, {"filename" }); + if (commandOpts.count("yaml-defaults")) + { + //we expect to break, continue parsing + } + else + { + BOOST_LOG_TRIVIAL(error) << "Error: \nFailed to parse configuration file " << filename; + BOOST_LOG_TRIVIAL(error) << e.msg << std::endl; + return false; + } } - - + catch (const YAML::ParserException& e) { - auto trop_sinex = stringsToYamlObject(outputs, {"trop_sinex"}); - - trySetFromYaml(output_trop_sinex, trop_sinex, {"0 output" }, "(bool) Enable data exporting to troposphere SINEX file"); - trySetEnumOpt( trop_data_source, trop_sinex, {"source" }, E_Ephemeris::_from_string_nocase, "(enum) Source for troposphere delay data - KALMAN, etc."); - trySetFromYaml(trop_sinex_directory, trop_sinex, {"directory" }, "(string) Directory to export troposphere SINEX file"); - trySetFromYaml(trop_sinex_filename, trop_sinex, {"filename" }, "(string) Troposphere SINEX filename"); + BOOST_LOG_TRIVIAL(error) << "Error: \nFailed to parse configuration. Check for errors as described near the below:\n"; + BOOST_LOG_TRIVIAL(error) << e.what() << std::endl << std::endl; + return false; } - + + { - auto streams = stringsToYamlObject(outputs, {"streams"}); - - string root_stream_url = ""; - trySetFromYaml(root_stream_url, streams, {"0 root_url"}, "(string) Root url to be prepended to all other streams specified in this section. If the streams used have individually specified root urls, usernames, or passwords, this should not be used."); - - replaceTags(root_stream_url); + auto outputs = stringsToYamlObject({yaml, ""}, {"1 outputs"}, "Configuration for types of files to output"); + + trySetFromYaml(root_output_directory, outputs, {"0 root_directory" }); - SsrBroadcast dummyStreamData; - tryGetStreamFromYaml(dummyStreamData, streams, {"XMPL"}); - - auto [outStreamNode, outStreamString] = stringsToYamlObject(streams, {"1 labels"}, "[string] List of output stream is with further information to be found in its own section, as per XMPL below"); - - for (auto outLabelYaml : outStreamNode) { - SsrBroadcast outStreamData; - string outLabel = outLabelYaml.as(); - - tryGetStreamFromYaml(outStreamData, streams, {outLabel}); - - tryAddRootToPath(root_stream_url, outStreamData.url); - - uploadingStreamData[outLabel] = outStreamData; + auto metadata = stringsToYamlObject(outputs, {"metadata"}); + + trySetFromAny (config_description, commandOpts, metadata, {"config_description" }, "(string) ID for this config, used to replace tags in other options"); + trySetFromAny (stream_user, commandOpts, metadata, {"user" }, "(string) Username for connecting to NTRIP casters"); + trySetFromAny (stream_pass, commandOpts, metadata, {"pass" }, "(string) Password for connecting to NTRIP casters"); + trySetFromYaml(analysis_agency, metadata, {"analysis_agency" }); + trySetFromYaml(analysis_center, metadata, {"analysis_center" }); + trySetFromYaml(ac_contact, metadata, {"ac_contact" }); + trySetFromYaml(analysis_program, metadata, {"analysis_program" }); + trySetFromYaml(analysis_program_version, metadata, {"analysis_program_version" }); + trySetFromYaml(rinex_comment, metadata, {"rinex_comment" }); + trySetFromYaml(reference_system, metadata, {"reference_system" }, "(string) Terrestrial Reference System Code"); + trySetFromYaml(time_system, metadata, {"time_system" }, "(string) Time system - e.g. \"G\", \"UTC\""); + trySetFromYaml(bias_time_system, metadata, {"bias_time_system" }, "(string) Time system for bias SINEX \"G\", \"UTC\""); + trySetFromYaml(ocean_tide_loading_model, metadata, {"ocean_tide_loading_model" }, "(string) Ocean tide loading model applied"); + trySetFromYaml(atmospheric_tide_loading_model, metadata, {"atmospheric_tide_loading_model" }, "(string) Atmospheric tide loading model applied"); + trySetFromYaml(geoid_model, metadata, {"geoid_model" }, "(string) Geoid model name for undulation values"); + trySetFromYaml(gradient_mapping_function, metadata, {"gradient_mapping_function" }, "(string) Name of mapping function used for mapping horizontal troposphere gradients"); } - } - } - - string root_input_directory = "./"; - string ephemeris_data_root_url; - string gnss_data_root_url; - vector gnssDataStreams; - vector ephemerisDataStreams; - { - auto inputs = stringsToYamlObject({yaml, ""}, {"0 inputs"}); - - string root_stream_url; - trySetFromAny(root_input_directory, commandOpts, inputs, {"0 root_directory" }, "(string) Root path to be added to all other input files (unless they are absolute)"); - trySetFromYaml(root_stream_url, inputs, {"0 root_stream_url" }, "(string) Root url to be prepended to all other streams specified in this section. If the streams used have individually specified root urls, usernames, or passwords, this should not be used."); - - trySetFromAny(atx_files, commandOpts, inputs, {"atx_files" }, "[string] List of atx files to use"); - trySetFromAny(snx_files, commandOpts, inputs, {"snx_files" }, "[string] List of snx files to use"); - trySetFromAny(blq_files, commandOpts, inputs, {"blq_files" }, "[string] List of blq files to use"); - trySetFromAny(erp_files, commandOpts, inputs, {"erp_files" }, "[string] List of erp files to use"); - trySetFromAny(ion_files, commandOpts, inputs, {"ion_files" }, "[string] List of ion files to use"); - trySetFromAny(egm_files, commandOpts, inputs, {"egm_files" }, "[string] List of egm files to use"); -// trySetFromAny(jpl_files, commandOpts, inputs, {"jpl_files" }, "[string] List of jpl files to use"); - - trySetFromYaml(model.trop.vmf3dir, inputs, {"troposphere", "vmf3_directory" }); - trySetFromYaml(model.trop.orography, inputs, {"troposphere", "orography_files" }); - trySetFromYaml(model.trop.gpt2grid, inputs, {"troposphere", "gpt2grid_files" }); - { - auto gnss_data = stringsToYamlObject(inputs, {"1 gnss_observations"}); + { + auto trace = stringsToYamlObject(outputs, {"0 trace"}); + + trySetFromYaml(output_station_trace, trace, {"0 output_stations" }, "(bool) "); + trySetFromYaml(output_network_trace, trace, {"0 output_network" }, "(bool) "); + trySetFromYaml(output_satellite_trace, trace, {"0 output_satellites" }, "(bool) "); + trySetFromYaml(trace_directory, trace, {"directory" }); + trySetFromYaml(satellite_trace_filename, trace, {"1 satellite_filename" }); + trySetFromYaml(station_trace_filename, trace, {"1 station_filename" }); + trySetFromYaml(network_trace_filename, trace, {"1 network_filename" }); + trySetFromAny(trace_level, commandOpts, trace, {"level" }, "(int) Threshold level for printing messages (0-5)"); + + trySetFromYaml(output_residual_chain, trace, {"output_residual_chain" }, "(bool) "); + trySetFromYaml(output_residuals, trace, {"output_residuals" }, "(bool) "); + trySetFromYaml(output_config, trace, {"output_config" }, "(bool) "); + trySetFromYaml(output_json_trace, trace, {"output_json" }, "(bool) "); + } - trySetFromAny(rnx_files, commandOpts, gnss_data, {"rnx_files" }, "[string] List of rinex files to use"); - trySetFromAny(obs_rtcm_files, commandOpts, gnss_data, {"rtcm_files" }, "[string] List of rtcmfiles files to use for observations"); //todo - - trySetFromYaml(gnssDataStreams, gnss_data, {"streams" }); - - string root_gnss_directory = "./"; - trySetFromAny(root_gnss_directory, commandOpts, gnss_data, {"0 root_directory" }, "(string) Root path to be added to all other gnss data files (unless they are absolute)"); - trySetFromYaml(gnss_data_root_url, gnss_data, {"0 root_stream_url" }); + { + auto output_rotation = stringsToYamlObject(outputs, {"output_rotation"}); + + trySetScaledFromYaml(rotate_period, output_rotation, {"period" }, {"period_units" }, E_Period::_from_string_nocase); + } + + { + auto bias_sinex = stringsToYamlObject(outputs, {"bias_sinex"}); + + trySetFromYaml(output_bias_sinex, bias_sinex, {"0 output" }, "(bool) "); + trySetFromYaml(bias_sinex_directory, bias_sinex, {"directory" }); + trySetFromYaml(bias_sinex_filename, bias_sinex, {"filename" }); + trySetFromYaml(ambrOpts.code_output_interval, bias_sinex, {"code_output_interval" }, "(double) Update interval for code biases"); + trySetFromYaml(ambrOpts.phase_output_interval, bias_sinex, {"phase_output_interval" }, "(double) Update interval for phase biases"); + trySetFromYaml(ambrOpts.output_rec_bias, bias_sinex, {"output_rec_bias" }, "(bool) output receiver biases"); + } + + { + auto clocks = stringsToYamlObject(outputs, {"clocks"}); + + trySetFromYaml(output_clocks, clocks, {"0 output" }, "(bool) "); + trySetFromYaml(clocks_directory, clocks, {"directory" }); + trySetFromYaml(clocks_filename, clocks, {"filename" }); + trySetFromYaml(output_ar_clocks, clocks, {"output_ar_clocks" }, "(bool) "); + trySetEnumVec (clocks_receiver_sources, clocks, {"receiver_sources" }); + trySetEnumVec (clocks_satellite_sources, clocks, {"satellite_sources" }); + } + + { + auto decoded_rtcm = stringsToYamlObject(outputs, {"decoded_rtcm"}); + + trySetFromYaml(output_decoded_rtcm_json, decoded_rtcm, {"0 output" }, "(bool) Enable exporting decoded RTCM data to file"); + trySetFromYaml(decoded_rtcm_json_directory, decoded_rtcm, {"directory" }, "(string) Directory to export decoded RTCM data"); + trySetFromYaml(decoded_rtcm_json_filename, decoded_rtcm, {"filename" }, "(string) Decoded RTCM data filename"); + } + + { + auto encoded_rtcm = stringsToYamlObject(outputs, {"encoded_rtcm"}); + + trySetFromYaml(output_encoded_rtcm_json, encoded_rtcm, {"0 output" }, "(bool) Enable exporting encoded RTCM data to file"); + trySetFromYaml(encoded_rtcm_json_directory, encoded_rtcm, {"directory" }, "(string) Directory to export encoded RTCM data"); + trySetFromYaml(encoded_rtcm_json_filename, encoded_rtcm, {"filename" }, "(string) Encoded RTCM data filename"); + } + + { + auto erp = stringsToYamlObject(outputs, {"erp"}); + + trySetFromYaml(output_erp, erp, {"0 output" }, "(bool) "); + trySetFromYaml(erp_directory, erp, {"directory" }); + trySetFromYaml(erp_filename, erp, {"filename" }); + } + + { + auto ionex = stringsToYamlObject(outputs, {"ionex"}); + + trySetFromYaml(output_ionex, ionex, {"0 output" }, "(bool) "); + trySetFromYaml(ionex_directory, ionex, {"directory" }); + trySetFromYaml(ionex_filename, ionex, {"filename" }); + trySetFromYaml(ionexGrid.lat_center, ionex, {"grid", "lat_center" }); + trySetFromYaml(ionexGrid.lon_center, ionex, {"grid", "lon_center" }); + trySetFromYaml(ionexGrid.lat_width, ionex, {"grid", "lat_width" }); + trySetFromYaml(ionexGrid.lon_width, ionex, {"grid", "lon_width" }); + trySetFromYaml(ionexGrid.lat_res, ionex, {"grid", "lat_resolution" }); + trySetFromYaml(ionexGrid.lon_res, ionex, {"grid", "lon_resolution" }); + trySetFromYaml(ionexGrid.time_res, ionex, {"grid", "time_resolution" }); + } + + { + auto ionstec = stringsToYamlObject(outputs, {"ionstec"}); + + trySetFromYaml(output_ionstec, ionstec, {"0 output" }, "(bool) "); + trySetFromYaml(ionstec_directory, ionstec, {"directory" }); + trySetFromYaml(ionstec_filename, ionstec, {"filename" }); + } + + { + auto sinex = stringsToYamlObject(outputs, {"sinex"}); + + trySetFromYaml(output_sinex, sinex, {"0 output" }, "(bool) "); + trySetFromYaml(sinex_directory, sinex, {"directory" }); + trySetFromYaml(sinex_filename, sinex, {"filename" }); + } + + { + auto log = stringsToYamlObject(outputs, {"log"}); + + trySetFromYaml(output_log, log, {"0 output" }, "(bool) "); + trySetFromYaml(log_directory, log, {"directory" }); + trySetFromYaml(log_filename, log, {"filename" }); + } + + { + auto ntrip_log = stringsToYamlObject(outputs, {"ntrip_log"}); + + trySetFromYaml(output_ntrip_log, ntrip_log, {"0 output" }, "(bool) "); + trySetFromYaml(ntrip_log_directory, ntrip_log, {"directory" }); + trySetFromYaml(ntrip_log_filename, ntrip_log, {"filename" }); + } + + { + auto gpx = stringsToYamlObject(outputs, {"gpx"}); + + trySetFromYaml(output_gpx, gpx, {"0 output" }, "(bool) "); + trySetFromYaml(gpx_directory, gpx, {"directory" }); + trySetFromYaml(gpx_filename, gpx, {"filename" }); + } + + { + auto network_statistics = stringsToYamlObject(outputs, {"network_statistics"}); + + trySetFromYaml(output_network_statistics_json, network_statistics, {"0 output" }, "(bool) Enable exporting network statistics data to file"); + trySetFromYaml(network_statistics_json_directory, network_statistics, {"directory" }, "(string) Directory to export network statistics data"); + trySetFromYaml(network_statistics_json_filename, network_statistics, {"filename" }, "(string) Network statistics data filename"); + } + + { + auto sp3 = stringsToYamlObject(outputs, {"sp3"}); + + trySetFromYaml(output_orbits, sp3, {"0 output" }, "(bool) "); + trySetFromYaml(output_predicted_orbits, sp3, {"0 output_predicted_orbits" }, "(bool) "); + trySetFromYaml(output_orbit_velocities, sp3, {"output_velocities" }, "(bool) "); + trySetFromYaml(orbits_directory, sp3, {"directory" }); + trySetFromYaml(orbits_filename, sp3, {"filename" }); + trySetFromYaml(predicted_orbits_filename, sp3, {"predicted_filename" }); + trySetEnumVec (orbits_data_sources, sp3, {"sources" }); + trySetFromYaml(orbits_output_interval, sp3, {"output_interval" }, "(int) Update interval for sp3 records"); + trySetFromYaml(output_inertial_orbits, sp3, {"output_inertial" }, "(bool) Output the entries using inertial positions and velocities"); + } - tryAddRootToPath(root_gnss_directory, rnx_files); - tryAddRootToPath(root_gnss_directory, obs_rtcm_files); + { + auto orbit_ics = stringsToYamlObject(outputs, {"orbit_ics"}); + + trySetFromYaml(output_orbit_ics, orbit_ics, {"output" }, ""); + trySetFromYaml(orbit_ics_filename, orbit_ics, {"orbit_ics_filename" }, ""); + trySetFromYaml(orbit_ics_directory, orbit_ics, {"orbit_ics_directory" }, ""); + } + + { + auto orbex = stringsToYamlObject(outputs, {"orbex"}); + + trySetFromYaml(output_orbex, orbex, {"0 output" }, "(bool) Output orbex file"); + trySetFromYaml(orbex_directory, orbex, {"directory" }, "(string) Output orbex directory"); + trySetFromYaml(orbex_filename, orbex, {"filename" }, "(string) Output orbex filename"); + trySetEnumVec (orbex_orbit_sources, orbex, {"orbit_sources" }, "[E_Source] Source for orbex orbits"); + trySetEnumVec (orbex_clock_sources, orbex, {"clock_sources" }, "[E_Source] Source for orbex clocks"); + trySetEnumVec (orbex_attitude_sources, orbex, {"attitude_sources" }, "[E_Source] Source for orbex attitudes"); + + vector recordTypeStrings; + bool found = trySetFromYaml(recordTypeStrings, orbex, {"record_types" }, "[string] List of record types to output to ORBEX file"); + if (found) + for (auto once : {1}) + { + orbex_record_types.clear(); + + for (auto& recordTypeString : recordTypeStrings) + { + try + { + orbex_record_types.push_back(recordTypeString); + } + catch (...) + { + continue; + } + } + } + } + + { + auto ppp_sol = stringsToYamlObject(outputs, {"ppp_sol"}); + + trySetFromYaml(output_ppp_sol, ppp_sol, {"0 output" }, "(bool) "); + trySetFromYaml(ppp_sol_directory, ppp_sol, {"directory" }); + trySetFromYaml(ppp_sol_filename, ppp_sol, {"filename" }); + } + + { + auto cost = stringsToYamlObject(outputs, {"cost"}); + + trySetFromYaml(output_cost, cost, {"0 output" }, "(bool) Enable data exporting to troposphere COST file"); + trySetEnumVec (cost_data_sources, cost, {"sources" }, "(enum) Source for troposphere delay data - KALMAN, etc."); + trySetFromYaml(cost_directory, cost, {"directory" }, "(string) Directory to export troposphere COST file"); + trySetFromYaml(cost_filename, cost, {"filename" }, "(string) Troposphere COST filename"); + trySetFromYaml(cost_time_interval, cost, {"time_interval" }, "(int) Time interval between entries in troposphere COST file (sec)"); + trySetFromYaml(cost_format, cost, {"cost_format" }, "(string) Format name & version number"); + trySetFromYaml(cost_project, cost, {"cost_project" }, "(string) Project name"); + trySetFromYaml(cost_status, cost, {"cost_status" }, "(string) File status"); + trySetFromYaml(cost_centre, cost, {"cost_centre" }, "(string) Processing centre"); + trySetFromYaml(cost_method, cost, {"cost_method" }, "(string) Processing method"); + trySetFromYaml(cost_orbit_type, cost, {"cost_orbit_type" }, "(string) Orbit type"); + trySetFromYaml(cost_met_source, cost, {"cost_met_sources" }, "(string) Source of met. data"); + } + + { + auto rinex_nav = stringsToYamlObject(outputs, {"rinex_nav"}); + + trySetFromYaml(output_rinex_nav, rinex_nav, {"0 output" }, "(bool) "); + trySetFromYaml(rinex_nav_directory, rinex_nav, {"directory" }); + trySetFromYaml(rinex_nav_filename, rinex_nav, {"filename" }); + trySetFromYaml(rinex_nav_version, rinex_nav, {"version" }); + } + + { + auto rinex_obs = stringsToYamlObject(outputs, {"rinex_obs"}); + + trySetFromYaml(output_rinex_obs, rinex_obs, {"0 output" }, "(bool) "); + trySetFromYaml(rinex_obs_directory, rinex_obs, {"directory" }); + trySetFromYaml(rinex_obs_print_C_code, rinex_obs, {"output_pseudorange" }, "(bool) "); + trySetFromYaml(rinex_obs_print_L_code, rinex_obs, {"output_phase_range" }, "(bool) "); + trySetFromYaml(rinex_obs_print_D_code, rinex_obs, {"output_doppler" }, "(bool) "); + trySetFromYaml(rinex_obs_print_S_code, rinex_obs, {"output_signal_to_noise" }, "(bool) "); + trySetFromYaml(rinex_obs_filename, rinex_obs, {"filename" }); + trySetFromYaml(rinex_obs_version, rinex_obs, {"version" }); + } + + { + auto rtcm_nav = stringsToYamlObject(outputs, {"rtcm_nav"}); + + trySetFromYaml(record_rtcm_nav, rtcm_nav, {"0 output" }, "(bool) "); + trySetFromYaml(rtcm_nav_directory, rtcm_nav, {"directory" }); + trySetFromYaml(rtcm_nav_filename, rtcm_nav, {"filename" }); + } + + { + auto rtcm_obs = stringsToYamlObject(outputs, {"rtcm_obs"}); + + trySetFromYaml(record_rtcm_obs, rtcm_obs, {"0 output" }, "(bool) "); + trySetFromYaml(rtcm_obs_directory, rtcm_obs, {"directory" }); + trySetFromYaml(rtcm_obs_filename, rtcm_obs, {"filename" }); + } + + { + auto raw_ubx = stringsToYamlObject(outputs, {"raw_ubx"}); + + trySetFromYaml(record_raw_ubx, raw_ubx, {"0 output" }, "(bool) "); + trySetFromYaml(raw_ubx_directory, raw_ubx, {"directory" }); + trySetFromYaml(raw_ubx_filename, raw_ubx, {"filename" }); + } + + { + auto slr_obs = stringsToYamlObject(outputs, {"slr_obs"}); + + trySetFromYaml(output_slr_obs, slr_obs, {"0 output" }, "(bool) Enable data exporting to tabular SLR obs file"); + trySetFromYaml(slr_obs_directory, slr_obs, {"directory" }, "(string) Directory to export tabular SLR obs file"); + trySetFromYaml(slr_obs_filename, slr_obs, {"filename" }, "(string) Tabular SLR obs filename"); + } + + { + auto trop_sinex = stringsToYamlObject(outputs, {"trop_sinex"}); + + trySetFromYaml(output_trop_sinex, trop_sinex, {"0 output" }, "(bool) Enable data exporting to troposphere SINEX file"); + trySetEnumVec (trop_sinex_data_sources, trop_sinex, {"sources" }, "(enum) Source for troposphere delay data - KALMAN, etc."); + trySetFromYaml(trop_sinex_directory, trop_sinex, {"directory" }, "(string) Directory to export troposphere SINEX file"); + trySetFromYaml(trop_sinex_filename, trop_sinex, {"filename" }, "(string) Troposphere SINEX filename"); + trySetFromYaml(trop_sinex_sol_type, trop_sinex, {"sol_type" }, "(string) Troposphere SINEX solution type"); + trySetFromYaml(trop_sinex_obs_code, trop_sinex, {"obs_code" }, "(string) Troposphere SINEX observation code"); + trySetFromYaml(trop_sinex_const_code, trop_sinex, {"const_code" }, "(string) Troposphere SINEX const code"); + trySetFromYaml(trop_sinex_version, trop_sinex, {"version" }, "(string) Troposphere SINEX version"); + } + + { + auto streams = stringsToYamlObject(outputs, {"streams"}); + + string root_stream_url = ""; + trySetFromYaml(root_stream_url, streams, {"0 root_url"}, "(string) Root url to be prepended to all other streams specified in this section. If the streams used have individually specified root urls, usernames, or passwords, this should not be used."); + + replaceTags(root_stream_url); + + SsrBroadcast dummyStreamData; + tryGetStreamFromYaml(dummyStreamData, streams, {"XMPL"}); + + auto [outStreamNode, outStreamString] = stringsToYamlObject(streams, {"1 labels"}, "[string] List of output stream is with further information to be found in its own section, as per XMPL below"); + + for (auto outLabelYaml : outStreamNode) + { + string outLabel = outLabelYaml.as(); + + tryGetStreamFromYaml(netOpts.uploadingStreamData[outLabel], streams, {outLabel}); + + tryAddRootToPath(root_stream_url, netOpts.uploadingStreamData[outLabel].url); + } + } } - + { - auto pseudo_observation_data = stringsToYamlObject(inputs, {"pseudo_observations"}); - - trySetFromAny(pseudoobs_files, commandOpts, pseudo_observation_data, {"sp3_files" }, "[string] List of sp3 files to use for pseudoobservations"); - + auto inputs = stringsToYamlObject({yaml, ""}, {"0 inputs"}); + string root_stream_url; - trySetFromAny(root_stations_dir, commandOpts, pseudo_observation_data, {"0 root_directory" }, "(string) Root path to be added to all other gnss data files (unless they are absolute)"); - trySetFromYaml(root_stream_url, pseudo_observation_data, {"0 root_stream_url" }); - - tryAddRootToPath(root_stations_dir, pseudoobs_files); - } - - { - auto satellite_data = stringsToYamlObject(inputs, {"0 satellite_data"}); - - string root_ephemeris_directory = "./"; - trySetFromAny(root_ephemeris_directory, commandOpts, satellite_data, {"0 root_directory" }, "(string) Root path to be added to all other gnss data files (unless they are absolute)"); - trySetFromYaml(ephemeris_data_root_url, satellite_data, {"0 root_stream_url" }); - - trySetFromAny(nav_rtcm_files, commandOpts, satellite_data, {"rtcm_files" }, "[string] List of rtcmfiles files to use for corrections"); - trySetFromAny(nav_files, commandOpts, satellite_data, {"nav_files" }, "[string] List of ephemeris files to use"); - trySetFromAny(sp3_files, commandOpts, satellite_data, {"sp3_files" }, "[string] List of sp3 files to use"); - trySetFromAny(dcb_files, commandOpts, satellite_data, {"dcb_files" }, "[string] List of dcb files to use"); - trySetFromAny(bsx_files, commandOpts, satellite_data, {"bsx_files" }, "[string] List of biassinex files to use"); - trySetFromAny(clk_files, commandOpts, satellite_data, {"clk_files" }, "[string] List of clock files to use"); - trySetFromAny(orb_files, commandOpts, satellite_data, {"orb_files" }, "[string] List of orbit(pod) files to use"); - - trySetFromYaml(ephemerisDataStreams, satellite_data, {"streams" }, "[strings] Streams to be processed separately from observations, and will typically be used for receiving SSR messages or other navigational data from an external service"); - - tryAddRootToPath(root_ephemeris_directory, nav_rtcm_files); + trySetFromAny(root_input_directory, commandOpts, inputs, {"0 root_directory" }, "(string) Root path to be added to all other input files (unless they are absolute)"); + trySetFromYaml(root_stream_url, inputs, {"0 root_stream_url" }, "(string) Root url to be prepended to all other streams specified in this section. If the streams used have individually specified root urls, usernames, or passwords, this should not be used."); + trySetFromAny(atx_files, commandOpts, inputs, {"atx_files" }, "[string] List of atx files to use"); + trySetFromAny(snx_files, commandOpts, inputs, {"snx_files" }, "[string] List of snx files to use"); + trySetFromAny(blq_files, commandOpts, inputs, {"blq_files" }, "[string] List of blq files to use"); + trySetFromAny(erp_files, commandOpts, inputs, {"erp_files" }, "[string] List of erp files to use"); + trySetFromAny(ion_files, commandOpts, inputs, {"ion_files" }, "[string] List of ion files to use"); + trySetFromAny(igrf_files, commandOpts, inputs, {"igrf_files" }, "[string] List of igrf files to use"); + trySetFromAny(egm_files, commandOpts, inputs, {"egm_files" }, "[string] List of egm files to use"); + trySetFromAny(jpl_files, commandOpts, inputs, {"jpl_files" }, "[string] List of jpl files to use"); + trySetFromAny(tide_files, commandOpts, inputs, {"tide_files"}); + + + trySetFromYaml(vmf_files, inputs, {"troposphere", "vmf_files" }, "[string] List of vmf files to use"); + trySetFromYaml(model.trop.orography, inputs, {"troposphere", "orography_files" }); + trySetFromYaml(model.trop.gpt2grid, inputs, {"troposphere", "gpt2grid_files" }); + + trySetFromYaml(atm_reg_definitions, inputs, {"ionosphere" , "atm_reg_definitions" }, "[string] List of files to define regions for compact SSR"); + trySetFromAny(ion_files, commandOpts, inputs, {"ionosphere" , "ion_files" }, "[string] List of IONEX files for VTEC input"); + + + { + auto gnss_data = stringsToYamlObject(inputs, {"1 gnss_observations"}); + + string inputs_root = "./"; + trySetFromAny(inputs_root, commandOpts, gnss_data, {"0 inputs_root" }, "(string) Root path to be added to all other gnss data inputs (unless they are absolute)"); + + trySetFromAny(rnx_inputs, commandOpts, gnss_data, {"rnx_inputs" }, "[string] List of rinex inputs to use"); + trySetFromAny(ubx_inputs, commandOpts, gnss_data, {"ubx_inputs" }, "[string] List of ubxfiles inputs to use"); + trySetFromAny(obs_rtcm_inputs, commandOpts, gnss_data, {"rtcm_inputs" }, "[string] List of rtcmfiles inputs to use for observations"); + + tryAddRootToPath(inputs_root, rnx_inputs); + tryAddRootToPath(inputs_root, ubx_inputs); + tryAddRootToPath(inputs_root, obs_rtcm_inputs); + } + + { + auto pseudo_observation_data = stringsToYamlObject(inputs, {"pseudo_observations"}); + + string inputs_root = "./"; + trySetFromYaml(inputs_root, pseudo_observation_data, {"0 inputs_root" }, "(string) Root path to be added to all other pseudo obs data files (unless they are absolute)"); + + trySetFromAny(pseudo_sp3_inputs, commandOpts, pseudo_observation_data, {"sp3_inputs" }, "[string] List of sp3 inputs to use for pseudoobservations"); + trySetFromAny(pseudo_snx_inputs, commandOpts, pseudo_observation_data, {"snx_inputs" }, "[string] List of snx inputs to use for pseudoobservations"); + + tryAddRootToPath(inputs_root, pseudo_sp3_inputs); + tryAddRootToPath(inputs_root, pseudo_snx_inputs); + } + + { + auto satellite_data = stringsToYamlObject(inputs, {"0 satellite_data"}); + + string inputs_root = "./"; + trySetFromYaml(inputs_root, satellite_data, {"0 inputs_root" }, "(string) Root path to be added to all other satellite data files (unless they are absolute)"); + + trySetFromAny(nav_files, commandOpts, satellite_data, {"nav_files" }, "[string] List of ephemeris files to use"); + trySetFromAny(sp3_files, commandOpts, satellite_data, {"sp3_files" }, "[string] List of sp3 files to use"); + trySetFromAny(dcb_files, commandOpts, satellite_data, {"dcb_files" }, "[string] List of dcb files to use"); + trySetFromAny(bsx_files, commandOpts, satellite_data, {"bsx_files" }, "[string] List of biassinex files to use"); + trySetFromAny(clk_files, commandOpts, satellite_data, {"clk_files" }, "[string] List of clock files to use"); + trySetFromAny(sid_files, commandOpts, satellite_data, {"sid_files" }, "[string] List of sat ID files to use - from https://cddis.nasa.gov/sp3c_satlist.html/"); + trySetFromAny(com_files, commandOpts, satellite_data, {"com_files" }, "[string] List of com files to use - retroreflector offsets from centre-of-mass for spherical sats"); + trySetFromAny(crd_files, commandOpts, satellite_data, {"crd_files" }, "[string] List of crd files to use - SLR observation data"); + trySetFromAny(obx_files, commandOpts, satellite_data, {"obx_files" }, "[string] List of orbex files to use"); + trySetFromAny(orb_files, commandOpts, satellite_data, {"orb_files" }, "[string] List of orbit(pod) files to use"); + trySetFromAny(nav_rtcm_inputs, commandOpts, satellite_data, {"rtcm_inputs" }, "[string] List of rtcm inputs to use for corrections"); + +// tryAddRootToPath(inputs_root, nav_files); +// tryAddRootToPath(inputs_root, sp3_files); +// tryAddRootToPath(inputs_root, dcb_files); +// tryAddRootToPath(inputs_root, bsx_files); +// tryAddRootToPath(inputs_root, clk_files); +// tryAddRootToPath(inputs_root, sid_files); +// tryAddRootToPath(inputs_root, com_files); +// tryAddRootToPath(inputs_root, crd_files); +// tryAddRootToPath(inputs_root, obx_files); +// tryAddRootToPath(inputs_root, orb_files); + tryAddRootToPath(inputs_root, nav_rtcm_inputs); + } } - } - - { + auto processing_options = stringsToYamlObject({ yaml, "" }, {processing_options_str}); - { auto general = stringsToYamlObject(processing_options, {"2 gnss_general"}); @@ -1732,48 +2148,60 @@ bool ACSConfig::parse( if (found) elevation_mask *= D2R; - trySetFromYaml (interpolate_rec_pco, general, {"interpolate_rec_pco" }, "(bool) "); - trySetFromYaml (max_gdop, general, {"max_gdop" }); - trySetFromYaml (reject_eclipse, general, {"reject_eclipse" }, "(bool) Exclude satellites that are in eclipsing season"); - trySetFromYaml (raim, general, {"raim" }, "(bool) "); - trySetEnumOpt (recOptsMap[""].error_model, general, {"error_model" }, E_NoiseModel::_from_string_nocase); - trySetFromYaml (pivot_station, general, {"pivot_station" }); - trySetFromYaml (common_atmosphere, general, {"common_atmosphere" }, "(bool) "); - trySetFromYaml (delete_old_ephemerides, general, {"delete_old_ephemerides" }, "(bool) "); - trySetFromYaml (if_antenna_phase_centre, general, {"use_if_apc" }, "(bool) "); - + trySetFromYaml (require_apriori_positions, general, {"require_apriori_positions" }, "(bool) "); + trySetFromYaml (require_antenna_details, general, {"require_antenna_details" }, "(bool) "); + trySetFromYaml (pivot_station, general, {"pivot_station" }, "(string) "); + trySetFromYaml (interpolate_rec_pco, general, {"interpolate_rec_pco" }, "(bool) "); + trySetFromYaml (max_gdop, general, {"max_gdop" }); + trySetFromYaml (raim, general, {"raim" }, "(bool) "); + trySetEnumOpt (recOptsMap[""].error_model, general, {"error_model" }, E_NoiseModel::_from_string_nocase); + trySetFromYaml (pppOpts.common_atmosphere, general, {"common_atmosphere" }, "(bool) "); + trySetFromYaml (pppOpts.use_rtk_combo, general, {"use_rtk_combo" }, "(bool) "); + trySetFromYaml (delete_old_ephemerides, general, {"delete_old_ephemerides" }, "(bool) "); + trySetFromYaml (no_bias_sigma, general, {"no_bias_sigma" }, "(float) Sigma to use for biases that are not found"); + trySetFromYaml (common_sat_pco, general, {"common_sat_pco" }, "(bool) Use L1 satellite PCO values for all signals"); + trySetFromYaml (common_rec_pco, general, {"common_rec_pco" }, "(bool) Use L1 receiver PCO values for all signals"); + trySetFromYaml (leap_seconds, general, {"gpst_utc_leap_seconds" }, "(int) Difference between gps time and utc in leap seconds"); + trySetFromYaml (process_meas[CODE], general, {"1 code_measurements", "process" }, "(bool) "); trySetFromYaml (recOptsMap[""].code_sigmas, general, {"1 code_measurements", "sigmas" }); trySetFromYaml (process_meas[PHAS], general, {"1 phase_measurements", "process" }, "(bool) "); trySetFromYaml (recOptsMap[""].phas_sigmas, general, {"1 phase_measurements", "sigmas" }); - - vector clockCodesStrings; - for (int i = 1; i < E_Sys::SUPPORTED; i++) + + trySetEnumOpt (receiver_reference_clk, general, {"rec_reference_system" }, E_Sys::_from_string_nocase, "(String) Receiver will use this system as reference clock"); + trySetFromYaml (fixed_phase_bias_var, general, {"fixed_phase_bias_var" }, "(double) variance of phase bias to be considered fixed/binded"); + trySetFromYaml (sat_clk_definition, general, {"sat_clk_definition" }, "(bool) use satellite clock definition pseudorange "); + + + for (int i = E_Sys::GPS; i < E_Sys::SUPPORTED; i++) { E_Sys sys = E_Sys::_values()[i]; - string sysName = E_Sys::_names() [i]; boost::algorithm::to_lower(sysName); + string sysName = boost::algorithm::to_lower_copy((string) sys._to_string()); auto sys_options = stringsToYamlObject(general, {"1 sys_options", sysName}); - - trySetFromYaml(process_sys[sys], sys_options, {"0 process" }, "(bool) "); - trySetFromYaml(solve_amb_for[sys], sys_options, {"ambiguity_resolution" }, "(bool) "); - - for (int i = 1; i < NUM_FTYPES; i++) - { - string freq = "l" + std::to_string(i); - trySetFromYaml(process_freq[sys][i], sys_options, {"process_freq", freq}, "(bool) "); - } + trySetFromYaml(process_sys [sys], sys_options, {"0 process" }, "(bool) Process this constellation"); + trySetFromYaml(solve_amb_for [sys], sys_options, {"ambiguity_resolution" }, "(bool) Solve carrier phase ambiguities for this constellation"); + trySetFromYaml(reject_eclipse [sys], sys_options, {"reject_eclipse" }, "(bool) Exclude satellites that are in eclipsing region"); + trySetFromYaml(zero_satellite_dcb [sys], sys_options, {"zero_satellite_dcb" }, "(bool) Constrain: satellite DCB for this system to zero"); + trySetFromYaml(zero_receiver_dcb [sys], sys_options, {"zero_receiver_dcb" }, "(bool) Constrain: receiver DCB for this system to zero"); + trySetFromYaml(one_phase_bias [sys], sys_options, {"one_phase_bias" }, "(bool) Constrain: assume satellite phase biases are common among frequencies"); + trySetFromYaml(receiver_amb_pivot [sys], sys_options, {"receiver_amb_pivot" }, "(bool) Constrain: set of ambiguities, to eliminate receiver rank deficiencies"); + trySetFromYaml(network_amb_pivot [sys], sys_options, {"network_amb_pivot" }, "(bool) Constrain: set of ambiguities, to eliminate network rank deficiencies"); + trySetFromYaml(use_for_iono_model [sys], sys_options, {"use_for_iono_model" }, "(bool) Use this constellation as part of Ionospheric model"); + trySetFromYaml(use_iono_corrections [sys], sys_options, {"use_iono_corrections" }, "(bool) Use external ionosphere delay estimation for this constellation"); + trySetEnumOpt( used_nav_types [sys], sys_options, {"used_nav_type" }, E_NavMsgType::_from_string_nocase); + vector clockCodesStrings; bool found = trySetFromYaml(clockCodesStrings, sys_options, {"clock_codes" }, "(string) Default observation codes on two frequencies for IF combination based satellite clocks"); if (found) for (auto once : {1}) { try { - clock_codesL1[sys] = E_ObsCode::_from_string(clockCodesStrings.at(0).c_str()); - clock_codesL2[sys] = E_ObsCode::_from_string(clockCodesStrings.at(1).c_str()); + clock_codesL1[sys] = E_ObsCode::_from_string_nocase(clockCodesStrings.at(0).c_str()); + clock_codesL2[sys] = E_ObsCode::_from_string_nocase(clockCodesStrings.at(1).c_str()); } catch (...) @@ -1796,7 +2224,7 @@ bool ACSConfig::parse( { try { - auto a = E_ObsCode::_from_string(codePriorityString.c_str()); + auto a = E_ObsCode::_from_string_nocase(codePriorityString.c_str()); code_priorities[sys].push_back(a); } catch (...) @@ -1805,187 +2233,346 @@ bool ACSConfig::parse( } } } + + vector zeroAverageCodes; + found = trySetFromYaml(zeroAverageCodes, sys_options, {"zero_code_average" }); + if (found) + for (auto once : {1}) + { + zero_code_average[sys].clear(); + + for (auto& codeString : zeroAverageCodes) + { + try + { + auto a = E_ObsCode::_from_string(codeString.c_str()); + zero_code_average[sys].push_back(a); + } + catch (...) + { + continue; + } + } + } + + vector zeroAveragePhase; + found = trySetFromYaml(zeroAveragePhase, sys_options, {"zero_phas_average" }); + if (found) + for (auto once : {1}) + { + zero_phas_average[sys].clear(); + + for (auto& codeString : zeroAveragePhase) + { + try + { + auto a = E_ObsCode::_from_string(codeString.c_str()); + zero_phas_average[sys].push_back(a); + } + catch (...) + { + continue; + } + } + } } - } - - { - auto epoch_control = stringsToYamlObject(processing_options, {"0 epoch_control"}); - - int i = 0; - - string startStr; - string stopStr; - trySetFromAny(epoch_interval, commandOpts, epoch_control, {std::to_string(i++) + "epoch_interval" }, "(float) Desired time step between each processing epoch"); - trySetFromAny(max_epochs, commandOpts, epoch_control, {std::to_string(i++) + "max_epochs" }, "(int) Maximum number of epochs to process"); - trySetFromAny(startStr, commandOpts, epoch_control, {std::to_string(i++) + "start_epoch" }, "(date) The time of the first epoch to process (all observations before this will be skipped)"); - trySetFromAny(stopStr, commandOpts, epoch_control, {std::to_string(i++) + "end_epoch" }, "(date) The time of the last epoch to process (all observations after this will be skipped)"); - - if (!startStr.empty()) start_epoch = boost::posix_time::time_from_string(startStr); - if (!stopStr .empty()) end_epoch = boost::posix_time::time_from_string(stopStr); - - trySetFromAny(fatal_level, commandOpts, epoch_control, {std::to_string(i++) + "fatal_message_level" }, "(int) Threshold level for exiting the program early (0-2)"); - - wait_next_epoch = epoch_interval + 0.01; - trySetFromYaml(wait_next_epoch, epoch_control, {std::to_string(i++) + "wait_next_epoch" }, "(float) Time to wait for next epochs data before skipping the epoch (will default to epoch_interval as an appropriate minimum value for realtime)"); - trySetFromYaml(wait_all_stations, epoch_control, {std::to_string(i++) + "wait_all_stations" }, "(float) Time to wait from the reception of the first data of an epoch before skipping stations with data still unreceived"); - trySetFromYaml(require_obs, epoch_control, {std::to_string(i++) + "require_obs" }, "(bool) Exit the program if no observation sources are available"); - trySetFromAny(simulate_real_time, commandOpts, epoch_control, {std::to_string(i++) + "simulate_real_time" }, "(bool) For RTCM playback - delay processing to match original data rate"); - } - - { - auto gnss_modelling = stringsToYamlObject(processing_options, {"2 gnss_models"}); - - trySetFromYaml(model.rec_pos.enable, gnss_modelling, {"rec_pos", "enable" }, "(bool) "); - trySetFromYaml(model.sat_pos.enable, gnss_modelling, {"sat_pos", "enable" }, "(bool) "); - trySetEnumOpt( model.sat_pos.ephemeris_source, gnss_modelling, {"sat_pos", "source" }, E_Ephemeris::_from_string_nocase); - - trySetFromYaml(model.range, gnss_modelling, {"range", "enable" }, "(bool) "); - - trySetFromYaml(model.sat_clock.enable, gnss_modelling, {"sat_clock", "enable" }, "(bool) "); - trySetEnumOpt( model.sat_clock.ephemeris_source, gnss_modelling, {"sat_clock", "source" }, E_Ephemeris::_from_string_nocase); - - trySetFromYaml(model.rec_clock.enable, gnss_modelling, {"rec_clock", "enable" }, "(bool) "); - trySetFromYaml(model.sat_code_bias, gnss_modelling, {"sat_code_bias", "enable" }, "(bool) "); - trySetFromYaml(model.rec_code_bias, gnss_modelling, {"rec_code_bias", "enable" }, "(bool) "); - trySetFromYaml(model.sat_phase_bias, gnss_modelling, {"sat_phase_bias", "enable" }, "(bool) "); - trySetFromYaml(model.rec_phase_bias, gnss_modelling, {"rec_phase_bias", "enable" }, "(bool) "); - - trySetFromYaml(model.rec_ant_delta, gnss_modelling, {"rec_ant_delta", "enable" }, "(bool) "); - trySetFromYaml(model.sat_pco, gnss_modelling, {"sat_pco", "enable" }, "(bool) "); - trySetFromYaml(model.rec_pco, gnss_modelling, {"rec_pco", "enable" }, "(bool) "); - trySetFromYaml(model.sat_pcv, gnss_modelling, {"sat_pcv", "enable" }, "(bool) "); - trySetFromYaml(model.rec_pcv, gnss_modelling, {"rec_pcv", "enable" }, "(bool) "); - - trySetFromYaml(model.tides.enable, gnss_modelling, {"tides", "enable" }, "(bool) "); - trySetFromYaml(model.tides.solid, gnss_modelling, {"tides", "solid" }, "(bool) "); - trySetFromYaml(model.tides.otl, gnss_modelling, {"tides", "otl" }, "(bool) "); - trySetFromYaml(model.tides.pole, gnss_modelling, {"tides", "pole" }, "(bool) "); - - trySetFromYaml(model.relativity, gnss_modelling, {"relativity", "enable" }, "(bool) "); - trySetFromYaml(model.relativity2, gnss_modelling, {"relativity2", "enable" }, "(bool) "); - trySetFromYaml(model.sagnac, gnss_modelling, {"sagnac", "enable" }, "(bool) "); - + { - auto ionospheric_component = stringsToYamlObject(gnss_modelling, {"ionospheric_component"}); - - trySetFromYaml(model.ionospheric_component, ionospheric_component, {"0 enable" }, "(bool) "); - - trySetEnumOpt( ionoOpts.corr_mode, ionospheric_component, {"corr_mode" }, E_IonoMode::_from_string_nocase); - trySetEnumOpt( ionoOpts.iflc_freqs, ionospheric_component, {"iflc_freqs" }, E_LinearCombo::_from_string_nocase); - trySetFromYaml(ionoOpts.common_ionosphere, ionospheric_component, {"common_ionosphere" }, "(bool) "); - trySetFromYaml(ionoOpts.use_if_combo, ionospheric_component, {"use_if_combo" }, "(bool) "); - trySetFromYaml(ionoOpts.auto_select_default_code, ionospheric_component, {"automatic_def_codes" }, "(bool) Automatically detect/select default GNSS codes to estimate the Ionosphere"); + auto epoch_control = stringsToYamlObject(processing_options, {"0 epoch_control"}); + + int i = 0; + + string startStr; + string stopStr; + trySetFromAny(epoch_interval, commandOpts, epoch_control, {std::to_string(i++) + "epoch_interval" }, "(float) Desired time step between each processing epoch"); + trySetFromAny(epoch_tolerance, commandOpts, epoch_control, {std::to_string(i++) + "epoch_tolerance" }, "(float) Tolerance of times to add to an epoch (usually half of the original data's sample rate)"); + trySetFromAny(max_epochs, commandOpts, epoch_control, {std::to_string(i++) + "max_epochs" }, "(int) Maximum number of epochs to process"); + trySetFromAny(startStr, commandOpts, epoch_control, {std::to_string(i++) + "start_epoch" }, "(date) The time of the first epoch to process (all observations before this will be skipped)"); + trySetFromAny(stopStr, commandOpts, epoch_control, {std::to_string(i++) + "end_epoch" }, "(date) The time of the last epoch to process (all observations after this will be skipped)"); + + if (!startStr.empty()) start_epoch = boost::posix_time::time_from_string(startStr); + if (!stopStr .empty()) end_epoch = boost::posix_time::time_from_string(stopStr); + + trySetFromAny(fatal_level, commandOpts, epoch_control, {std::to_string(i++) + "fatal_message_level" }, "(int) Threshold level for exiting the program early (0-2)"); + + wait_next_epoch = epoch_interval + 0.01; + trySetFromYaml(wait_next_epoch, epoch_control, {std::to_string(i++) + "wait_next_epoch" }, "(float) Time to wait for next epochs data before skipping the epoch (will default to epoch_interval as an appropriate minimum value for realtime)"); + trySetFromYaml(wait_all_stations, epoch_control, {std::to_string(i++) + "wait_all_stations" }, "(float) Time to wait from the reception of the first data of an epoch before skipping stations with data still unreceived"); + trySetFromYaml(require_obs, epoch_control, {std::to_string(i++) + "require_obs" }, "(bool) Exit the program if no observation sources are available"); + trySetFromYaml(assign_closest_epoch, epoch_control, {std::to_string(i++) + "assign_closest_epoch"}, "(bool) Assign observations to the closest epoch - don't skip observations that fall between epochs"); + trySetFromAny(simulate_real_time, commandOpts, epoch_control, {std::to_string(i++) + "simulate_real_time" }, "(bool) For RTCM playback - delay processing to match original data rate"); } - + { - auto ionospheric_model = stringsToYamlObject(gnss_modelling, {"ionospheric_model"}); + auto gnss_modelling = stringsToYamlObject(processing_options, {"2 gnss_models"}); + + trySetFromYaml(model.rec_pos.enable, gnss_modelling, {"rec_pos", "enable" }, "(bool) "); + trySetFromYaml(model.sat_pos.enable, gnss_modelling, {"sat_pos", "enable" }, "(bool) "); + trySetEnumVec( model.sat_pos.ephemeris_sources, gnss_modelling, {"sat_pos", "sources" }); + + trySetFromYaml(model.range, gnss_modelling, {"range", "enable" }, "(bool) "); + + trySetFromYaml(model.sat_clock.enable, gnss_modelling, {"sat_clock", "enable" }, "(bool) "); + trySetEnumVec( model.sat_clock.ephemeris_sources, gnss_modelling, {"sat_clock", "sources" }); + + trySetFromYaml(model.rec_clock.enable, gnss_modelling, {"rec_clock", "enable" }, "(bool) "); + trySetFromYaml(model.sat_code_bias, gnss_modelling, {"sat_code_bias", "enable" }, "(bool) "); + trySetFromYaml(model.rec_code_bias, gnss_modelling, {"rec_code_bias", "enable" }, "(bool) "); + trySetFromYaml(model.sat_phase_bias, gnss_modelling, {"sat_phase_bias", "enable" }, "(bool) "); + trySetFromYaml(model.rec_phase_bias, gnss_modelling, {"rec_phase_bias", "enable" }, "(bool) "); + + trySetFromYaml(model.rec_ant_delta, gnss_modelling, {"rec_ant_delta", "enable" }, "(bool) "); + trySetFromYaml(model.sat_pco, gnss_modelling, {"sat_pco", "enable" }, "(bool) "); + trySetFromYaml(model.rec_pco, gnss_modelling, {"rec_pco", "enable" }, "(bool) "); + trySetFromYaml(model.sat_pcv, gnss_modelling, {"sat_pcv", "enable" }, "(bool) "); + trySetFromYaml(model.rec_pcv, gnss_modelling, {"rec_pcv", "enable" }, "(bool) "); + + trySetFromYaml(model.tides.enable, gnss_modelling, {"tides", "enable" }, "(bool) "); + trySetFromYaml(model.tides.solid, gnss_modelling, {"tides", "solid" }, "(bool) "); + trySetFromYaml(model.tides.otl, gnss_modelling, {"tides", "otl" }, "(bool) "); + trySetFromYaml(model.tides.pole, gnss_modelling, {"tides", "pole" }, "(bool) "); + + trySetFromYaml(model.relativity, gnss_modelling, {"relativity", "enable" }, "(bool) "); + trySetFromYaml(model.relativity2, gnss_modelling, {"relativity2", "enable" }, "(bool) "); + trySetFromYaml(model.sagnac, gnss_modelling, {"sagnac", "enable" }, "(bool) "); + + trySetFromYaml(model.sat_attitude.enable, gnss_modelling, {"sat_attitude", "enable" }, "(bool) Enables non-nominal attitude types"); + trySetEnumVec( model.sat_attitude.sources, gnss_modelling, {"sat_attitude", "sources" }, "[E_Source] Attitude type "); + trySetFromYaml(model.sat_attitude.valid_var, gnss_modelling, {"sat_attitude", "valid_var" }, "(double) Observation variance added when attitude is valid"); + trySetFromYaml(model.sat_attitude.invalid_var, gnss_modelling, {"sat_attitude", "invalid_var"},"(double) Observation variance added when attitude is invalid"); + + trySetFromYaml(model.rec_attitude.enable, gnss_modelling, {"rec_attitude", "enable" }, "(bool) Enables non-nominal attitude types"); + trySetEnumVec( model.rec_attitude.sources, gnss_modelling, {"rec_attitude", "sources" }, "[E_Source] Attitude type"); + trySetFromYaml(model.rec_attitude.valid_var, gnss_modelling, {"rec_attitude", "valid_var" }, "(double) Observation variance added when attitude is valid"); + trySetFromYaml(model.rec_attitude.invalid_var, gnss_modelling, {"rec_attitude", "invalid_var"},"(double) Observation variance added when attitude is invalid"); + + + { + auto ionospheric_component = stringsToYamlObject(gnss_modelling, {"ionospheric_component"}); + + trySetFromYaml(model.ionospheric_component, ionospheric_component, {"0 enable" }, "(bool) "); + + trySetEnumOpt( ionoOpts.corr_mode, ionospheric_component, {"corr_mode" }, E_IonoMode::_from_string_nocase); + trySetEnumOpt( ionoOpts.iflc_freqs, ionospheric_component, {"iflc_freqs" }, E_LinearCombo::_from_string_nocase); + trySetEnumOpt( ionoOpts.mapping_function, ionospheric_component, {"mapping_function" }, E_IonoMapFn::_from_string_nocase, "(E_IonoMapFn) mapping function if not specified in the data or model"); + trySetFromYaml(ionoOpts.pierce_point_layer_height, ionospheric_component, {"pierce_point_layer_height" }, "(double) ionospheric pierce point layer height if not specified in the data or model (km)"); + trySetFromYaml(ionoOpts.mapping_function_layer_height, ionospheric_component, {"mapping_function_layer_height" }, "(double) mapping function layer height if not specified in the data or model (km)"); + trySetFromYaml(ionoOpts.common_ionosphere, ionospheric_component, {"common_ionosphere" }, "(bool) "); + trySetFromYaml(ionoOpts.use_if_combo, ionospheric_component, {"use_if_combo" }, "(bool) "); + trySetFromYaml(ionoOpts.auto_select_default_code, ionospheric_component, {"automatic_def_codes" }, "(bool) Automatically detect/select default GNSS codes to estimate the Ionosphere"); + } + + { + auto ionospheric_component2 = stringsToYamlObject(gnss_modelling, {"ionospheric_component2"}); + + trySetFromYaml(model.ionospheric_component2, ionospheric_component2, {"0 enable" }, "(bool) "); + } + + { + auto ionospheric_component3 = stringsToYamlObject(gnss_modelling, {"ionospheric_component3"}); + + trySetFromYaml(model.ionospheric_component3, ionospheric_component3, {"0 enable" }, "(bool) "); + } - trySetFromYaml(process_ionosphere, ionospheric_model, {"0 enable" }, "(bool) Compute ionosphere maps from a network of stations"); - trySetEnumOpt( ionModelOpts.model, ionospheric_model, {"model" }, E_IonoModel::_from_string_nocase); - trySetFromYaml(ionModelOpts.function_order, ionospheric_model, {"function_order" }); - trySetFromYaml(ionModelOpts.model_noise, ionospheric_model, {"model_noise" }); - trySetKalmanFromYaml(ionModelOpts.ion, ionospheric_model, "ion"); - - bool found = trySetFromYaml(ionModelOpts.layer_heights, ionospheric_model, {"layer_heights" }); - if (found) - for (auto& a : ionModelOpts.layer_heights) { - a *= 1000; //km to m + auto ionospheric_model = stringsToYamlObject(gnss_modelling, {"ionospheric_model"}); + + trySetFromYaml(process_ionosphere, ionospheric_model, {"0 enable" }, "(bool) Compute ionosphere maps from a network of stations"); + trySetEnumOpt( ionModelOpts.model, ionospheric_model, {"model" }, E_IonoModel::_from_string_nocase); + trySetFromYaml(ionModelOpts.function_order, ionospheric_model, {"function_order" }, "Maximum order of Spherical harmonics for Ionospheric mapping"); + trySetFromYaml(ionModelOpts.function_degree, ionospheric_model, {"function_degree" }, "Maximum degree of Spherical harmonics for Ionospheric mapping"); + trySetFromYaml(ionModelOpts.estimate_sat_dcb, ionospheric_model, {"estimate_sat_dcb" }, "(bool) Estimate satellite dcb alongside Ionosphere models, should be false for local STEC"); + trySetFromYaml(ionModelOpts.use_rotation_mtx, ionospheric_model, {"use_rotation_mtx" }, "(bool) Use 3D rotation matrix for spherical harmonics"); + + bool found = trySetFromYaml(ionModelOpts.layer_heights, ionospheric_model, {"layer_heights" }); + if (found) + for (auto& a : ionModelOpts.layer_heights) + { + a *= 1000; //km to m + } } + + auto troposhpere = stringsToYamlObject(gnss_modelling, {"troposphere"}); + { + trySetFromYaml(model.trop.enable, troposhpere, {"0 enable" }); + trySetEnumOpt( model.trop.model, troposhpere, {"model" }, E_TropModel::_from_string_nocase); + } + + auto orbits = stringsToYamlObject(gnss_modelling, {"orbits"}); + { + trySetFromYaml(model.orbits, orbits, {"0 enable" }); + } + + trySetFromYaml(model.phase_windup, gnss_modelling, {"phase_windup", "enable" }, "(bool) "); + trySetFromYaml(model.heading, gnss_modelling, {"heading", "enable" }, "(bool) "); + trySetFromYaml(model.integer_ambiguity, gnss_modelling, {"integer_ambiguity", "enable" }, "(bool) "); + trySetFromYaml(model.clock_definitions, gnss_modelling, {"clock_definitions", "enable" }, "(bool) "); } - auto troposhpere = stringsToYamlObject(gnss_modelling, {"troposphere"}); { - trySetFromYaml(model.trop.enable, troposhpere, {"0 enable" }); - trySetEnumOpt( model.trop.model, troposhpere, {"model" }, E_TropModel::_from_string_nocase); + auto model_error_checking = stringsToYamlObject(processing_options, {"3 model_error_checking"}); + + { + auto deweighting = stringsToYamlObject(model_error_checking, {"deweighting"}); + + trySetFromYaml(deweight_on_state_error, deweighting, {"deweight_on_state_error" }, "(bool) Any \"state\" errors cause deweighting of all measurements that reference the state"); + + trySetFromYaml(deweight_factor, deweighting, {"deweight_factor" }, "(float) Factor to downweight the variance of measurements with statistically detected errors"); + trySetFromYaml(deweight_on_state_error, deweighting, {"deweight_on_state_error" }, "(bool) Any \"state\" errors cause deweighting of all measurements that reference the state"); + } + + { + auto orbit_errors = stringsToYamlObject(model_error_checking, {"orbit_errors"}); + + trySetFromYaml(orbit_pos_proc_noise, orbit_errors, {"orbit_pos_proc_noise" }); + trySetFromYaml(orbit_vel_proc_noise, orbit_errors, {"orbit_vel_proc_noise" }); + trySetFromYaml(orbit_vel_proc_noise_trail, orbit_errors, {"orbit_vel_proc_noise_trail" }); + trySetFromYaml(orbit_vel_proc_noise_trail_tau, orbit_errors, {"orbit_vel_proc_noise_trail_tau" }); + } + + { + auto ambiguities = stringsToYamlObject(model_error_checking, {"ambiguities"}); + + trySetFromYaml(reinit_on_all_slips, ambiguities, {"reinit_on_all_slips" }, "(bool) Any detected slips cause removal and reinitialisation of ambiguities"); + trySetFromYaml(pppOpts.outage_reset_limit, ambiguities, {"outage_reset_limit" }, "(int) Maximum number of epochs with missed phase measurements before the ambiguity associated with the measurement is reset."); + trySetFromYaml(pppOpts.phase_reject_limit, ambiguities, {"phase_reject_limit" }, "(int) Maximum number of phase measurements to reject before the ambiguity associated with the measurement is reset."); + } + + { + auto clocks = stringsToYamlObject(model_error_checking, {"clocks"}); + + trySetFromYaml(reinit_on_clock_error, clocks, {"reinit_on_clock_error" }, "(bool) Any clock \"state\" errors cause removal and reinitialisation of the clocks and all associated ambiguities"); + } + + { + auto cycle_slips = stringsToYamlObject(model_error_checking, {"cycle_slips"}); + + trySetFromYaml(thres_slip, cycle_slips, {"slip_threshold" }); + trySetFromYaml(mw_proc_noise, cycle_slips, {"mw_proc_noise" }); + + trySetFromYaml(excludeSlip.LLI, cycle_slips, {"exclude_on", "lli" }, "(bool) Exclude measurements that fail LLI slip test in preprocessor"); + trySetFromYaml(excludeSlip.GF, cycle_slips, {"exclude_on", "gf" }, "(bool) Exclude measurements that fail GF slip test in preprocessor"); + trySetFromYaml(excludeSlip.MW, cycle_slips, {"exclude_on", "mw" }, "(bool) Exclude measurements that fail MW slip test in preprocessor"); + trySetFromYaml(excludeSlip.SCDIA, cycle_slips, {"exclude_on", "scdia" }, "(bool) Exclude measurements that fail SCDIA test in preprocessor"); + + trySetFromYaml(resetOnSlip.LLI, cycle_slips, {"reset_on", "lli" }, "(bool) Reset ambiguities if LLI test is detecting a slip"); + trySetFromYaml(resetOnSlip.GF, cycle_slips, {"reset_on", "gf" }, "(bool) Reset ambiguities if GF test is detecting a slip"); + trySetFromYaml(resetOnSlip.MW, cycle_slips, {"reset_on", "mw" }, "(bool) Reset ambiguities if MW test is detecting a slip"); + trySetFromYaml(resetOnSlip.SCDIA, cycle_slips, {"reset_on", "scdia" }, "(bool) Reset ambiguities if SCDIA test is detecting a slip"); + } + } - - trySetFromYaml(model.phase_windup, gnss_modelling, {"phase_windup", "enable" }, "(bool) "); - trySetFromYaml(model.integer_ambiguity, gnss_modelling, {"integer_ambiguity", "enable" }, "(bool) "); - trySetFromYaml(model.clock_definitions, gnss_modelling, {"clock_definitions", "enable" }, "(bool) "); - } - - { - auto model_error_checking = stringsToYamlObject(processing_options, {"3 model_error_checking"}); - + { - auto deweighting = stringsToYamlObject(model_error_checking, {"deweighting"}); - - trySetFromYaml(deweight_factor, deweighting, {"deweight_factor" }, "(float) Factor to downweight the variance of measurements with statistically detected errors"); - trySetFromYaml(deweight_on_state_error, deweighting, {"deweight_on_state_error" }, "(bool) Any \"state\" errors cause deweighting of all measurements that reference the state"); - } + auto process_modes = stringsToYamlObject(processing_options, {"1 process_modes"}); + trySetFromYaml(process_user, process_modes, {"user" }, "(bool) Compute position/clock/atmosphere at autonomous receiver location using UD/IF PPP"); + trySetFromYaml(process_network, process_modes, {"network" }, "(bool) Compute GNSS corrections using UD/IF PPP on a CORS network"); + trySetFromYaml(process_ionosphere, process_modes, {"ionosphere" }, "(bool) Compute Ionosphere models based on GNSS measurements"); + trySetFromYaml(process_preprocessor, process_modes, {"preprocessor" }, "(bool) Preprocessing and quality checks"); + trySetFromYaml(process_spp, process_modes, {"spp" }, "(bool) Perform SPP on station data"); + trySetFromYaml(process_ppp, process_modes, {"ppp" }, "(bool) Perform PPP network or end user mode"); + } + { - auto ambiguities = stringsToYamlObject(model_error_checking, {"ambiguities"}); - - trySetFromYaml(reinit_on_all_slips, ambiguities, {"reinit_on_all_slips" }, "(bool) Any detected slips cause removal and reinitialisation of ambiguities"); - trySetFromYaml(pppOpts.outage_reset_limit, ambiguities, {"outage_reset_limit" }, "(int) Maximum number of epochs with missed phase measurements before the ambiguity associated with the measurement is reset."); - trySetFromYaml(pppOpts.phase_reject_limit, ambiguities, {"phase_reject_limit" }, "(int) Maximum number of phase measurements to reject before the ambiguity associated with the measurement is reset."); + auto minimum_constraints = stringsToYamlObject(processing_options, {"minimum_constraints"}); + + trySetFromYaml(process_minimum_constraints, minimum_constraints, {"enable" }, "(bool) Transform states by minimal constraints to selected station coordinates"); + + trySetKalmanFromYaml(minCOpts.scale, minimum_constraints, "scale"); + trySetKalmanFromYaml(minCOpts.rotation, minimum_constraints, "rotation"); + trySetKalmanFromYaml(minCOpts.translation, minimum_constraints, "translation"); + + trySetFromYaml(minCOpts.once_per_epoch, minimum_constraints, {"once_per_epoch" }, "(bool) Perform minimum constraints on a temporary filter and output results once per epoch"); + trySetFromYaml(minCOpts.full_vcv, minimum_constraints, {"full_vcv" }, "(bool) ! experimental ! Use full VCV for measurement noise in minimum constraints filter"); + trySetFromYaml(minCOpts.scale_by_vcv, minimum_constraints, {"scale_by_vcv" }, "(bool) Use variance of positions as additional scaling factor in minimum constraints weighting"); + + trySetEnumOpt( minCOpts.inverter, minimum_constraints, {"inverter" }, E_Inverter::_from_string_nocase); + trySetFromYaml(minCOpts.max_filter_iter, minimum_constraints, {"max_filter_iterations" }); + trySetFromYaml(minCOpts.max_prefit_remv, minimum_constraints, {"max_prefit_removals" }, "(int) Maximum number of measurements to exclude using prefit checks before attempting to filter"); + trySetFromYaml(minCOpts.sigma_check, minimum_constraints, {"outlier_screening", "sigma_check" }, "(bool) Enable prefit and postfit sigma check"); + trySetFromYaml(minCOpts.w_test, minimum_constraints, {"outlier_screening", "w_test" }, "(bool) Enable w-test"); + trySetFromYaml(minCOpts.chi_square_test, minimum_constraints, {"outlier_screening", "chi_square_test" }, "(bool) Enable Chi-square test"); + trySetEnumOpt( minCOpts.chi_square_mode, minimum_constraints, {"outlier_screening", "chi_square_mode" }, E_ChiSqMode::_from_string_nocase, "(enum) Chi-square test mode - innovation, measurement, state"); + trySetFromYaml(minCOpts.sigma_threshold, minimum_constraints, {"outlier_screening", "sigma_threshold" }, "(float) sigma threshold"); } - + + auto filter_options = stringsToYamlObject(processing_options, {"filter_options"}); { - auto clocks = stringsToYamlObject(model_error_checking, {"clocks"}); + trySetFromYaml(joseph_stabilisation, filter_options, {"joseph_stabilisation" }); + trySetEnumOpt( pppOpts.inverter, filter_options, {"inverter" }, E_Inverter::_from_string_nocase, "Inverter to be used within the Kalman filter update stage, which may provide different performance outcomes in terms of processing time and accuracy and stability."); + trySetFromYaml(process_rts, filter_options, {"rts", "0 enable" }, "(bool) Perform backward smoothing of states to improve precision of earlier states"); + trySetFromYaml(pppOpts.rts_lag, filter_options, {"rts", "1 lag" }, "(int) Number of epochs to use in RTS smoothing. Negative numbers indicate full reverse smoothing."); + trySetFromYaml(pppOpts.rts_directory, filter_options, {"rts", "directory" }, "(string) Directory for rts intermediate files"); + trySetFromYaml(pppOpts.rts_filename, filter_options, {"rts", "filename" }, "(string) Base filename for rts intermediate files"); + trySetFromYaml(pppOpts.rts_smoothed_suffix, filter_options, {"rts", "suffix" }, "(string) Suffix to be applied to smoothed versions of files"); + trySetEnumOpt( pppOpts.rts_inverter, filter_options, {"rts", "inverter" }, E_Inverter::_from_string_nocase, "Inverter to be used within the rts processor, which may provide different performance outcomes in terms of processing time and accuracy and stability."); + trySetFromYaml(pppOpts.output_intermediate_rts, filter_options, {"rts", "output_intermediates" }, "(bool) Output best available smoothed states when performing fixed-lag rts (slow, use only when needed)"); + trySetFromYaml(pppOpts.simulate_filter_only, filter_options, {"simulate_filter_only" }, "(bool) Residuals will be calculated, but no adjustments to state or covariances will be applied"); + trySetFromYaml(pppOpts.simulate_pseudos_only, filter_options, {"simulate_pseudos_only" }, "(bool) Residuals will be calculated for sp3 pseudoobs, but no adjustments to state or covariances will be applied"); - trySetFromYaml(reinit_on_clock_error, clocks, {"reinit_on_clock_error" }, "(bool) Any clock \"state\" errors cause removal and reinitialisation of the clocks and all associated ambiguities"); + trySetFromYaml(pppOpts.max_filter_iter, filter_options, {"outlier_screening", "max_filter_iterations" }); + trySetFromYaml(pppOpts.sigma_check, filter_options, {"outlier_screening", "sigma_check" }, "(bool) Enable prefit and postfit sigma check"); + trySetFromYaml(pppOpts.w_test, filter_options, {"outlier_screening", "w_test" }, "(bool) Enable w-test"); + trySetFromYaml(pppOpts.chi_square_test, filter_options, {"outlier_screening", "chi_square_test" }, "(bool) Enable Chi-square test"); + trySetEnumOpt( pppOpts.chi_square_mode, filter_options, {"outlier_screening", "chi_square_mode" }, E_ChiSqMode::_from_string_nocase, "(enum) Chi-square test mode - innovation, measurement, state"); + trySetFromYaml(pppOpts.sigma_threshold, filter_options, {"outlier_screening", "sigma_threshold" }, "(float) sigma threshold"); + trySetFromYaml(pppOpts.max_prefit_remv, filter_options, {"outlier_screening", "max_prefit_removals" }, "(int) Maximum number of measurements to exclude using prefit checks before attempting to filter"); + trySetFromYaml(pppOpts.chunk_size, filter_options, {"chunking", "size" }); + trySetFromYaml(pppOpts.station_chunking, filter_options, {"station_chunking", "enable" }, "(bool) "); + trySetFromYaml(pppOpts.satellite_chunking, filter_options, {"satellite_chunking", "enable" }, "(bool) "); } - + + auto slr_options = stringsToYamlObject(processing_options, {"slr_options"}); { - auto cycle_slips = stringsToYamlObject(model_error_checking, {"cycle_slips"}); - - trySetFromYaml(thres_slip, cycle_slips, {"slip_threshold" }); - trySetFromYaml(mw_proc_noise, cycle_slips, {"mw_proc_noise" }); - - trySetFromYaml(excludeSlip.LLI, cycle_slips, {"detect", "lli" }, "(bool) Exclude measurements that fail LLI slip test in preprocessor"); - trySetFromYaml(excludeSlip.GF, cycle_slips, {"detect", "gf" }, "(bool) Exclude measurements that fail GF slip test in preprocessor"); - trySetFromYaml(excludeSlip.MW, cycle_slips, {"detect", "mw" }, "(bool) Exclude measurements that fail MW slip test in preprocessor"); - trySetFromYaml(excludeSlip.EMW, cycle_slips, {"detect", "emw" }, "(bool) Exclude measurements that fail EMW slip test in preprocessor"); - trySetFromYaml(excludeSlip.CJ, cycle_slips, {"detect", "cj" }, "(bool) Exclude measurements that fail clk jump test in preprocessor"); - trySetFromYaml(excludeSlip.SCDIA, cycle_slips, {"detect", "scdia" }, "(bool) Exclude measurements that fail SCDIA test in preprocessor"); + trySetFromYaml(slrOpts.process_slr, slr_options, {"process_slr" }, "(bool) Process SLR observations (in addition to GNSS)"); } } - - { - auto process_modes = stringsToYamlObject(processing_options, {"1 process_modes"}); - - trySetFromYaml(process_user, process_modes, {"user" }, "(bool) Compute PPP for separate stations using provided satellite data"); - trySetFromYaml(process_network, process_modes, {"network" }, "(bool) Compute PPP corrections for a network of stations and satellites"); - trySetFromYaml(process_ionosphere, process_modes, {"ionosphere" }, "(bool) "); - trySetFromYaml(process_preprocessor, process_modes, {"preprocessor" }, "(bool) Perform preprocessing for quality checks"); - trySetFromYaml(process_ppp, process_modes, {"ppp" }, "(bool) Perform PPP on a network of stations and satellites"); - // trySetFromYaml(process_orbits, b, {"process_modes","orbits" }, "(bool) Propagate an orbit using initial conditions"); - } - + + + auto orbit_propagation = stringsToYamlObject({ yaml, "" }, {processing_options_str, "orbit_propagation"}); { - auto minimum_constraints = stringsToYamlObject(processing_options, {"minimum_constraints"}); - - trySetFromYaml(process_minimum_constraints, minimum_constraints, {"enable" }, "(bool) Transform states by minimal constraints to selected station coordinates"); - - trySetKalmanFromYaml(minCOpts.scale, minimum_constraints, "scale"); - trySetKalmanFromYaml(minCOpts.rotation, minimum_constraints, "rotation"); - trySetKalmanFromYaml(minCOpts.translation, minimum_constraints, "translation"); + trySetFromYaml(orbitPropagation.central_force, orbit_propagation, {"central_force" }); + trySetFromYaml(orbitPropagation.planetary_perturbation, orbit_propagation, {"planetary_perturbation" }); + trySetFromYaml(orbitPropagation.indirect_J2, orbit_propagation, {"indirect_J2" }); + trySetFromYaml(orbitPropagation.egm_field, orbit_propagation, {"egm_field" }); + trySetFromYaml(orbitPropagation.solid_earth_tide, orbit_propagation, {"solid_earth_tide" }); + trySetFromYaml(orbitPropagation.ocean_tide, orbit_propagation, {"ocean_tide" }); + trySetFromYaml(orbitPropagation.general_relativity, orbit_propagation, {"general_relativity" }); + trySetFromYaml(orbitPropagation.pole_tide_ocean, orbit_propagation, {"pole_tide_ocean" }); + trySetFromYaml(orbitPropagation.pole_tide_solid, orbit_propagation, {"pole_tide_solid" }); + trySetFromYaml(orbitPropagation.solar_pressure_radiation, orbit_propagation, {"solar_pressure_radiation" }); + trySetFromYaml(orbitPropagation.empirical_dyb, orbit_propagation, {"empirical_dyb" }); + trySetFromYaml(orbitPropagation.antenna_thrust, orbit_propagation, {"antenna_thrust" }); + trySetFromYaml(orbitPropagation.albedo, orbit_propagation, {"albedo" }); + trySetFromYaml(orbitPropagation.sat_mass, orbit_propagation, {"sat_mass" }); + trySetFromYaml(orbitPropagation.sat_area, orbit_propagation, {"sat_area" }); + trySetFromYaml(orbitPropagation.srp_cr, orbit_propagation, {"srp_cr" }); + trySetFromYaml(orbitPropagation.degree_max, orbit_propagation, {"degree_max" }); + trySetFromYaml(orbitPropagation.itrf_pseudoobs, orbit_propagation, {"itrf_pseudoobs" }); + trySetFromYaml(orbitPropagation.integrator_time_step, orbit_propagation, {"integrator_time_step" }); + - trySetFromYaml(minCOpts.full_vcv, minimum_constraints, {"full_vcv" }, "(bool) ! experimental ! Use full VCV for measurement noise in minimum constraints filter"); - trySetFromYaml(minCOpts.scale_by_vcv, minimum_constraints, {"scale_by_vcv" }, "(bool) Use variance of positions as additional scaling factor in minimum constraints weighting"); - - trySetEnumOpt( minCOpts.inverter, minimum_constraints, {"inverter" }, E_Inverter::_from_string_nocase); - trySetFromYaml(minCOpts.max_filter_iter, minimum_constraints, {"max_filter_iterations" }); - trySetFromYaml(minCOpts.max_prefit_remv, minimum_constraints, {"max_prefit_removals" }, "(int) Maximum number of measurements to exclude using prefit checks before attempting to filter"); - trySetFromYaml(minCOpts.sigma_check, minimum_constraints, {"outlier_screening", "sigma_check" }, "(bool) Enable prefit and postfit sigma check"); - trySetFromYaml(minCOpts.w_test, minimum_constraints, {"outlier_screening", "w_test" }, "(bool) Enable w-test"); - trySetFromYaml(minCOpts.chi_square_test, minimum_constraints, {"outlier_screening", "chi_square_test" }, "(bool) Enable Chi-square test"); - trySetEnumOpt( minCOpts.chi_square_mode, minimum_constraints, {"outlier_screening", "chi_square_mode" }, E_ChiSqMode::_from_string_nocase, "(enum) Chi-square test mode - innovation, measurement, state"); - trySetFromYaml(minCOpts.sigma_threshold, minimum_constraints, {"outlier_screening", "sigma_threshold" }, "(float) sigma threshold"); } + + +// trySetFromYaml(split_sys, outputs, { "split_sys" }); + +// trySetFromAny (output_persistance, commandOpts, output_files, {"output_persistance" }); +// trySetFromAny (input_persistance, commandOpts, output_files, {"input_persistance" }); +// trySetFromYaml(persistance_directory, output_files, {"persistance_directory" }); +// trySetFromYaml(persistance_filename, output_files, {"persistance_filename" }); + { auto ambres_options = stringsToYamlObject(processing_options, {"ambiguity_resolution"}); - + trySetFromYaml(ambrOpts.min_el_AR, ambres_options, {"elevation_mask" }); trySetFromYaml(ambrOpts.lambda_set, ambres_options, {"lambda_set_size" }); trySetFromYaml(ambrOpts.AR_max_itr, ambres_options, {"max_rounding_iterations" }); trySetFromYaml(ambrOpts.Max_Hold_epoc, ambres_options, {"max_hold_epochs" }, "Maximun number of epocs to hold ambiguities"); trySetFromYaml(ambrOpts.Max_Hold_time, ambres_options, {"max_hold_time" }, "Maximun amount of time (sec) to hold ambiguities"); - + trySetEnumOpt( ambrOpts.WLmode, ambres_options, {"wide_lane", "mode" }, E_ARmode::_from_string_nocase); trySetFromYaml(ambrOpts.WLsuccsThres, ambres_options, {"wide_lane", "success_rate_threshold" }); trySetFromYaml(ambrOpts.WLratioThres, ambres_options, {"wide_lane", "solution_ratio_threshold" }); @@ -1993,7 +2580,7 @@ bool ACSConfig::parse( trySetFromYaml(ambrOpts.WLRecPrcNois, ambres_options, {"wide_lane", "process_noise_rec" }, "WL bias process noise for receivers"); trySetFromYaml(ambrOpts.WL_filter_iter, ambres_options, {"wide_lane", "filter_max_iterations" }); trySetFromYaml(ambrOpts.WL_prefit_remv, ambres_options, {"wide_lane", "filter_max_removals" }); - + trySetEnumOpt( ambrOpts.NLmode, ambres_options, {"narrow_lane", "mode" }, E_ARmode::_from_string_nocase); trySetFromYaml(ambrOpts.NLsuccsThres, ambres_options, {"narrow_lane", "success_rate_threshold" }); trySetFromYaml(ambrOpts.NLratioThres, ambres_options, {"narrow_lane", "solution_ratio_threshold" }); @@ -2001,182 +2588,175 @@ bool ACSConfig::parse( trySetFromYaml(ambrOpts.reduction_limit, ambres_options, {"reduction_limit" }); } - + { auto ssr_corrections = stringsToYamlObject(processing_options, {"ssr_corrections"}); - - trySetEnumOpt (ssrOpts.ephemeris_source, ssr_corrections, {"ephemeris_source" }, E_Ephemeris::_from_string_nocase); - trySetEnumOpt (ssrOpts.clock_source, ssr_corrections, {"clock_source" }, E_Ephemeris::_from_string_nocase); - trySetEnumOpt (ssrOpts.code_bias_source, ssr_corrections, {"code_bias_source" }, E_Ephemeris::_from_string_nocase); - trySetEnumOpt (ssrOpts.phase_bias_source, ssr_corrections, {"phase_bias_source" }, E_Ephemeris::_from_string_nocase); - trySetFromYaml(ssrOpts.calculate_ssr, ssr_corrections, {"calculate_precursors" }, "(bool) "); + + trySetEnumVec (ssrOpts.ephemeris_sources, ssr_corrections, {"ephemeris_sources" }); + trySetEnumVec (ssrOpts.clock_sources, ssr_corrections, {"clock_sources" }); + trySetEnumVec (ssrOpts.code_bias_sources, ssr_corrections, {"code_bias_sources" }); + trySetEnumVec (ssrOpts.phase_bias_sources, ssr_corrections, {"phase_bias_sources" }); + trySetEnumVec (ssrOpts.ionosphere_sources, ssr_corrections, {"ionosphere_sources" }); + // trySetEnumVec (ssrOpts.troposphere_sources, ssr_corrections, {"troposphere_sources" }); trySetFromYaml(ssrOpts.prediction_interval, ssr_corrections, {"prediction_interval" }); trySetFromYaml(ssrOpts.prediction_duration, ssr_corrections, {"prediction_duration" }); trySetFromYaml(ssrOpts.extrapolate_corrections, ssr_corrections, {"extrapolate_corrections" }, "(bool) "); - } - + } + { auto ssr_inputs = stringsToYamlObject(processing_options, {"ssr_inputs"}); - - trySetFromYaml(ssrInOpts.code_bias_valid_time, ssr_inputs, {"code_bias_validity_time" }, "(double) Valid time period of SSR code biases"); - trySetFromYaml(ssrInOpts.phase_bias_valid_time, ssr_inputs, {"phase_bias_validity_time" }, "(double) Valid time period of SSR phase biases"); + + trySetFromYaml(ssrInOpts.code_bias_valid_time, ssr_inputs, {"code_bias_validity_time" }, "(double) Valid time period of SSR code biases"); + trySetFromYaml(ssrInOpts.phase_bias_valid_time, ssr_inputs, {"phase_bias_validity_time" }, "(double) Valid time period of SSR phase biases"); + trySetFromYaml(ssrInOpts.one_freq_phase_bias, ssr_inputs, {"one_freq_phase_bias" }, "(bool) Used stream have one SSR phase bias per frequency"); + trySetFromYaml(ssrInOpts.global_vtec_valid_time,ssr_inputs, {"global_vtec_valid_time" }, "(double) Valid time period of global VTEC maps"); + trySetFromYaml(ssrInOpts.local_stec_valid_time, ssr_inputs, {"local_stec_valid_time" }, "(double) Valid time period of local STEC corrections"); trySetFromYaml(validity_interval_factor, ssr_inputs, {"validity_interval_factor" }); trySetEnumOpt(ssr_input_antenna_offset, ssr_inputs, {"ssr_antenna_offset" }, E_OffsetType::_from_string_nocase, "Ephemeris type that is provided in the listed SSR stream, i.e. satellite antenna-phase-centre (APC) or centre-of-mass (COM). This information is listed in the NTRIP Caster's sourcetable"); } - - auto filter_options = stringsToYamlObject(processing_options, {"filter_options"}); + + auto estimation_parameters = stringsToYamlObject({yaml, ""}, {estimation_parameters_str}); { - trySetFromYaml(joseph_stabilisation, filter_options, {"joseph_stabilisation" }); - trySetEnumOpt( pppOpts.inverter, filter_options, {"inverter" }, E_Inverter::_from_string_nocase, "Inverter to be used within the Kalman filter update stage, which may provide different performance outcomes in terms of processing time and accuracy and stability."); - trySetFromYaml(process_rts, filter_options, {"rts", "0 enable" }, "(bool) Perform backward smoothing of states to improve precision of earlier states"); - trySetFromYaml(pppOpts.rts_lag, filter_options, {"rts", "1 lag" }, "(int) Number of epochs to use in RTS smoothing. Negative numbers indicate full reverse smoothing."); - trySetFromYaml(pppOpts.rts_directory, filter_options, {"rts", "directory" }, "(string) Directory for rts intermediate files"); - trySetFromYaml(pppOpts.rts_filename, filter_options, {"rts", "filename" }, "(string) Base filename for rts intermediate files"); - trySetFromYaml(pppOpts.max_filter_iter, filter_options, {"outlier_screening", "max_filter_iterations" }); - trySetFromYaml(pppOpts.sigma_check, filter_options, {"outlier_screening", "sigma_check" }, "(bool) Enable prefit and postfit sigma check"); - trySetFromYaml(pppOpts.w_test, filter_options, {"outlier_screening", "w_test" }, "(bool) Enable w-test"); - trySetFromYaml(pppOpts.chi_square_test, filter_options, {"outlier_screening", "chi_square_test" }, "(bool) Enable Chi-square test"); - trySetEnumOpt( pppOpts.chi_square_mode, filter_options, {"outlier_screening", "chi_square_mode" }, E_ChiSqMode::_from_string_nocase, "(enum) Chi-square test mode - innovation, measurement, state"); - trySetFromYaml(pppOpts.sigma_threshold, filter_options, {"outlier_screening", "sigma_threshold" }, "(float) sigma threshold"); - trySetFromYaml(pppOpts.max_prefit_remv, filter_options, {"outlier_screening", "max_prefit_removals" }, "(int) Maximum number of measurements to exclude using prefit checks before attempting to filter"); - trySetFromYaml(pppOpts.chunk_size, filter_options, {"chunking", "size" }); - trySetFromYaml(pppOpts.chunk_stations, filter_options, {"chunking", "enable" }, "(bool) "); + trySetKalmanFromYaml(pppOpts.eop, estimation_parameters, "eop" ); + trySetKalmanFromYaml(pppOpts.eop_rates, estimation_parameters, "eop_rates" ); + trySetKalmanFromYaml(ionModelOpts.ion, estimation_parameters, "ion" ); } - } - -#if 0 - auto force_models = stringsToYamlObject({ yaml, "" }, {processing_options_str, "force_models"}); - { - trySetFromYaml(forceModels.earth_gravity, force_models, {"earth_gravity" }); - trySetFromYaml(forceModels.solid_earth_tides, force_models, {"solid_earth_tides" }); - trySetFromYaml(forceModels.ocean_tide_loading, force_models, {"ocean_tide_loading" }); - trySetFromYaml(forceModels.relativity_effect, force_models, {"relativity_effect" }); - trySetFromYaml(forceModels.solar_radiation_pressure, force_models, {"solar_radiation_pressure" }); - trySetFromYaml(forceModels.thermal_emission, force_models, {"thermal_emission" }); - trySetFromYaml(forceModels.earth_albedo, force_models, {"earth_albedo" }); - trySetFromYaml(forceModels.infrared_radiation, force_models, {"infrared_radiation" }); - trySetFromYaml(forceModels.antenna_thrust, force_models, {"antenna_thrust" }); - trySetFromYaml(forceModels.satellite_manoeuvre, force_models, {"satellite_manoeuvre" }); - trySetFromYaml(forceModels.empirical_acceleration, force_models, {"empirical_acceleration" }); - trySetFromYaml(forceModels.sat_mass, force_models, {"satMass" }); - trySetFromYaml(forceModels.srp_area, force_models, {"srpArea" }); - trySetFromYaml(forceModels.srp_coef, force_models, {"srpCoef" }); - trySetFromYaml(forceModels.egmAccDeg, force_models, {"egmAccDeg" }); - trySetFromYaml(forceModels.egmAccOrd, force_models, {"egmAccOrd" }); - trySetFromYaml(forceModels.egmSTMDeg, force_models, {"egmSTMDeg" }); - trySetFromYaml(forceModels.egmSTMOrd, force_models, {"egmSTMOrd" }); - trySetEnumOpt( forceModels.gravity_model, force_models, {"gravity_model" }, E_GravMdl::_from_string_nocase); - trySetEnumOpt( forceModels.srp_model, force_models, {"srp_model" }, E_SRPModels::_from_string_nocase); - trySetEnumOpt( forceModels.ode_integrator, force_models, {"ode_integrator" }, E_Integrator::_from_string_nocase); - - for (int i = 0; i < E_ThirdBody::_size(); i++) - { - E_ThirdBody body = E_ThirdBody::_values()[i]; - string bodyName = E_ThirdBody::_names() [i]; boost::algorithm::to_lower(bodyName); - trySetFromYaml(forceModels.process_third_body[body], force_models, {"process_third_body", bodyName }); + { + auto mongo = stringsToYamlObject({yaml, ""}, {"5 mongo"}); + + trySetFromYaml(localMongo.enable, mongo, {"0 enable" }, "(bool) Enable and connect to mongo database"); + trySetFromYaml(localMongo.predict_states, mongo, {"predict_states" }, "(bool) "); + trySetFromYaml(localMongo.output_rtcm_messages, mongo, {"output_rtcm_messages" }, "(bool) Output rtcm data to mongo"); + trySetFromYaml(localMongo.output_measurements, mongo, {"output_measurements" }, "(bool) Output measurements and their residuals"); + trySetFromYaml(localMongo.output_components, mongo, {"output_components" }, "(bool) Output components of measurements"); + trySetFromYaml(localMongo.output_states, mongo, {"output_states" }, "(bool) Output states"); + trySetFromYaml(localMongo.output_trace, mongo, {"output_trace" }, "(bool) Output trace"); + trySetFromYaml(localMongo.output_test_stats, mongo, {"output_test_stats" }, "(bool) Output test statistics"); + trySetFromYaml(localMongo.output_logs, mongo, {"output_logs" }, "(bool) Output console trace and warnings to mongo with timestamps and other metadata"); + trySetFromYaml(localMongo.output_ssr_precursors, mongo, {"output_ssr_precursors" }, "(bool) "); + trySetFromYaml(localMongo.delete_history, mongo, {"delete_history" }, "(bool) Drop the collection in the database at the beginning of the run to only show fresh data"); + trySetFromYaml(localMongo.cull_history, mongo, {"cull_history" }, "(bool) "); + trySetFromYaml(localMongo.min_cull_age, mongo, {"min_cull_age" }, "(float) "); + trySetFromYaml(localMongo.suffix, mongo, {"suffix" }, "(string) Suffix to append to database elements to make distinctions between runs for comparison"); + trySetFromYaml(localMongo.database, mongo, {"database" }, "(string) "); + trySetFromYaml(localMongo.uri, mongo, {"uri" }, "(string) Location and port of the mongo database to connect to"); + + trySetScaledFromYaml(localMongo.prediction_interval, mongo, {"prediction_interval" }, {"interval_units" }, E_Period::_from_string_nocase); + trySetScaledFromYaml(localMongo.forward_prediction_duration, mongo, {"forward_prediction_duration" }, {"duration_units" }, E_Period::_from_string_nocase); + trySetScaledFromYaml(localMongo.reverse_prediction_duration, mongo, {"reverse_prediction_duration" }, {"duration_units" }, E_Period::_from_string_nocase); } - } - - -// trySetFromYaml(split_sys, outputs, { "split_sys" }); - -// trySetFromAny (output_persistance, commandOpts, output_files, {"output_persistance" }); -// trySetFromAny (input_persistance, commandOpts, output_files, {"input_persistance" }); -// trySetFromYaml(persistance_directory, output_files, {"persistance_directory" }); -// trySetFromYaml(persistance_filename, output_files, {"persistance_filename" }); -#endif - - auto estimation_parameters = stringsToYamlObject({yaml, ""}, {estimation_parameters_str}); - { - trySetKalmanFromYaml(pppOpts.eop, estimation_parameters, "eop" ); - trySetKalmanFromYaml(pppOpts.eop_rates, estimation_parameters, "eop_rates" ); - } + { + auto mongo = stringsToYamlObject({yaml, ""}, {"5 remote_mongo"}); + + trySetFromYaml(remoteMongo.enable, mongo, {"0 enable" }, "(bool) Enable and connect to mongo database"); + trySetFromYaml(remoteMongo.predict_states, mongo, {"predict_states" }, "(bool) "); + trySetFromYaml(remoteMongo.output_rtcm_messages, mongo, {"output_rtcm_messages" }, "(bool) Output rtcm data to mongo"); + trySetFromYaml(remoteMongo.output_measurements, mongo, {"output_measurements" }, "(bool) Output measurements and their residuals"); + trySetFromYaml(remoteMongo.output_components, mongo, {"output_components" }, "(bool) Output components of measurements"); + trySetFromYaml(remoteMongo.output_states, mongo, {"output_states" }, "(bool) Output states"); + trySetFromYaml(remoteMongo.output_trace, mongo, {"output_trace" }, "(bool) Output trace"); + trySetFromYaml(remoteMongo.output_test_stats, mongo, {"output_test_stats" }, "(bool) Output test statistics"); + trySetFromYaml(remoteMongo.output_logs, mongo, {"output_logs" }, "(bool) Output console trace and warnings to mongo with timestamps and other metadata"); + trySetFromYaml(remoteMongo.output_ssr_precursors, mongo, {"output_ssr_precursors" }, "(bool) "); + trySetFromYaml(remoteMongo.delete_history, mongo, {"delete_history" }, "(bool) Drop the collection in the database at the beginning of the run to only show fresh data"); + trySetFromYaml(remoteMongo.cull_history, mongo, {"cull_history" }, "(bool) "); + trySetFromYaml(remoteMongo.min_cull_age, mongo, {"min_cull_age" }, "(float) "); + trySetFromYaml(remoteMongo.suffix, mongo, {"suffix" }, "(string) Suffix to append to database elements to make distinctions between runs for comparison"); + trySetFromYaml(remoteMongo.database, mongo, {"database" }, "(string) "); + trySetFromYaml(remoteMongo.uri, mongo, {"uri" }, "(string) Location and port of the mongo database to connect to"); + + trySetScaledFromYaml(remoteMongo.prediction_interval, mongo, {"prediction_interval" }, {"interval_units" }, E_Period::_from_string_nocase); + trySetScaledFromYaml(remoteMongo.forward_prediction_duration, mongo, {"forward_prediction_duration" }, {"duration_units" }, E_Period::_from_string_nocase); + trySetScaledFromYaml(remoteMongo.reverse_prediction_duration, mongo, {"reverse_prediction_duration" }, {"duration_units" }, E_Period::_from_string_nocase); + } - { - auto mongo = stringsToYamlObject({yaml, ""}, {"5 mongo"}); - - trySetFromYaml(enable_mongo, mongo, {"0 enable" }, "(bool) Enable and connect to mongo database"); - trySetFromYaml(output_mongo_rtcm_messages, mongo, {"output_rtcm_messages" }, "(bool) Output rtcm data to mongo"); - trySetFromYaml(output_mongo_measurements, mongo, {"output_measurements" }, "(bool) Output measurements and their residuals"); - trySetFromYaml(output_mongo_states, mongo, {"output_states" }, "(bool) Output states"); - trySetFromYaml(output_mongo_test_stats, mongo, {"output_test_stats" }, "(bool) Output test statistics"); - trySetFromYaml(output_intermediate_rts, mongo, {"output_intermediate_rts" }, "(bool) Output best available smoothed states when performing fixed-lag rts (slow, use only when needed)"); - trySetFromYaml(output_mongo_logs, mongo, {"output_logs" }, "(bool) Output console trace and warnings to mongo with timestamps and other metadata"); - trySetFromYaml(delete_mongo_history, mongo, {"delete_history" }, "(bool) Drop the collection in the database at the beginning of the run to only show fresh data"); - trySetFromYaml(mongo_rts_suffix, mongo, {"rts_suffix" }, "(string) Suffix to append to database elements for reverse smoothed elements"); - trySetFromYaml(mongo_suffix, mongo, {"suffix" }, "(string) Suffix to append to database elements to make distinctions between runs for comparison"); - trySetFromYaml(mongo_database, mongo, {"database" }, "(string) "); - trySetFromYaml(mongo_uri, mongo, {"uri" }, "(string) Location and port of the mongo database to connect to"); - } - - { - auto debug = stringsToYamlObject({yaml, ""}, {"9 debug"}); - - trySetFromYaml(check_plumbing, debug, {"check_plumbing" }, "(bool) Debugging option to show sizes of objects in memory to detect leaks"); - trySetFromYaml(retain_rts_files, debug, {"retain_rts_files" }, "(bool) Debugging option to keep rts files for post processing"); - trySetFromYaml(rts_only, debug, {"rts_only" }, "(bool) Debugging option to only re-run rts from previous run"); - trySetFromYaml(mincon_only, debug, {"mincon_only" }, "(bool) Debugging option to only save and re-run minimum constraints code"); - - auto unit_tests = stringsToYamlObject(debug, {"unit_tests"}); { - trySetFromYaml(testOpts.enable, unit_tests, {"enable" }, "(bool) Perform unit tests while processing"); - - trySetFromYaml(testOpts.output_pass, unit_tests, {"output_pass" }, "(bool) "); - trySetFromYaml(testOpts.stop_on_fail, unit_tests, {"stop_on_fail" }, "(bool) "); - trySetFromYaml(testOpts.stop_on_done, unit_tests, {"stop_on_done" }, "(bool) "); - trySetFromYaml(testOpts.output_errors, unit_tests, {"output_errors" }, "(bool) "); - trySetFromYaml(testOpts.absorb_errors, unit_tests, {"absorb_errors" }, "(bool) "); - - trySetFromYaml(test_directory, unit_tests, {"directory" }); - trySetFromYaml(test_filename, unit_tests, {"filename" }); + auto debug = stringsToYamlObject({yaml, ""}, {"9 debug"}); + + trySetFromYaml(check_plumbing, debug, {"check_plumbing" }, "(bool) Debugging option to show sizes of objects in memory to detect leaks"); + trySetFromYaml(retain_rts_files, debug, {"retain_rts_files" }, "(bool) Debugging option to keep rts files for post processing"); + trySetFromYaml(rts_only, debug, {"rts_only" }, "(bool) Debugging option to only re-run rts from previous run"); + trySetFromYaml(mincon_only, debug, {"mincon_only" }, "(bool) Debugging option to only save and re-run minimum constraints code"); + + auto unit_tests = stringsToYamlObject(debug, {"unit_tests"}); + { + trySetFromYaml(testOpts.enable, unit_tests, {"enable" }, "(bool) Perform unit tests while processing"); + + trySetFromYaml(testOpts.output_pass, unit_tests, {"output_pass" }, "(bool) "); + trySetFromYaml(testOpts.stop_on_fail, unit_tests, {"stop_on_fail" }, "(bool) "); + trySetFromYaml(testOpts.stop_on_done, unit_tests, {"stop_on_done" }, "(bool) "); + trySetFromYaml(testOpts.output_errors, unit_tests, {"output_errors" }, "(bool) "); + trySetFromYaml(testOpts.absorb_errors, unit_tests, {"absorb_errors" }, "(bool) "); + + trySetFromYaml(test_directory, unit_tests, {"directory" }); + trySetFromYaml(test_filename, unit_tests, {"filename" }); + } } } + tryAddRootToPath(root_input_directory, vmf_files); globber(vmf_files); tryAddRootToPath(root_input_directory, atx_files); globber(atx_files); tryAddRootToPath(root_input_directory, snx_files); globber(snx_files); tryAddRootToPath(root_input_directory, blq_files); globber(blq_files); + tryAddRootToPath(root_input_directory, erp_files); globber(erp_files); + tryAddRootToPath(root_input_directory, ion_files); globber(ion_files); tryAddRootToPath(root_input_directory, nav_files); globber(nav_files); tryAddRootToPath(root_input_directory, sp3_files); globber(sp3_files); - tryAddRootToPath(root_input_directory, erp_files); globber(erp_files); tryAddRootToPath(root_input_directory, dcb_files); globber(dcb_files); tryAddRootToPath(root_input_directory, bsx_files); globber(bsx_files); - tryAddRootToPath(root_input_directory, ion_files); globber(ion_files); + tryAddRootToPath(root_input_directory, igrf_files); globber(igrf_files); tryAddRootToPath(root_input_directory, clk_files); globber(clk_files); + tryAddRootToPath(root_input_directory, obx_files); globber(obx_files); tryAddRootToPath(root_input_directory, orb_files); globber(orb_files); + tryAddRootToPath(root_input_directory, sid_files); globber(sid_files); + tryAddRootToPath(root_input_directory, com_files); globber(com_files); + tryAddRootToPath(root_input_directory, crd_files); globber(crd_files); tryAddRootToPath(root_input_directory, egm_files); globber(egm_files); -// tryAddRootToPath(root_input_directory, jpl_files); globber(jpl_files); - tryAddRootToPath(root_input_directory, rnx_files); globber(rnx_files); - tryAddRootToPath(root_input_directory, obs_rtcm_files); globber(obs_rtcm_files); - tryAddRootToPath(root_input_directory, nav_rtcm_files); globber(nav_rtcm_files); - tryAddRootToPath(root_input_directory, pseudoobs_files); globber(pseudoobs_files); - - tryAddRootToPath(root_input_directory, model.trop.vmf3dir); - tryAddRootToPath(root_input_directory, model.trop.orography); - tryAddRootToPath(root_input_directory, model.trop.gpt2grid); + tryAddRootToPath(root_input_directory, jpl_files); globber(jpl_files); + tryAddRootToPath(root_input_directory, tide_files); globber(tide_files); + + globber(rnx_inputs); + globber(ubx_inputs); + globber(obs_rtcm_inputs); + globber(nav_rtcm_inputs); + globber(pseudo_sp3_inputs); + globber(pseudo_snx_inputs); + + tryAddRootToPath(root_input_directory, model.trop.orography); + tryAddRootToPath(root_input_directory, model.trop.gpt2grid); - string revert = trace_directory; + string revert_trace = trace_directory; + string revert_orbits = orbits_directory; tryPatchPaths(root_output_directory, erp_directory, erp_filename); tryPatchPaths(root_output_directory, gpx_directory, gpx_filename); tryPatchPaths(root_output_directory, log_directory, log_filename); + tryPatchPaths(root_output_directory, cost_directory, cost_filename); tryPatchPaths(root_output_directory, test_directory, test_filename); tryPatchPaths(root_output_directory, sinex_directory, sinex_filename); tryPatchPaths(root_output_directory, ionex_directory, ionex_filename); - tryPatchPaths(root_output_directory, orbits_directory, orbits_filename); + tryPatchPaths(root_output_directory, orbex_directory, orbex_filename); + tryPatchPaths(root_output_directory, orbits_directory, orbits_filename); orbits_directory = revert_orbits; tryPatchPaths(root_output_directory, clocks_directory, clocks_filename); + tryPatchPaths(root_output_directory, slr_obs_directory, slr_obs_filename); tryPatchPaths(root_output_directory, ionstec_directory, ionstec_filename); tryPatchPaths(root_output_directory, ppp_sol_directory, ppp_sol_filename); + tryPatchPaths(root_output_directory, raw_ubx_directory, raw_ubx_filename); tryPatchPaths(root_output_directory, rtcm_nav_directory, rtcm_nav_filename); tryPatchPaths(root_output_directory, rtcm_obs_directory, rtcm_obs_filename); + tryPatchPaths(root_output_directory, orbit_ics_directory, orbit_ics_filename); + tryPatchPaths(root_output_directory, ntrip_log_directory, ntrip_log_filename); tryPatchPaths(root_output_directory, rinex_obs_directory, rinex_obs_filename); tryPatchPaths(root_output_directory, rinex_nav_directory, rinex_nav_filename); + tryPatchPaths(root_output_directory, orbits_directory, predicted_orbits_filename); tryPatchPaths(root_output_directory, bias_sinex_directory, bias_sinex_filename); tryPatchPaths(root_output_directory, trop_sinex_directory, trop_sinex_filename); tryPatchPaths(root_output_directory, persistance_directory, persistance_filename); tryPatchPaths(root_output_directory, pppOpts.rts_directory, pppOpts.rts_filename); - tryPatchPaths(root_output_directory, trace_directory, station_trace_filename); trace_directory = revert; + tryPatchPaths(root_output_directory, trace_directory, satellite_trace_filename); trace_directory = revert_trace; + tryPatchPaths(root_output_directory, trace_directory, station_trace_filename); trace_directory = revert_trace; tryPatchPaths(root_output_directory, trace_directory, network_trace_filename); tryPatchPaths(root_output_directory, decoded_rtcm_json_directory, decoded_rtcm_json_filename); tryPatchPaths(root_output_directory, encoded_rtcm_json_directory, encoded_rtcm_json_filename); @@ -2187,6 +2767,7 @@ bool ACSConfig::parse( replaceTags(orb_files); replaceTags(sp3_files); replaceTags(clk_files); + replaceTags(obx_files); replaceTags(atx_files); replaceTags(snx_files); replaceTags(blq_files); @@ -2195,62 +2776,28 @@ bool ACSConfig::parse( replaceTags(bsx_files); replaceTags(ion_files); replaceTags(egm_files); + replaceTags(sid_files); + replaceTags(com_files); + replaceTags(crd_files); replaceTags(jpl_files); - replaceTags(rnx_files); - replaceTags(obs_rtcm_files); - replaceTags(nav_rtcm_files); - replaceTags(pseudoobs_files); - - replaceTags(root_stations_dir); - replaceTags(gnss_data_root_url); - replaceTags(ephemeris_data_root_url); - replaceTags(mongo_suffix); - replaceTags(mongo_database); + replaceTags(rnx_inputs); + replaceTags(ubx_inputs); + replaceTags(obs_rtcm_inputs); + replaceTags(nav_rtcm_inputs); + replaceTags(pseudo_sp3_inputs); + replaceTags(pseudo_snx_inputs); - for (auto& station_file : station_files) - { - replaceTags(station_file); - } + replaceTags(localMongo.suffix); + replaceTags(localMongo.database); - for (auto nav : {false, true}) - { - vector* streamNode_ptr; - string stream_root; - if (nav == false) { streamNode_ptr = &gnssDataStreams; stream_root = gnss_data_root_url; } - else { streamNode_ptr = &ephemerisDataStreams; stream_root = ephemeris_data_root_url; } - - map ntripStreams; - for (auto streamUrl : *streamNode_ptr) - { - string fullUrl = streamUrl; - - if (fullUrl.find(':') == std::string::npos) - { - //only add root if it looks like it doesnt have one (eg https':'//) - tryAddRootToPath(stream_root, fullUrl); - } - - replaceTags(fullUrl); - - while (fullUrl.back() == '/') - fullUrl.pop_back(); // in case of terminating '/' - - std::size_t slashPos = fullUrl.find_last_of("/"); // find first 4 characters after last '/' - string hostname = fullUrl.substr(0,slashPos+1); // e.g. http://user:pass@auscors.ga.gov.au:2101/BCEP00BKG0 --> BCEP - - pppOpts.download_hosts.insert(hostname); - - if (nav == false) pppOpts.obs_mount_url.insert(fullUrl); - else pppOpts.nav_mount_url.insert(fullUrl); - } - } - - SatSys dummySat; + replaceTags(remoteMongo.suffix); + replaceTags(remoteMongo.database); + + SatSys dummySat; auto satOpts = getSatOpts(dummySat); - auto recOpts = getRecOpts ("XMPL"); - auto minOpts = getMinConOpts("XMPL"); + auto recOpts = getRecOpts("XMPL"); # ifndef ENABLE_UNIT_TESTS @@ -2262,7 +2809,10 @@ bool ACSConfig::parse( } # endif - recurseYaml(yaml); + for (auto& yaml : yamls) + { + recurseYaml(yaml); + } if (commandOpts.count("yaml-defaults")) { diff --git a/src/cpp/common/acsConfig.hpp b/src/cpp/common/acsConfig.hpp index ff38e353e..e43f75417 100644 --- a/src/cpp/common/acsConfig.hpp +++ b/src/cpp/common/acsConfig.hpp @@ -1,6 +1,5 @@ -#ifndef ACS_CONFIG_H -#define ACS_CONFIG_H +#pragma once #include #include @@ -14,22 +13,22 @@ #include #include #include +#include #include #include -#include #include #include using std::vector; using std::string; using std::tuple; +using std::mutex; using std::array; -using std::list; using std::map; using std::set; -#include "streamTrace.hpp" #include "satSys.hpp" +#include "trace.hpp" #include "enums.h" @@ -37,6 +36,40 @@ using std::set; #define D2R (PI/180.0) ///< deg to rad #define R2D (180.0/PI) ///< rad to deg +template +void setInited( + BASE& base, + COMP& comp, + bool init = true) +{ + if (init == false) + { + return; + } + + int offset = (char*)(&comp) - (char*)(&base); + + base.initialisedMap[offset] = true; +} + +template +bool isInited( + const BASE& base, + const COMP& comp) +{ + int offset = (char*)(&comp) - (char*)(&base); + + auto it = base.initialisedMap.find(offset); + if (it == base.initialisedMap.end()) + { + return false; + } + + auto [dummy, inited] = *it; + + return inited; +} + /** Input source filenames and directories */ struct InputOptions @@ -49,21 +82,30 @@ struct InputOptions vector orb_files; vector sp3_files; vector clk_files; + vector obx_files; + vector sid_files; + vector com_files; + vector crd_files; + vector vmf_files; vector erp_files; vector dcb_files; vector bsx_files; vector ion_files; - - vector rnx_files; - vector obs_rtcm_files; - vector nav_rtcm_files; - vector pseudoobs_files; + vector igrf_files; + + vector rnx_inputs; + vector ubx_inputs; + vector obs_rtcm_inputs; + vector nav_rtcm_inputs; + vector pseudo_sp3_inputs; + vector pseudo_snx_inputs; - vector egm_files; - vector jpl_files; + vector atm_reg_definitions; - string root_stations_dir = "./"; + vector egm_files; + vector jpl_files; + vector tide_files; string stream_user = ""; string stream_pass = ""; @@ -84,53 +126,77 @@ struct IonexOptions */ struct OutputOptions { - int trace_level = 0; int fatal_level = 0; + double rotate_period = 60*60*24; + + int trace_level = 0; bool output_station_trace = false; bool output_network_trace = false; + bool output_satellite_trace = false; + bool output_json_trace = false; string trace_directory = "./"; - string station_trace_filename = ".trace"; - string network_trace_filename = ".trace"; - double rotate_period = 60*60*24; + string station_trace_filename = "-.trace"; + string network_trace_filename = "-.trace"; + string satellite_trace_filename = "-.trace"; + + bool record_raw_ubx = false; + string raw_ubx_directory = "./"; + string raw_ubx_filename = "--OBS.rtcm"; bool record_rtcm_obs = false; bool record_rtcm_nav = false; string rtcm_obs_directory = "./"; string rtcm_nav_directory = "./"; - string rtcm_obs_filename = "-OBS.rtcm3"; - string rtcm_nav_filename = "-NAV.rtcm3"; + string rtcm_obs_filename = "--OBS.rtcm"; + string rtcm_nav_filename = "--NAV.rtcm"; bool output_log = false; string log_directory = "./"; - string log_filename = "log.json"; + string log_filename = "log-.json"; + + bool output_ntrip_log = false; + string ntrip_log_directory = "./"; + string ntrip_log_filename = "ntrip_log-.json"; bool output_gpx = false; string gpx_directory = "./"; - string gpx_filename = ".gpx"; + string gpx_filename = "-.gpx"; bool output_residuals = false; bool output_residual_chain = true; bool output_config = false; - bool output_clocks = false; - E_Ephemeris clocks_receiver_source = E_Ephemeris::KALMAN; - E_Ephemeris clocks_satellite_source = E_Ephemeris::KALMAN; - string clocks_directory = "./"; - string clocks_filename = "pea_.clk"; - bool output_ar_clocks = false; //todo aaron this config sucks - - bool output_orbits = false; - bool output_orbit_velocities = false; - E_Ephemeris orbits_data_source = E_Ephemeris::BROADCAST; - string orbits_directory = "./"; - string orbits_filename = "pea_.sp3"; + bool output_clocks = false; + vector clocks_receiver_sources = {E_Source::KALMAN}; + vector clocks_satellite_sources = {E_Source::KALMAN}; + string clocks_directory = "./"; + string clocks_filename = "-_.clk"; + bool output_ar_clocks = false; //todo aaron this config sucks + + bool output_orbits = false; + bool output_predicted_orbits = false; + bool output_inertial_orbits = false; + bool output_orbit_velocities = false; + vector orbits_data_sources = {E_Source::BROADCAST}; + int orbits_output_interval = 900; + string orbits_directory = "./"; + string orbits_filename = "-_-Filt.sp3"; + string predicted_orbits_filename = "-_-Prop.sp3"; + bool output_orbex = false; + vector orbex_orbit_sources = {E_Source::BROADCAST}; + vector orbex_clock_sources = {E_Source::BROADCAST}; + vector orbex_attitude_sources = {E_Source::NOMINAL}; + string orbex_directory = "./"; + string orbex_filename = "-_.obx"; + vector orbex_record_types = { "ATT" }; + bool split_sys = false; bool output_rinex_obs = false; string rinex_obs_directory = "./"; - string rinex_obs_filename = "__.O"; + string rinex_obs_filename = "-_.O"; double rinex_obs_version = 3.05; bool rinex_obs_print_C_code = true; bool rinex_obs_print_L_code = true; @@ -139,57 +205,76 @@ struct OutputOptions bool output_ppp_sol = false; string ppp_sol_directory = "./"; - string ppp_sol_filename = "pea.pppsol"; + string ppp_sol_filename = ".pppsol"; bool output_ionex = false; string ionex_directory = "./"; - string ionex_filename = "pea.ionex"; + string ionex_filename = "-.INX"; IonexOptions ionexGrid; bool output_rinex_nav = false; string rinex_nav_directory = "./"; - string rinex_nav_filename = "_nav_.rnx"; + string rinex_nav_filename = "-_nav_.rnx"; double rinex_nav_version = 3.05; bool output_ionstec = false; string ionstec_directory = "./"; - string ionstec_filename = "pea.STEC"; + string ionstec_filename = "-.STEC"; bool output_erp = false; string erp_directory = "./"; - string erp_filename = "pea.ERP"; - - bool output_bias_sinex = false; - string bias_sinex_directory = "./"; - string bias_sinex_filename = "AUS0ACSRAP_00_01D_30S_ABS.BIA"; + string erp_filename = "-.ERP"; + + bool output_bias_sinex = false; + string bias_sinex_directory = "./"; + string bias_sinex_filename = "-.BIA"; + + bool output_sinex = false; + string sinex_directory = "./"; + string sinex_filename = "-.snx"; + + bool output_trop_sinex = false; + vector trop_sinex_data_sources = {E_Source::KALMAN}; + string trop_sinex_directory = "./"; + string trop_sinex_filename = "-.tro"; + string trop_sinex_sol_type = "Solution parameters"; + char trop_sinex_obs_code = 'P'; + char trop_sinex_const_code = ' '; + double trop_sinex_version = 2.0; + + + bool output_cost = false; + vector cost_data_sources = {E_Source::KALMAN}; + string cost_directory = "./"; + string cost_filename = "cost_s_t___ga__.dat"; + int cost_time_interval = 900; + string cost_format = "COST-716 V2.2"; + string cost_project = "GA-NRT"; + string cost_status = "TEST"; + string cost_centre = "GA__ Geoscience Aus"; + string cost_method = "GINAN V2"; + string cost_orbit_type = "IGSPRE"; + string cost_met_source = "NONE"; - bool output_sinex = false; - string sinex_directory = "./"; - string sinex_filename = ".snx"; - - bool output_trop_sinex = false; - E_Ephemeris trop_data_source = E_Ephemeris::KALMAN; - string trop_sinex_directory = "./"; - string trop_sinex_filename = ".tro"; bool output_persistance = false; bool input_persistance = false; string persistance_directory = "./"; - string persistance_filename = ".persist"; - - bool enable_mongo = false; - bool output_mongo_rtcm_messages = false; - bool output_mongo_measurements = false; - bool output_mongo_states = false; - bool output_mongo_test_stats = false; - bool output_intermediate_rts = false; - bool output_mongo_logs = false; - bool delete_mongo_history = false; - string mongo_rts_suffix = "~"; - string mongo_uri = "mongodb://localhost:27017"; - string mongo_suffix = ""; - string mongo_database = ""; + string persistance_filename = ".persist"; + + bool output_slr_obs = false; + string slr_obs_directory = "./"; + string slr_obs_filename = ".slr_obs"; + + bool output_orbit_ics = false; + string orbit_ics_directory = "./"; + string orbit_ics_filename = "--orbits.yaml"; + + bool enable_binary_store = false; + bool store_binary_states = false; + bool store_binary_measurements = false; + void defaultOutputOptions() { *this = OutputOptions(); @@ -197,17 +282,17 @@ struct OutputOptions bool output_decoded_rtcm_json = false; string decoded_rtcm_json_directory = "./"; - string decoded_rtcm_json_filename = "___decoded_rtcm.json"; + string decoded_rtcm_json_filename = "-_rtcm_decoded.json"; bool output_encoded_rtcm_json = false; string encoded_rtcm_json_directory = "./"; - string encoded_rtcm_json_filename = "___encoded_rtcm.json"; + string encoded_rtcm_json_filename = "-_rtcm_encoded.json"; - bool output_network_statistics_json = false; + bool output_network_statistics_json = false; string network_statistics_json_directory = "./"; - string network_statistics_json_filename = "_network_statistics.json"; + string network_statistics_json_filename = "-_network_statistics.json"; - string test_filename = "testData"; + string test_filename = "-testData"; string test_directory = "./"; }; @@ -235,6 +320,13 @@ struct TestOptions bool absorb_errors = false; }; +/** Options for processing SLR observations +*/ +struct SlrOptions +{ + bool process_slr = false; +}; + struct Enable { bool enable = true; @@ -242,12 +334,12 @@ struct Enable struct ModelSatPos : Enable { - E_Ephemeris ephemeris_source = E_Ephemeris::PRECISE; + vector ephemeris_sources = {E_Source::KALMAN, E_Source::PRECISE, E_Source::BROADCAST}; }; struct ModelClk : Enable { - E_Ephemeris ephemeris_source = E_Ephemeris::PRECISE; + vector ephemeris_sources = {E_Source::KALMAN, E_Source::PRECISE, E_Source::BROADCAST}; }; struct ModelRecPos : Enable{}; @@ -265,12 +357,20 @@ struct ModelTides : Enable struct ModelTrop : Enable { E_TropModel model = E_TropModel::VMF3; - - string vmf3dir; + string orography; string gpt2grid; }; +/** Options for modelling attitude +*/ +struct ModelAtt : Enable +{ + vector sources = {E_Source::PRECISE, E_Source::MODEL, E_Source::NOMINAL}; + double valid_var = 0.01; + double invalid_var = 1; +}; + struct Model { ModelRecPos rec_pos; @@ -279,6 +379,8 @@ struct Model ModelClk rec_clock; ModelTrop trop; ModelTides tides; + ModelAtt sat_attitude; + ModelAtt rec_attitude; bool range = true; @@ -297,11 +399,17 @@ struct Model bool relativity2 = true; bool sagnac = true; bool phase_windup = true; + bool heading = true; bool integer_ambiguity = true; bool ionospheric_component = true; - + bool ionospheric_component2 = false; + bool ionospheric_component3 = false; + bool eop = true; + bool clock_definitions = true; bool ionospheric_model = false; + + bool orbits = true; }; /** Options for the general operation of the software @@ -311,7 +419,9 @@ struct GlobalOptions Model model; double epoch_interval = 1; + double epoch_tolerance = 0.5; int max_epochs = 0; + int leap_seconds = -1; boost::posix_time::ptime start_epoch { boost::posix_time::not_a_date_time }; boost::posix_time::ptime end_epoch { boost::posix_time::not_a_date_time }; @@ -319,10 +429,13 @@ struct GlobalOptions string config_description = "Pea"; string analysis_agency = "GAA"; string analysis_center = "Geoscience Australia"; - string analysis_program = "AUSACS"; - string rinex_comment = "AUSNETWORK1"; + string analysis_program = "Ginan"; + string analysis_program_version = "2.0"; + string ac_contact = "clientservices@ga.gov.au"; + string rinex_comment = "Daily 30-sec observations from IGS stations"; string reference_system = "igb14"; string time_system = "G"; + string bias_time_system = "G"; string ocean_tide_loading_model = "FES2004"; string atmospheric_tide_loading_model = "---"; string geoid_model = "EGM96"; @@ -331,6 +444,7 @@ struct GlobalOptions bool simulate_real_time = false; bool process_preprocessor = true; + bool process_spp = true; bool process_user = false; bool process_network = false; bool process_minimum_constraints = false; @@ -341,42 +455,58 @@ struct GlobalOptions map process_sys; map solve_amb_for; - map> process_freq; bool process_meas[NUM_MEAS_TYPES] = {true, true}; + map reject_eclipse; double elevation_mask = 10 * D2R; + + string pivot_station = "NO_PIVOT"; - string pivot_station = ""; - - - bool reject_eclipse = true; - bool raim = true; - bool interpolate_rec_pco = true; + bool raim = true; + bool interpolate_rec_pco = true; + bool require_apriori_positions = false; + bool require_antenna_details = false; double thres_slip = 0.05; double mw_proc_noise = 0; double max_gdop = 30; double deweight_factor = 100; - - double wait_next_epoch = 0; - double wait_all_stations = 0; - bool require_obs = true; - bool delete_old_ephemerides = false; + double no_bias_sigma = 20; + + double orbit_pos_proc_noise = 10; + double orbit_vel_proc_noise = 5; + double orbit_vel_proc_noise_trail = 1; + double orbit_vel_proc_noise_trail_tau = 0.05; - bool reinit_on_all_slips = false; - bool reinit_on_clock_error = false; - bool deweight_on_state_error = false; + + double wait_next_epoch = 0; + double wait_all_stations = 0; + bool require_obs = true; + bool assign_closest_epoch = false; + + bool delete_old_ephemerides = false; + + bool reinit_on_all_slips = false; + bool reinit_on_clock_error = false; + bool deweight_on_state_error = false; bool joseph_stabilisation = false; double validity_interval_factor = 100; - list station_files; - E_OffsetType ssr_input_antenna_offset = E_OffsetType::UNSPECIFIED; - bool if_antenna_phase_centre = true; map> code_priorities; + map> zero_code_average; + map> zero_phas_average; + map used_nav_types = ///< Default observation codes on L1 for IF combination based satellite clocks + { + {E_Sys::GPS, E_NavMsgType::LNAV}, + {E_Sys::GLO, E_NavMsgType::FDMA}, + {E_Sys::GAL, E_NavMsgType::INAV}, + {E_Sys::BDS, E_NavMsgType::D1}, + {E_Sys::QZS, E_NavMsgType::LNAV} + }; vector code_priorities_default = { @@ -406,33 +536,45 @@ struct GlobalOptions E_ObsCode::L5X }; - map clock_codesL1 = ///< Default observation codes on L1 for IF combination based satellite clocks + map clock_codesL1 = ///< Default observation codes on first frequency for IF combination based satellite clocks { {E_Sys::GPS, E_ObsCode::L1W}, {E_Sys::GLO, E_ObsCode::L1P}, {E_Sys::GAL, E_ObsCode::L1C}, {E_Sys::BDS, E_ObsCode::L2I}, - {E_Sys::QZS, E_ObsCode::L1C} + {E_Sys::QZS, E_ObsCode::L1C}, + {E_Sys::SBS, E_ObsCode::L1C} }; - map clock_codesL2 = ///< Default observation codes on L2 for IF combination based satellite clocks + map clock_codesL2 = ///< Default observation codes on second frequency for IF combination based satellite clocks { {E_Sys::GPS, E_ObsCode::L2W}, {E_Sys::GLO, E_ObsCode::L2P}, {E_Sys::GAL, E_ObsCode::L5Q}, - {E_Sys::BDS, E_ObsCode::L7I}, - {E_Sys::QZS, E_ObsCode::L2L} + {E_Sys::BDS, E_ObsCode::L6I}, + {E_Sys::QZS, E_ObsCode::L2L}, + {E_Sys::SBS, E_ObsCode::L5I} }; - bool dumb_sat_pco = true; - bool dumb_rec_pco = false; + E_Sys receiver_reference_clk = E_Sys::NONE; + double fixed_phase_bias_var = 0.01; + + bool sat_clk_definition = false; + map zero_receiver_dcb; ///< set receiver DCBs to 0 + map zero_satellite_dcb; ///< set satellite DCBs to 0 + map one_phase_bias; ///< use common phase bias for frequency + map receiver_amb_pivot; ///< fix one ambiguity to eliminate rank deficiency + map network_amb_pivot; ///< fix ambiguities to eliminate network rank deficiencies + map use_for_iono_model; ///< use system for ionospheric modelling + map use_iono_corrections; ///< use system for ionospheric modelling + + bool common_sat_pco = false; + bool common_rec_pco = false; double clock_wrap_threshold = 0.05e-3; //to be removed? - - double proc_noise_iono = 0.001; //todo aaron, these need values, or move to other type double predefined_fail = 0.001; /* pre-defined fail-rate (0.01,0.001) */ }; @@ -447,46 +589,63 @@ struct KalmanModel vector tau = {-1}; //tau<0 (inf): Random Walk model; tau>0: First Order Gauss Markov model vector mu = {0}; vector estimate = {false}; + vector comment = {""}; + + KalmanModel& operator+=( + const KalmanModel& rhs) + { + if (isInited(rhs, rhs.sigma )) { sigma = rhs.sigma ; setInited(*this, sigma ); } + if (isInited(rhs, rhs.apriori_val )) { apriori_val = rhs.apriori_val ; setInited(*this, apriori_val); } + if (isInited(rhs, rhs.proc_noise )) { proc_noise = rhs.proc_noise ; setInited(*this, proc_noise ); } + if (isInited(rhs, rhs.tau )) { tau = rhs.tau ; setInited(*this, tau ); } + if (isInited(rhs, rhs.mu )) { mu = rhs.mu ; setInited(*this, mu ); } + if (isInited(rhs, rhs.estimate )) { estimate = rhs.estimate ; setInited(*this, estimate ); } + if (isInited(rhs, rhs.comment )) { comment = rhs.comment ; setInited(*this, comment ); } + + return *this; + } + + map initialisedMap; }; struct FilterOptions { - int phase_reject_limit = 10; - int outage_reset_limit = 10; + int phase_reject_limit = 10; + int outage_reset_limit = 10; - bool sigma_check = true; - bool w_test = false; - bool chi_square_test = false; - E_ChiSqMode chi_square_mode = E_ChiSqMode::NONE; - double sigma_threshold = 4; - - int max_filter_iter = 2; - int max_prefit_remv = 2; + bool sigma_check = true; + bool w_test = false; + bool chi_square_test = false; + bool simulate_filter_only = false; + bool simulate_pseudos_only = false; + E_ChiSqMode chi_square_mode = E_ChiSqMode::NONE; + double sigma_threshold = 4; + + int max_filter_iter = 2; + int max_prefit_remv = 2; - string rts_filename = "Filter-.rts"; - string rts_directory = "./"; - int rts_lag = -1; + string rts_filename = "Filter--.rts"; + string rts_directory = "./"; + int rts_lag = -1; + string rts_smoothed_suffix = "_smoothed"; + bool output_intermediate_rts = false; - E_Inverter inverter = E_Inverter::LDLT; + E_Inverter rts_inverter = E_Inverter::LDLT; + E_Inverter inverter = E_Inverter::LDLT; }; -/** Options associated with the network processing mode of operation +/** Options associated with the ppp processing mode of operation */ -struct NetworkOptions : FilterOptions +struct PPPOptions : FilterOptions { - NetworkOptions() - { - rts_filename = "Network.rts"; - } - KalmanModel eop; KalmanModel eop_rates; - - set download_hosts; - set nav_mount_url; - set obs_mount_url; - bool chunk_stations = false; + bool common_atmosphere = false; + bool use_rtk_combo = false; + + bool satellite_chunking = false; + bool station_chunking = false; int chunk_size = 0; }; @@ -496,8 +655,11 @@ struct IonosphericOptions { E_IonoMode corr_mode = E_IonoMode::IONO_FREE_LINEAR_COMBO; E_LinearCombo iflc_freqs = E_LinearCombo::ANY; + E_IonoMapFn mapping_function = E_IonoMapFn::MSLM; - bool common_ionosphere = false; + double pierce_point_layer_height = 450; + double mapping_function_layer_height = 506.7; + bool common_ionosphere = true; bool use_if_combo = false; bool auto_select_default_code = false; }; @@ -507,8 +669,6 @@ struct SlipOptions bool LLI = true; bool GF = true; bool MW = true; - bool EMW = true; - bool CJ = true; bool SCDIA = true; }; @@ -517,24 +677,27 @@ struct IonModelOptions E_IonoModel model = E_IonoModel::NONE; int NBasis; int function_order; - double model_noise; + int function_degree; + vector layer_heights; + bool estimate_sat_dcb = true; + bool use_rotation_mtx = false; KalmanModel ion; }; struct AmbROptions { - E_ARmode WLmode = E_ARmode::OFF; ///< Ambiguity resolution mode: OFF, ROUND, ITER_RND, BOOTST, LAMBDA - E_ARmode NLmode = E_ARmode::OFF; ///< Ambiguity resolution mode: OFF, ROUND, ITER_RND, BOOTST, LAMBDA + E_ARmode WLmode = E_ARmode::OFF; + E_ARmode NLmode = E_ARmode::OFF; int lambda_set = 2; int AR_max_itr = 1; - double min_el_AR = 15; ///< minimum elevation to attempt ambigity resolution (degrees) + double min_el_AR = 15; int Max_Hold_epoc = 0; double Max_Hold_time = 1200; - double WLsuccsThres = 0.9999; ///< Thresholds for ambiguity validation: succsess rate WL - double WLratioThres = 3; ///< Thresholds for ambiguity validation: succsess rate WL + double WLsuccsThres = 0.9999; + double WLratioThres = 3; int WL_filter_iter = 2; int WL_prefit_remv = 2; @@ -545,68 +708,325 @@ struct AmbROptions double NLratioThres = 3; ///< Thresholds for ambiguity validation: succsess rate NL double NLstarttime = 3600; ///< Time before starting to calculate (and output NL zmbiguities/biases) - double biasOutrate = 0; ///< Update interval for clock update 0: no output + double code_output_interval = 0; ///< Update interval for code biases, 0: no output + double phase_output_interval = 0; ///< Update interval for phase biases, 0: no output + bool output_rec_bias = false; ///< Output receivr bias int reduction_limit = 5000; }; +/** Rinex 2 conversions for individual receivers +*/ +struct Rinex23Conversion +{ + map> codeConv = + { + {E_Sys::GPS,{ + {E_ObsCode2::P1, E_ObsCode::L1W}, + {E_ObsCode2::P2, E_ObsCode::L2W}, + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5X}, + {E_ObsCode2::L1, E_ObsCode::L1W}, + {E_ObsCode2::L2, E_ObsCode::L2C}, + {E_ObsCode2::L5, E_ObsCode::L5X}} + }, + + {E_Sys::GAL,{ + {E_ObsCode2::P1, E_ObsCode::L1P}, + {E_ObsCode2::P2, E_ObsCode::L2P}, + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::C7, E_ObsCode::L7Q}, + {E_ObsCode2::C8, E_ObsCode::L8Q}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2P}, + {E_ObsCode2::L5, E_ObsCode::L5I}, + {E_ObsCode2::L7, E_ObsCode::L7Q}, + {E_ObsCode2::L8, E_ObsCode::L8Q}} + }, + + {E_Sys::GLO,{ + {E_ObsCode2::P1, E_ObsCode::L1P}, + {E_ObsCode2::P2, E_ObsCode::L2P}, + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C3, E_ObsCode::L3Q}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2P}, + {E_ObsCode2::L3, E_ObsCode::L3Q}, + {E_ObsCode2::L5, E_ObsCode::L5I}} + }, + + {E_Sys::BDS,{ + {E_ObsCode2::C2, E_ObsCode::L2I}, + {E_ObsCode2::C6, E_ObsCode::L6I}, + {E_ObsCode2::C7, E_ObsCode::L7I}, + {E_ObsCode2::C8, E_ObsCode::L8X}, + {E_ObsCode2::L2, E_ObsCode::L2X}, + {E_ObsCode2::L6, E_ObsCode::L6I}, + {E_ObsCode2::L7, E_ObsCode::L7I}, + {E_ObsCode2::L8, E_ObsCode::L8X}} + }, + + {E_Sys::QZS,{ + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::C6, E_ObsCode::L6X}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2C}, + {E_ObsCode2::L5, E_ObsCode::L5I}, + {E_ObsCode2::L6, E_ObsCode::L6X}} + }, + + {E_Sys::SBS,{ + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2C}, + {E_ObsCode2::L5, E_ObsCode::L5I}} + } + }; + + map> phasConv = + { + {E_Sys::GPS,{ + {E_ObsCode2::P1, E_ObsCode::L1W}, + {E_ObsCode2::P2, E_ObsCode::L2W}, + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5X}, + {E_ObsCode2::L1, E_ObsCode::L1W}, + {E_ObsCode2::L2, E_ObsCode::L2C}, + {E_ObsCode2::L5, E_ObsCode::L5X}} + }, + + {E_Sys::GAL,{ + {E_ObsCode2::P1, E_ObsCode::L1P}, + {E_ObsCode2::P2, E_ObsCode::L2P}, + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::C7, E_ObsCode::L7Q}, + {E_ObsCode2::C8, E_ObsCode::L8Q}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2P}, + {E_ObsCode2::L5, E_ObsCode::L5I}, + {E_ObsCode2::L7, E_ObsCode::L7Q}, + {E_ObsCode2::L8, E_ObsCode::L8Q}} + }, + + {E_Sys::GLO,{ + {E_ObsCode2::P1, E_ObsCode::L1P}, + {E_ObsCode2::P2, E_ObsCode::L2P}, + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C3, E_ObsCode::L3Q}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2P}, + {E_ObsCode2::L3, E_ObsCode::L3Q}, + {E_ObsCode2::L5, E_ObsCode::L5I}} + }, + + {E_Sys::BDS,{ + {E_ObsCode2::C2, E_ObsCode::L2I}, + {E_ObsCode2::C6, E_ObsCode::L6I}, + {E_ObsCode2::C7, E_ObsCode::L7I}, + {E_ObsCode2::C8, E_ObsCode::L8X}, + {E_ObsCode2::L2, E_ObsCode::L2I}, + {E_ObsCode2::L6, E_ObsCode::L6I}, + {E_ObsCode2::L7, E_ObsCode::L7I}, + {E_ObsCode2::L8, E_ObsCode::L8X}} + }, + + {E_Sys::QZS,{ + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::C6, E_ObsCode::L6X}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2C}, + {E_ObsCode2::L5, E_ObsCode::L5I}, + {E_ObsCode2::L6, E_ObsCode::L6X}} + }, + + {E_Sys::SBS,{ + {E_ObsCode2::C1, E_ObsCode::L1C}, + {E_ObsCode2::C2, E_ObsCode::L2C}, + {E_ObsCode2::C5, E_ObsCode::L5I}, + {E_ObsCode2::L1, E_ObsCode::L1C}, + {E_ObsCode2::L2, E_ObsCode::L2C}, + {E_ObsCode2::L5, E_ObsCode::L5I}} + } + }; +}; + + /** Options to be applied to kalman filter states for individual satellites */ struct SatelliteOptions { - bool _initialised = false; - bool exclude = false; - - KalmanModel clk; - KalmanModel clk_rate; - KalmanModel clk_rate_gauss_markov; - KalmanModel orbit; - KalmanModel srp; - KalmanModel pos; - KalmanModel pos_rate; - KalmanModel orb; - KalmanModel pco; - KalmanModel ant; - KalmanModel code_bias; - KalmanModel phase_bias; + bool _initialised = false; + + KalmanModel clk; + KalmanModel clk_rate; + KalmanModel orbit; + KalmanModel srp; + KalmanModel pos; + KalmanModel pos_rate; + KalmanModel orb; + KalmanModel pco; + KalmanModel ant; + KalmanModel code_bias; + KalmanModel phase_bias; + KalmanModel ion_model; + KalmanModel emp_dyb_0; + KalmanModel emp_dyb_1c; + KalmanModel emp_dyb_1s; + KalmanModel emp_dyb_2c; + KalmanModel emp_dyb_2s; + KalmanModel emp_dyb_3c; + KalmanModel emp_dyb_3s; + KalmanModel emp_dyb_4c; + KalmanModel emp_dyb_4s; + + bool exclude = false; + vector code_sigmas = {0}; + vector phas_sigmas = {0}; + vector laser_sigmas = {0}; + + Vector3d antenna_boresight = { 0, 0, +1}; + Vector3d antenna_azimuth = { 0, +1, 0}; + + SatelliteOptions& operator+=( + const SatelliteOptions& rhs) + { + clk += rhs.clk; + clk_rate += rhs.clk_rate; + orbit += rhs.orbit; + srp += rhs.srp; + pos += rhs.pos; + pos_rate += rhs.pos_rate; + orb += rhs.orb; + pco += rhs.pco; + ant += rhs.ant; + code_bias += rhs.code_bias; + phase_bias += rhs.phase_bias; + ion_model += rhs.ion_model; + emp_dyb_0 += rhs.emp_dyb_0; + emp_dyb_1c += rhs.emp_dyb_1c; + emp_dyb_1s += rhs.emp_dyb_1s; + emp_dyb_2c += rhs.emp_dyb_2c; + emp_dyb_2s += rhs.emp_dyb_2s; + emp_dyb_3c += rhs.emp_dyb_3c; + emp_dyb_3s += rhs.emp_dyb_3s; + emp_dyb_4c += rhs.emp_dyb_4c; + emp_dyb_4s += rhs.emp_dyb_4s; + + if (isInited(rhs, rhs.exclude )) { exclude = rhs.exclude ; setInited(*this, exclude ); } + if (isInited(rhs, rhs.code_sigmas )) { code_sigmas = rhs.code_sigmas ; setInited(*this, code_sigmas ); } + if (isInited(rhs, rhs.phas_sigmas )) { phas_sigmas = rhs.phas_sigmas ; setInited(*this, phas_sigmas ); } + if (isInited(rhs, rhs.laser_sigmas )) { laser_sigmas = rhs.laser_sigmas ; setInited(*this, laser_sigmas ); } + + if (isInited(rhs, rhs.antenna_boresight )) { antenna_boresight = rhs.antenna_boresight ; setInited(*this, antenna_boresight ); } + if (isInited(rhs, rhs.antenna_azimuth )) { antenna_azimuth = rhs.antenna_azimuth ; setInited(*this, antenna_azimuth ); } + + return *this; + } + + map initialisedMap; }; /** Options to be applied to kalman filter states for individual receivers */ struct ReceiverOptions { - bool _initialised = false; - bool exclude = false; - - KalmanModel amb; - KalmanModel pos; - KalmanModel pos_rate; - KalmanModel clk; - KalmanModel clk_rate; - KalmanModel clk_rate_gauss_markov; - KalmanModel dcb; - KalmanModel pco; - KalmanModel ant; - KalmanModel ion; - KalmanModel trop; - KalmanModel trop_gauss_markov; - KalmanModel trop_grads; - KalmanModel trop_grads_gauss_markov; - KalmanModel code_bias; - KalmanModel phase_bias; - - E_NoiseModel error_model = E_NoiseModel::ELEVATION_DEPENDENT; - vector code_sigmas = {1}; - vector phas_sigmas = {0.0015}; -}; - -/** Minimum constraint options for individual receivers -*/ -struct MinimumStationOptions //todo aaron, move to stations? -{ - bool _initialised = false; - - vector noise = {-1}; + bool _initialised = false; + + KalmanModel amb; + KalmanModel pos; + KalmanModel pos_rate; + KalmanModel heading; + KalmanModel orbit; + KalmanModel strain_rate; + KalmanModel clk; + KalmanModel clk_rate; + KalmanModel slr_range_bias; + KalmanModel slr_time_bias; + KalmanModel dcb; + KalmanModel pco; + KalmanModel ant; + KalmanModel ion_stec; + KalmanModel trop; + KalmanModel trop_grads; + KalmanModel code_bias; + KalmanModel phase_bias; + + bool exclude = false; + E_NoiseModel error_model = E_NoiseModel::ELEVATION_DEPENDENT; + vector code_sigmas = {1}; + vector phas_sigmas = {0.0015}; + vector laser_sigmas = {0.5}; + vector minConNoise = {-1}; + double spp_sigma_scaling = 1; + + Rinex23Conversion rinex23Conv ; + + Vector3d apriori_pos = Vector3d::Zero(); + Vector3d eccentricity = Vector3d::Zero(); + Vector3d antenna_boresight = { 0, 0, +1}; + Vector3d antenna_azimuth = { 0, +1, 0}; + string antenna_type ; + string receiver_type ; + + ReceiverOptions& operator+=( + const ReceiverOptions& rhs) + { + amb += rhs.amb; + pos += rhs.pos; + pos_rate += rhs.pos_rate; + heading += rhs.heading; + orbit += rhs.orbit; + strain_rate += rhs.strain_rate; + clk += rhs.clk; + clk_rate += rhs.clk_rate; + slr_range_bias += rhs.slr_range_bias; + slr_time_bias += rhs.slr_time_bias; + dcb += rhs.dcb; + pco += rhs.pco; + ant += rhs.ant; + ion_stec += rhs.ion_stec; + trop += rhs.trop; + trop_grads += rhs.trop_grads; + code_bias += rhs.code_bias; + phase_bias += rhs.phase_bias; + + if (isInited(rhs, rhs.exclude )) { exclude = rhs.exclude ; setInited(*this, exclude ); } + if (isInited(rhs, rhs.error_model )) { error_model = rhs.error_model ; setInited(*this, error_model ); } + if (isInited(rhs, rhs.code_sigmas )) { code_sigmas = rhs.code_sigmas ; setInited(*this, code_sigmas ); } + if (isInited(rhs, rhs.phas_sigmas )) { phas_sigmas = rhs.phas_sigmas ; setInited(*this, phas_sigmas ); } + if (isInited(rhs, rhs.laser_sigmas )) { laser_sigmas = rhs.laser_sigmas ; setInited(*this, laser_sigmas ); } + if (isInited(rhs, rhs.minConNoise )) { minConNoise = rhs.minConNoise ; setInited(*this, minConNoise ); } + if (isInited(rhs, rhs.spp_sigma_scaling )) { spp_sigma_scaling = rhs.spp_sigma_scaling ; setInited(*this, spp_sigma_scaling ); } + + if (isInited(rhs, rhs.rinex23Conv )) { rinex23Conv = rhs.rinex23Conv ; setInited(*this, rinex23Conv ); } + + if (isInited(rhs, rhs.apriori_pos )) { apriori_pos = rhs.apriori_pos ; setInited(*this, apriori_pos ); } + if (isInited(rhs, rhs.eccentricity )) { eccentricity = rhs.eccentricity ; setInited(*this, eccentricity ); } + if (isInited(rhs, rhs.antenna_boresight )) { antenna_boresight = rhs.antenna_boresight ; setInited(*this, antenna_boresight ); } + if (isInited(rhs, rhs.antenna_azimuth )) { antenna_azimuth = rhs.antenna_azimuth ; setInited(*this, antenna_azimuth ); } + if (isInited(rhs, rhs.antenna_type )) { antenna_type = rhs.antenna_type ; setInited(*this, antenna_type ); } + if (isInited(rhs, rhs.receiver_type )) { receiver_type = rhs.receiver_type ; setInited(*this, receiver_type ); } + + return *this; + } + + map initialisedMap; }; /** Options associated with the minimum constraints mode of operation @@ -616,31 +1036,58 @@ struct MinimumConstraintOptions : FilterOptions KalmanModel scale; KalmanModel rotation; KalmanModel translation; - + + bool once_per_epoch = false; bool full_vcv = false; bool scale_by_vcv = false; +}; - map stationMap; +struct MongoOptions +{ + bool enable = false; + bool output_rtcm_messages = false; + bool output_measurements = false; + bool output_components = false; + bool output_states = false; + bool output_trace = false; + bool output_test_stats = false; + bool output_logs = false; + bool output_ssr_precursors = false; + bool delete_history = false; + bool cull_history = false; + bool local = false; + string uri = "mongodb://localhost:27017"; + string suffix = ""; + string database = ""; + bool predict_states = false; + double prediction_interval = 30; + double forward_prediction_duration = 300; + double reverse_prediction_duration = -1; + double min_cull_age = 300; }; /** Options associated with SSR corrections and exporting RTCM messages */ struct SsrOptions { - bool calculate_ssr = false; - bool extrapolate_corrections = false; - int prediction_interval = 30; - int prediction_duration = 0; - E_Ephemeris ephemeris_source = E_Ephemeris::PRECISE; - E_Ephemeris clock_source = E_Ephemeris::KALMAN; - E_Ephemeris code_bias_source = E_Ephemeris::PRECISE; - E_Ephemeris phase_bias_source = E_Ephemeris::NONE; + bool extrapolate_corrections = false; + double prediction_interval = 30; + double prediction_duration = 0; + vector ephemeris_sources = {E_Source::PRECISE}; + vector clock_sources = {E_Source::KALMAN}; + vector code_bias_sources = {E_Source::PRECISE}; + vector phase_bias_sources = {E_Source::NONE}; + vector ionosphere_sources = {E_Source::NONE}; + // vector troposphere_sources = E_Source::NONE; }; struct SsrInOptions { double code_bias_valid_time = 3600; ///< Valid time period of SSR code biases double phase_bias_valid_time = 30; ///< Valid time period of SSR phase biases + double global_vtec_valid_time = 300; ///< Valid time period of SSR global Ionospheres + double local_stec_valid_time = 120; ///< Valid time period of SSR local Ionospheres + bool one_freq_phase_bias = false; }; struct SSRMetaOpts @@ -648,102 +1095,120 @@ struct SSRMetaOpts bool itrf_datum = true; int provider_id = 0; int solution_id = 0; - int update_interval = 10; int master_iod = 10; }; +struct RtcmMsgTypeOpts +{ + int udi = 0; ///< Update interval (0 = don't upload message) + + map comp_udi; + map igs_udi; + + // space for multiple UDI's here +}; + struct SsrBroadcast : SSRMetaOpts { - int message_timeout = INT_MAX; - string url; + int message_timeout = INT_MAX; + string url; - set> rtcmMessagesTypes; + map rtcmMsgOptsMap; ///< RTCM message type options +}; + +struct NetworkOptions +{ + map uploadingStreamData; }; + /** Options associated with orbital force models */ -struct ForceModels +struct OrbitPropagation { - bool earth_gravity = true; - E_GravMdl gravity_model = E_GravMdl::GGM03S; - bool solid_earth_tides = false; - bool ocean_tide_loading = false; - bool relativity_effect = false; - bool solar_radiation_pressure = false; - bool thermal_emission = false; - bool earth_albedo = false; - bool infrared_radiation = false; + bool central_force = true; + bool planetary_perturbation = true; + bool indirect_J2 = true; + bool egm_field = true; + bool solid_earth_tide = true; + bool ocean_tide = true; + bool general_relativity = true; + bool pole_tide_ocean = true; + bool pole_tide_solid = true; + bool solar_pressure_radiation = false; + bool empirical_dyb = false; bool antenna_thrust = false; - bool empirical_acceleration = false; - bool satellite_manoeuvre = false; - double sat_mass = 100; - E_SRPModels srp_model = E_SRPModels::CANNONBALL; - double srp_area = 5; - double srp_coef = 1; - int egmAccDeg = 12; - int egmAccOrd = 12; - int egmSTMDeg = 4; - int egmSTMOrd = 4; - E_Integrator ode_integrator = E_Integrator::RKF78; - E_TidesMdl earth_tide_Model = E_TidesMdl::ELASTIC; - - map process_third_body; + bool albedo = false; + + int degree_max = 12; + double sat_mass = 1000; + double sat_area = 20; + double srp_cr = 1.25; + double integrator_time_step = 60; + bool itrf_pseudoobs = true; +}; + +struct YamlDefault +{ + string defaultValue; + string comment; + bool found; + string foundValue; }; /** General options object to be used throughout the software */ struct ACSConfig : GlobalOptions, InputOptions, OutputOptions, DebugOptions { - YAML::Node yaml; - map> yamlDefaults; - map availableOptions; + vector yamls; + map yamlDefaults; + map availableOptions; - - string configFilename; + mutex configMutex; + + vector configFilenames; map configModifyTimeMap; boost::program_options::variables_map commandOpts; void recurseYaml( YAML::Node node, - string stack = ""); + string stack = "", + string aliasStack = ""); + + bool parse( + vector filenames, + boost::program_options::variables_map& vm); - bool parse(string filename, boost::program_options::variables_map& vm); bool parse(); - void info(Trace& trace); + + void info( + Trace& trace); void outputDefaultConfiguration(); - SatelliteOptions& getSatOpts (SatSys& Sat); - ReceiverOptions& getRecOpts (string id); - MinimumStationOptions& getMinConOpts (string id); + SatelliteOptions& getSatOpts (SatSys Sat, vector suffixes = {}); + ReceiverOptions& getRecOpts (string id, vector suffixes = {}); map satOptsMap; map recOptsMap; IonosphericOptions ionoOpts; - NetworkOptions pppOpts; + PPPOptions pppOpts; MinimumConstraintOptions minCOpts; TestOptions testOpts; SsrOptions ssrOpts; SsrInOptions ssrInOpts; AmbROptions ambrOpts; SlipOptions excludeSlip; - ForceModels forceModels; - IonModelOptions ionModelOpts; - - KalmanModel ion; - list rinexFiles; - - bool common_atmosphere = false; - - map uploadingStreamData; + SlipOptions resetOnSlip; + OrbitPropagation orbitPropagation; + IonModelOptions ionModelOpts; + NetworkOptions netOpts; + SlrOptions slrOpts; + MongoOptions localMongo = {.local = true}; + MongoOptions remoteMongo = {.local = false}; }; - - - - - bool replaceString( string& str, string subStr, @@ -773,6 +1238,3 @@ void dumpConfig( extern ACSConfig acsConfig; ///< Global variable housing all options to be used throughout the software - - -#endif diff --git a/src/cpp/common/acsQC.cpp b/src/cpp/common/acsQC.cpp index 3ccd17b61..c8f07446e 100644 --- a/src/cpp/common/acsQC.cpp +++ b/src/cpp/common/acsQC.cpp @@ -5,7 +5,6 @@ #include #include "observations.hpp" -#include "streamTrace.hpp" #include "acsConfig.hpp" #include "testUtils.hpp" #include "constants.hpp" @@ -13,13 +12,72 @@ #include "algebra.hpp" #include "common.hpp" #include "acsQC.hpp" +#include "trace.hpp" #include "lambda.h" #include "enums.h" #define THRES_MW_JUMP 10.0 #define PDEGAP 60.0 #define PDESLIPTHRESHOLD 0.5 +#define PROC_NOISE_IONO 0.001 + +bool satFreqs( + E_Sys sys, + E_FType& ft1, + E_FType& ft2, + E_FType& ft3) +{ + if (acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L2_ONLY) + { + ft1 = F1; + ft2 = F2; + ft3 = FTYPE_NONE; + } + + if (acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) + { + ft1 = F1; + ft2 = F5; + ft3 = FTYPE_NONE; + } + + bool ft1Ready = false; + bool ft2Ready = false; + + if (acsConfig.code_priorities.find(sys) == acsConfig.code_priorities.end()) + return false; + + for (auto& code : acsConfig.code_priorities[sys]) + { + E_FType ft = code2Freq[sys][code]; + + if (ft1Ready == false) + { + ft1 = ft; ft1Ready = true; + continue; + } + + if (ft == ft1) + continue; + + if (ft2Ready == false) + { + ft2 = ft; ft2Ready = true; + continue; + } + + if (ft == ft2) + continue; + + { + ft3 = ft; + break; + } + } + + return true; +} /** Detect cycle slip by reported loss of lock */ void detslp_ll( @@ -28,7 +86,9 @@ void detslp_ll( { tracepdeex(5, trace, "\n%s: n=%d", __FUNCTION__, obsList.size()); - for (auto& obs : obsList) +// auto begin_iter = boost::make_filter_iterator([] + + for (auto& obs : only(obsList)) for (auto& [ft, sig] : obs.Sigs) { if (obs.exclude) @@ -45,7 +105,8 @@ void detslp_ll( tracepdeex(3, trace, "\n%s: slip detected sat=%s f=F%d\n", __FUNCTION__, obs.Sat.id().c_str(), ft); - obs.satStat_ptr->sigStatMap[ft].slip.LLI = true; + obs.satStat_ptr->sigStatMap[ft2string(ft)].slip. LLI = true; + obs.satStat_ptr->sigStatMap[ft2string(ft)].savedSlip. LLI = true; } } @@ -57,20 +118,20 @@ void detslp_gf( { tracepdeex(5, trace, "\n%s: n=%d", __FUNCTION__, obsList.size()); - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { if (obs.exclude) { continue; } - E_FType frq1 = F1; + E_FType frq1; E_FType frq2; E_FType frq3; - if (obs.Sat.sys == +E_Sys::GPS && acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) { frq2=F5; frq3=F7; } - if (obs.Sat.sys == +E_Sys::GAL) { frq2=F5; frq3=F7; } - else { frq2=F2; frq3=F5; } - + bool pass = satFreqs(obs.Sat.sys, frq1, frq2, frq3); + if (pass == false) + continue; + S_LC& lc = getLC(obs.satStat_ptr->lc_new, frq1, frq2); double gf1 = lc.GF_Phas_m; @@ -94,10 +155,10 @@ void detslp_gf( { tracepdeex(3, trace, "\n%s: slip detected: sat=%s gf0=%f gf1=%f", __FUNCTION__, obs.Sat.id().c_str(), gf0, gf1); - for (auto& [ft, sigStat] : obs.satStat_ptr->sigStatMap) - { - sigStat.slip.GF = true; - } + obs.satStat_ptr->sigStatMap[ft2string(frq1)].slip. GF = true; + obs.satStat_ptr->sigStatMap[ft2string(frq2)].slip. GF = true; + obs.satStat_ptr->sigStatMap[ft2string(frq1)].savedSlip. GF = true; + obs.satStat_ptr->sigStatMap[ft2string(frq2)].savedSlip. GF = true; } } } @@ -110,20 +171,20 @@ void detslp_mw( { tracepdeex(5, trace, "\n%s: n=%d", __FUNCTION__, obsList.size()); - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { if (obs.exclude) { continue; } - E_FType frq1 = F1; + E_FType frq1; E_FType frq2; E_FType frq3; - if (obs.Sat.sys == +E_Sys::GPS && acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) { frq2=F5; frq3=F7; } - if (obs.Sat.sys == +E_Sys::GAL) { frq2=F5; frq3=F7; } - else { frq2=F2; frq3=F5; } - + bool pass = satFreqs(obs.Sat.sys, frq1, frq2, frq3); + if (pass == false) + continue; + S_LC& lc = getLC(obs.satStat_ptr->lc_new, frq1, frq2); double mw1 = lc.MW_c; @@ -147,10 +208,10 @@ void detslp_mw( { tracepdeex(3, trace, "\n%s: slip detected: sat=%s mw0=%f mw1=%f", __FUNCTION__, obs.Sat.id().c_str(), mw0, mw1); - for (auto& [ft, sigStat] : obs.satStat_ptr->sigStatMap) - { - sigStat.slip.MW = true; - } + obs.satStat_ptr->sigStatMap[ft2string(frq1)].slip. MW = true; + obs.satStat_ptr->sigStatMap[ft2string(frq2)].slip. MW = true; + obs.satStat_ptr->sigStatMap[ft2string(frq1)].savedSlip. MW = true; + obs.satStat_ptr->sigStatMap[ft2string(frq2)].savedSlip. MW = true; } } } @@ -178,20 +239,21 @@ void scdia( double sigmaPhase, ///< Phase noise double sigmaCode, ///< Code noise int nf, ///< Number of frequencies - int sys, ///< Satellite system + E_Sys sys, ///< Satellite system E_FilterMode filterMode) ///< LSQ/Kalman filter flag { - E_FType frq1 = F1; + if (nf == 0) + return; + + E_FType frq1; E_FType frq2; E_FType frq3; - if (sys == +E_Sys::GPS && acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) { frq2=F5; frq3=F7; } - if (sys == +E_Sys::GAL) { frq2=F5; frq3=F7; } - else { frq2=F2; frq3=F5; } - - if (nf == 0) + bool pass = satFreqs(sys, frq1, frq2, frq3); + if (pass == false) + { return; + } - lc_t* lc_pre_ptr; if (filterMode == +E_FilterMode::LSQ) lc_pre_ptr = &satStat. lc_pre; @@ -206,7 +268,7 @@ void scdia( return; } - E_FType ftypes[3] = {frq1, frq2, frq3}; + E_FType freqs[3] = {frq1, frq2, frq3}; /* m-rows measurements, n-cols unknowns */ int m = 2 * nf + 1; @@ -221,7 +283,7 @@ void scdia( //phase and code for (int f = 0; f < nf; f++) { - E_FType frqX = ftypes[f]; + E_FType frqX = freqs[f]; double lamX = lam[frqX]; Z[i] = lc .L_m[frqX] @@ -249,9 +311,12 @@ void scdia( return; } - satStat.sigStatMap[frq1].slip.SCDIA = true; - satStat.sigStatMap[frq2].slip.SCDIA = true; - if (nf == 3) satStat.sigStatMap[frq3].slip.SCDIA = true; + satStat.sigStatMap[ft2string(frq1)].slip. SCDIA = true; + satStat.sigStatMap[ft2string(frq2)].slip. SCDIA = true; + if (nf == 3) satStat.sigStatMap[ft2string(frq3)].slip. SCDIA = true; + satStat.sigStatMap[ft2string(frq1)].savedSlip. SCDIA = true; + satStat.sigStatMap[ft2string(frq2)].savedSlip. SCDIA = true; + if (nf == 3) satStat.sigStatMap[ft2string(frq3)].savedSlip. SCDIA = true; VectorXd xp = VectorXd::Zero(n); MatrixXd Pp = MatrixXd::Zero(n, n); @@ -329,7 +394,6 @@ void scdia( /* integer cycle slip estimation */ MatrixXd F = MatrixXd::Zero(nf, 2); - bool pass; double s[2]; lambda(trace, nf, 2, a.data(), Qa.data(), F.data(), s, acsConfig.predefined_fail, pass); @@ -343,7 +407,6 @@ void scdia( if (pass) { tracepdeex(2, trace, "fixed "); -// tracematpde(2, trace, F, 1, nf, 4, 1); for (int i = 0; i < 3; i++) satStat.amb[i] = ROUND(F.data()[i]); @@ -365,7 +428,6 @@ void scdia( memset(satStat.flt.Qa, 0, 9); //todo aaron, looks sketchy satStat.flt.slip |= 2; tracepdeex(1, trace, " ACC fixed "); -// tracematpde(1, trace, F, 1, nf, 4, 1); for (int i = 0; i < nf; i++) { satStat.flt.amb[i] = ROUND(F.data()[i]); @@ -377,17 +439,18 @@ void scdia( } } -/** Cycle slip detection and repair for dual-frequency +/** Cycle slip detection for dual-frequency */ void cycleslip2( Trace& trace, ///< Trace to output to SatStat& satStat, ///< Persistant satellite status parameters lc_t& lcBase, ///< Linear combinations - Obs& obs) ///< Navigation object for this satellite + GObs& obs) ///< Navigation object for this satellite { - int week; - double sec = time2gpst(lcBase.time, &week); - double dt = lcBase.time - satStat.lc_pre.time; + GWeek week = lcBase.time; + GTow tow = lcBase.time; + + double dt = (lcBase.time - satStat.lc_pre.time).to_double(); if ( dt < 20 ||dt > PDEGAP) @@ -397,7 +460,7 @@ void cycleslip2( satStat.dIono = 0; // approximation of ionosphere residual - satStat.sigmaIono = acsConfig.proc_noise_iono * SQRT(dt); + satStat.sigmaIono = PROC_NOISE_IONO * SQRT(dt); } else { @@ -405,7 +468,7 @@ void cycleslip2( if (satStat.dIono == 0) { - satStat.sigmaIono = acsConfig.proc_noise_iono * SQRT(dt); + satStat.sigmaIono = PROC_NOISE_IONO * SQRT(dt); } } @@ -414,14 +477,16 @@ void cycleslip2( satStat.sigmaIono = 0.001; } - int sys = lcBase.Sat.sys; + auto sys = lcBase.Sat.sys; - E_FType frq1 = F1; + E_FType frq1; E_FType frq2; E_FType frq3; - if (obs.Sat.sys == +E_Sys::GPS && acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) { frq2=F5; frq3=F7; } - if (obs.Sat.sys == +E_Sys::GAL) { frq2=F5; frq3=F7; } - else { frq2=F2; frq3=F5; } + bool pass = satFreqs(obs.Sat.sys, frq1, frq2, frq3); + if (pass == false) + { + return; + } auto& lam = obs.satNav_ptr->lamMap; @@ -459,7 +524,7 @@ void cycleslip2( - lcPre.GF_Phas_m; /* Eq (9) in TN */ tracepdeex(2, trace, "\nPDE-CS GPST DUAL %4d %8.1f %4s %5.2f %5.3f %8.4f %7.4f %8.4f ", - week, sec, lcBase.Sat.id().c_str(), satStat.el * R2D, lamw, deltaGF, fNw, sigmaGF); + week, tow, lcBase.Sat.id().c_str(), satStat.el * R2D, lamw, deltaGF, fNw, sigmaGF); /* cycle slip detection */ if (satStat.el >= acsConfig.elevation_mask) @@ -468,8 +533,8 @@ void cycleslip2( } /* update TD ionosphere residual */ - if ( satStat.sigStatMap[frq1].slip.any == 0 - &&satStat.sigStatMap[frq2].slip.any == 0) + if ( satStat.sigStatMap[ft2string(frq1)].slip.any == 0 + &&satStat.sigStatMap[ft2string(frq2)].slip.any == 0) { satStat.dIono = deltaGF / coef; satStat.sigmaIono = sigmaGF / coef; @@ -482,11 +547,12 @@ void cycleslip3( Trace& trace, ///< Trace to output to SatStat& satStat, ///< Persistant satellite status parameters lc_t& lc, ///< Linear combinations - Obs& obs) ///< Navigation object for this satellite + GObs& obs) ///< Navigation object for this satellite { - int week; - double sec = time2gpst(lc.time, &week); - double dt = lc.time - satStat.lc_pre.time; + GWeek week = lc.time; + GTow tow = lc.time; + + double dt = (lc.time - satStat.lc_pre.time).to_double(); /* small interval */ if (dt < 20) @@ -494,14 +560,14 @@ void cycleslip3( satStat.dIono = 0; /* approximation of ionosphere residual */ - satStat.sigmaIono = acsConfig.proc_noise_iono * SQRT(dt); + satStat.sigmaIono = PROC_NOISE_IONO * SQRT(dt); } else { /* large interval */ if (satStat.sigmaIono == 0) { - satStat.sigmaIono = acsConfig.proc_noise_iono * SQRT(dt); + satStat.sigmaIono = PROC_NOISE_IONO * SQRT(dt); } } @@ -510,15 +576,15 @@ void cycleslip3( satStat.sigmaIono = 0.001; } - int sys = lc.Sat.sys; + auto sys = lc.Sat.sys; - E_FType frq1 = F1; + E_FType frq1; E_FType frq2; E_FType frq3; - { frq2=F2; frq3=F5; } - if (obs.Sat.sys == +E_Sys::GAL) { frq2=F5; frq3=F7; } - if (obs.Sat.sys == +E_Sys::GPS && acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) { frq2=F5; frq3=F7; } - + bool pass = satFreqs(obs.Sat.sys, frq1, frq2, frq3); + if (pass == false) + return; + auto& lam = obs.satNav_ptr->lamMap; double lam1 = lam[frq1]; double lam2 = lam[frq2]; @@ -564,18 +630,12 @@ void cycleslip3( if (coef1 < 0) coef1 = -coef1; - /* wide-lane with longer wavelength, note for the IGNSS paper */ - E_FType frqX; - double lamX; - if (sys == E_Sys::BDS) { frqX = frq3; lamX = lam5; } - else { frqX = frq2; lamX = lam2; } - - S_LC lcNew = getLC(lc, frq1, frqX); - S_LC lcPre = getLC(satStat.lc_pre, frq1, frqX); + S_LC lcNew = getLC(lc, frq1, frq2); + S_LC lcPre = getLC(satStat.lc_pre, frq1, frq2); - double lamw = lam1 * lamX / (lamX - lam1); + double lamw = lam1 * lam2 / (lam2 - lam1); - double coef = SQR(lamX) / SQR(lam1) - 1; // ionosphere coefficient for L1 & LX + double coef = SQR(lam2) / SQR(lam1) - 1; // ionosphere coefficient for L1 & LX /* averaged MW measurement and noise */ double fNw; @@ -586,7 +646,7 @@ void cycleslip3( - lcPre.GF_Phas_m; tracepdeex(2, trace, "\nPDE-CS GPST TRIP %4d %8.1f %4s %5.2f %5.3f %8.4f %7.4f %8.4f %6.2f %8.4f %7.4f ", week, - sec, lc.Sat.id().c_str(), satStat.el * R2D, lamw, deltaGF, fNw, sigmaGF, lamew, deltaGF25, fNew); + tow, lc.Sat.id().c_str(), satStat.el * R2D, lamw, deltaGF, fNw, sigmaGF, lamew, deltaGF25, fNew); if (satStat.el >= acsConfig.elevation_mask) { @@ -594,9 +654,9 @@ void cycleslip3( } /* update TD ionosphere residual */ - if ( satStat.sigStatMap[frq1].slip.any == 0 - &&satStat.sigStatMap[frq2].slip.any == 0 - &&satStat.sigStatMap[frq3].slip.any == 0) + if ( satStat.sigStatMap[ft2string(frq1)].slip.any == 0 + &&satStat.sigStatMap[ft2string(frq2)].slip.any == 0 + &&satStat.sigStatMap[ft2string(frq3)].slip.any == 0) { satStat.dIono = deltaGF / coef; satStat.sigmaIono = sigmaGF / coef; @@ -610,7 +670,7 @@ void detectslip( SatStat& satStat, ///< Persistant satellite status parameters lc_t& lc_new, ///< Linear combination for this epoch lc_t& lc_old, ///< Linear combination from previous epoch - Obs& obs) ///< Navigation object for this satellite + GObs& obs) ///< Navigation object for this satellite { bool dualFreq = false; E_Sys sys = lc_new.Sat.sys; @@ -618,42 +678,32 @@ void detectslip( char id[32]; lc_new.Sat.getId(id); - int week; - double sec = time2gpst(lc_new.time, &week); + GWeek week = lc_new.time; + GTow tow = lc_new.time; - E_FType frq1 = F1; + if (acsConfig.process_sys[sys] == false) + return; + + E_FType frq1; E_FType frq2; E_FType frq3; - if (obs.Sat.sys == +E_Sys::GPS && acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) { frq2=F5; frq3=F7; } - if (obs.Sat.sys == +E_Sys::GAL) { frq2=F5; frq3=F7; } - else { frq2=F2; frq3=F5; } - - /* SBS and LEO are not included */ - if ( acsConfig.process_sys[sys] == false - ||sys == +E_Sys::SBS - ||sys == +E_Sys::LEO) + bool pass = satFreqs(obs.Sat.sys, frq1, frq2, frq3); + if (pass == false) { return; } - - /* initialize the amb parameter each epoch */ - for (auto& [key, sigStat] : satStat.sigStatMap) - { - if (key < 3) - satStat.amb[key] = 0; //todo aaron, yuk - } - + /* first epoch or large gap or low elevation */ //todo aaron initialisation stuff, remove - if ( satStat.lc_pre.time.time == 0 + if ( satStat.lc_pre.time.bigTime == 0 || satStat.el < acsConfig.elevation_mask || lc_new.time > lc_old.time + PDEGAP) { satStat.mwSlip = {}; satStat.emwSlip = {}; - if (lc_new.time > lc_old.time + PDEGAP) tracepdeex(1, trace, "PDE-CS GPST %4d %8.1f %4s %5.2f --time gap --", week, sec, id, satStat.el * R2D); - if (satStat.el < acsConfig.elevation_mask) tracepdeex(1, trace, "PDE-CS GPST %4d %8.1f %4s %5.2f --low_elevation --", week, sec, id, satStat.el * R2D); - if (satStat.el > acsConfig.elevation_mask) tracepdeex(1, trace, "PDE-CS GPST %4d %8.1f %4s %5.2f --satStat.lc_pre.time.time --", week, sec, id, satStat.el * R2D); + if (lc_new.time > lc_old.time + PDEGAP) tracepdeex(1, trace, "\nPDE-CS GPST %4d %8.1f %4s %5.2f --time gap --", week, tow, id, satStat.el * R2D); + if (satStat.el < acsConfig.elevation_mask) tracepdeex(1, trace, "\nPDE-CS GPST %4d %8.1f %4s %5.2f --low_elevation --", week, tow, id, satStat.el * R2D); + if (satStat.el > acsConfig.elevation_mask) tracepdeex(1, trace, "\nPDE-CS GPST %4d %8.1f %4s %5.2f --satStat.lc_pre.time.time --", week, tow, id, satStat.el * R2D); return; } @@ -680,8 +730,8 @@ void detectslip( cycleslip2(trace, satStat, lc_new, obs); /* update averaged MW noise when no cycle slip */ - if ( satStat.sigStatMap[frq1].slip.any == 0 - &&satStat.sigStatMap[frq2].slip.any == 0) + if ( satStat.sigStatMap[ft2string(frq1)].slip.any == 0 + &&satStat.sigStatMap[ft2string(frq2)].slip.any == 0) { S_LC& lc12 = getLC(lc_new, frq1, frq2); lowPassFilter(satStat.mwSlip, lc12.MW_c, acsConfig.mw_proc_noise); @@ -700,12 +750,12 @@ void detectslip( &&lc_old.L_m[frq3] == 0) //was zero, now not. { /* set slip flag for L5 (introduce new ambiguity for L5) */ - satStat.sigStatMap[frq3].slip.LLI = true; + satStat.sigStatMap[ft2string(frq3)].slip.LLI = true; cycleslip2(trace, satStat, lc_new, obs); /* update averaged MW noise when no cycle slip */ - if ( satStat.sigStatMap[frq1].slip.any == 0 - &&satStat.sigStatMap[frq2].slip.any == 0) + if ( satStat.sigStatMap[ft2string(frq1)].slip.any == 0 + &&satStat.sigStatMap[ft2string(frq2)].slip.any == 0) { S_LC& lc12 = getLC(lc_new, frq1, frq2); lowPassFilter(satStat.mwSlip, lc12.MW_c, acsConfig.mw_proc_noise); @@ -727,21 +777,21 @@ void detectslip( if (satStat.el * R2D > 30) { - if ( satStat.sigStatMap[frq1].slip.any == 2 //todo aaron, check the 2 + if ( satStat.sigStatMap[ft2string(frq1)].slip.any == 2 //todo aaron, check the 2 &&satStat.amb[0] == 0 &&satStat.amb[1] == 0 &&satStat.amb[2] == 0) { - satStat.sigStatMap[frq1].slip.any = 0; - satStat.sigStatMap[frq2].slip.any = 0; - satStat.sigStatMap[frq3].slip.any = 0; + satStat.sigStatMap[ft2string(frq1)].slip.any = 0; + satStat.sigStatMap[ft2string(frq2)].slip.any = 0; + satStat.sigStatMap[ft2string(frq3)].slip.any = 0; } } /*update averaged MW25 noise when no cycle slip */ - if ( satStat.sigStatMap[frq1].slip.any == 0 - &&satStat.sigStatMap[frq2].slip.any == 0 - &&satStat.sigStatMap[frq3].slip.any == 0) + if ( satStat.sigStatMap[ft2string(frq1)].slip.any == 0 + &&satStat.sigStatMap[ft2string(frq2)].slip.any == 0 + &&satStat.sigStatMap[ft2string(frq3)].slip.any == 0) { S_LC& lc25 = getLC(lc_new, frq2, frq3); lowPassFilter(satStat.emwSlip, lc25.MW_c, acsConfig.mw_proc_noise); @@ -763,7 +813,7 @@ void detectslip( sigStat.slip.LLI = true; } - tracepdeex(1, trace, "\nPDE-CS GPST %4d %8.1f %4s %5.2f -- re-tracking --\n", week, sec, id, satStat.el * R2D); + tracepdeex(1, trace, "\nPDE-CS GPST %4d %8.1f %4s %5.2f -- re-tracking --\n", week, tow, id, satStat.el * R2D); } else { @@ -774,7 +824,7 @@ void detectslip( sigStat.slip.LLI = true; } - tracepdeex(1, trace, "\nPDE-CS GPST %4d %8.1f %4s %5.2f --single frequency--\n", week, sec, id, satStat.el * R2D); + tracepdeex(1, trace, "\nPDE-CS GPST %4d %8.1f %4s %5.2f --single frequency--\n", week, tow, id, satStat.el * R2D); } } @@ -782,13 +832,20 @@ void clearSlips( ObsList& obsList) { //clear non-persistent status values. - for (auto& obs : obsList) - for (auto& [sigKey, sigStat] : obs.satStat_ptr->sigStatMap) + for (auto& obs : only(obsList)) { - SatStat& satStat = *(obs.satStat_ptr); + if (acsConfig.process_sys[obs.Sat.sys] == false) + { + continue; + } - satStat.slip = false; - sigStat.slip.any = 0; + for (auto& [sigKey, sigStat] : obs.satStat_ptr->sigStatMap) + { + SatStat& satStat = *(obs.satStat_ptr); + + satStat.slip = false; + sigStat.slip.any = 0; + } } } @@ -806,21 +863,20 @@ void detectslips( tracepdeex(2, trace, "\nPDE-CS GPST week sec prn el lamw gf12 mw12 siggf sigmw lamew gf25 mw25 LC N1 N2 N5\n"); - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { if (obs.exclude) { continue; } - TestStack ts(obs.Sat); SatStat& satStat = *(obs.satStat_ptr); detectslip(trace, satStat, satStat.lc_new, satStat.lc_pre, obs); for (auto& [ft, sig] : obs.Sigs) { - auto& sigStat = obs.satStat_ptr->sigStatMap[ft]; + auto& sigStat = obs.satStat_ptr->sigStatMap[ft2string(ft)]; if (sigStat.slip.any) { diff --git a/src/cpp/common/acsQC.hpp b/src/cpp/common/acsQC.hpp index 52519e536..d2b2164c2 100644 --- a/src/cpp/common/acsQC.hpp +++ b/src/cpp/common/acsQC.hpp @@ -1,6 +1,5 @@ -#ifndef ACSQC_HPP -#define ACSQC_HPP +#pragma once #include #include @@ -17,62 +16,6 @@ #define NTROP 2880 /* max daily trop solution number */ #define MAXSTR 32 /* max string length */ -/** Clock jump repair object -*/ -struct ClockJump -{ - int msJump; - int type; -}; - - -/* trop sinex file */ -struct mgex_tropcoord /* trop station coordinates block */ -{ - char sitecode[5] = {}; /* site code */ - char ptcode[3] = {}; /* point code */ - char solid[5] = {}; /* solution ID */ - char obscode; /* observation code */ - double x[3]; /* coordinates */ - char sys[7] = {}; /* system */ - char remark[6] = {}; - double std[3]; /* (mm) */ - int counter; -}; - -struct mgex_tropsol /* trop description block */ -{ - char marker[5] = {}; /* marker name */ - double ts[3]; /* solution time YDS */ - double x[14]; - int actak; - int acdel; -}; - -struct mgex_trop /* trop information */ -{ - char id[6] = {}; - double ver; - char agency[4] = {}; - char agencycode[4] = {}; - int tbc[3]; /* time created */ - int tbs[3]; /* time started */ - int tbe[3]; /* time end */ - char obscode; /* observation code */ - char solcon[5] = {}; - /* description block */ - char solfield[14][6] = {}; /* solution */ - int inttrop; /* trop solution sample rate */ - int intdata; /* data sampling interval */ - char tropmap[23] = {}; /* mapping function */ - double el; /* elevation cut off */ - int bstart; /* bias start */ - int bend; /* bias end */ - double factor; /* delete factor */ - char cfactor[23] = {}; /* conversion factor */ - mgex_tropcoord tcoord[MAXIGSSTA]; - mgex_tropsol* tsol = nullptr; -}; int lsqqc( Trace& trace, @@ -113,5 +56,3 @@ void detslp_mw( void detslp_ll( ObsList& obsList); - -#endif diff --git a/src/cpp/common/acsStream.cpp b/src/cpp/common/acsStream.cpp deleted file mode 100644 index 533b20b34..000000000 --- a/src/cpp/common/acsStream.cpp +++ /dev/null @@ -1,294 +0,0 @@ - -// #pragma GCC optimize ("O0") -#include - -using std::multimap; -using std::map; - -#include -#include - -using bsoncxx::builder::basic::kvp; - -#include "rtcmEncoder.hpp" -#include "navigation.hpp" -#include "streamRtcm.hpp" -#include "ephemeris.hpp" -#include "constants.hpp" -#include "acsStream.hpp" -#include "acsConfig.hpp" -#include "fileLog.hpp" -#include "enums.h" - - -GTime RtcmStream::rtcmDeltaTime = {}; - - -// Used for stream specific tracing. -multimap> ntripRtcmMultimap; -multimap obsStreamMultimap; -multimap navStreamMultimap; -multimap pseudoObsStreamMultimap; -map streamDOAMap; - - -ObsList ObsStream::getObs() -{ - if (obsListList.empty()) - { - return ObsList(); - } - ObsList& obsList = obsListList.front(); - - std::sort(obsList.begin(), obsList.end(), [](Obs& a, Obs& b) - { - if (a.Sat.sys < b.Sat.sys) return true; - if (a.Sat.sys > b.Sat.sys) return false; - if (a.Sat.prn < b.Sat.prn) return true; - else return false; - }); - - for (auto& obs : obsList) - for (auto& [ftype, sigsList] : obs.SigsLists) - { - E_Sys sys = obs.Sat.sys; - - if (sys == +E_Sys::GPS) - { - double dirty_C1W_phase = 0; - for (auto& sig : sigsList) - if ( sig.code == +E_ObsCode::L1C) - { - dirty_C1W_phase = sig.L; - break; - } - - for (auto& sig : sigsList) - if ( sig.code == +E_ObsCode::L1W - && sig.L == 0) - { - sig.L = dirty_C1W_phase; - break; - } - } - - sigsList.sort([sys](RawSig& a, RawSig& b) - { - auto iterA = std::find(acsConfig.code_priorities[sys].begin(), acsConfig.code_priorities[sys].end(), a.code); - auto iterB = std::find(acsConfig.code_priorities[sys].begin(), acsConfig.code_priorities[sys].end(), b.code); - - if (a.L == 0) return false; - if (b.L == 0) return true; - if (a.P == 0) return false; - if (b.P == 0) return true; - if (iterA < iterB) return true; - else return false; - }); - - if (sigsList.empty()) - { - continue; - } - - RawSig firstOfType = sigsList.front(); - - //use first of type as representative if its in the priority list - auto iter = std::find(acsConfig.code_priorities[sys].begin(), acsConfig.code_priorities[sys].end(), firstOfType.code); - if (iter != acsConfig.code_priorities[sys].end()) - { - obs.Sigs[ftype] = Sig(firstOfType); - } - } - - return obsList; -} - - -PseudoObsList PseudoObsStream::getObs() -{ - if (obsListList.empty()) - { - return PseudoObsList(); - } - - PseudoObsList& pseudoObsList = obsListList.front(); - - return pseudoObsList; -} - - -void RtcmStream::createRtcmFile() -{ - GTime curTime; - time(&curTime.time); - long int roundTime = curTime.time; - roundTime /= acsConfig.rotate_period; - roundTime *= acsConfig.rotate_period; - curTime.time = roundTime; - - string logtime = curTime.to_string(0); - std::replace( logtime.begin(), logtime.end(), '/', '-'); - - string path_rtcm = rtcm_filename; - replaceString(path_rtcm, "", logtime); - - std::ofstream ofs( path_rtcm,std::ofstream::out | std::ofstream::ate); -} - - -/** Writes nav.satNavMap[].ssrOut to a human-readable file -*/ -void writeSsrOutToFile( - int epochNum, - map& ssrOutMap) -{ - string filename = "ssrOut.dbg"; - std::ofstream out(filename, std::ios::app); - - if (!out) - { - BOOST_LOG_TRIVIAL(error) - << "Error: Could not open trace file for SSR messages at " << filename; - return; - } - out.precision(17); - - // Header - out << "epochNum" << "\t"; - out << "satId" << "\t"; - -// out << "SSREph.canExport" << "\t"; - out << "SSREph.t0" << "\t"; - out << "SSREph.udi" << "\t"; - out << "SSREph.iod" << "\t"; - out << "SSREph.iode" << "\t"; - out << "SSREph.deph[0]" << "\t"; - out << "SSREph.deph[1]" << "\t"; - out << "SSREph.deph[2]" << "\t"; - out << "SSREph.ddeph[0]" << "\t"; - out << "SSREph.ddeph[1]" << "\t"; - out << "SSREph.ddeph[2]" << "\t"; - -// out << "SSRClk.canExport" << "\t"; - out << "SSRClk.t0" << "\t"; - out << "SSRClk.udi" << "\t"; - out << "SSRClk.iod" << "\t"; - out << "SSRClk.dclk[0]" << "\t"; - out << "SSRClk.dclk[1]" << "\t"; - out << "SSRClk.dclk[2]" << "\t"; - - out << "SSRBias.t0_code" << "\t"; - out << "SSRBias.t0_phas" << "\t"; - out << "SSRBias.udi_code" << "\t"; - out << "SSRBias.udi_phas" << "\t"; - out << "SSRBias.iod_code" << "\t"; - out << "SSRBias.iod_phas" << "\t"; - for (int i=0; i<2; ++i) out << "ssrBias.cbias_"<< i << "\t"; - for (int i=0; i<2; ++i) out << "ssrBias.cvari_"<< i << "\t"; - for (int i=0; i<2; ++i) out << "ssrBias.pbias_"<< i << "\t"; - for (int i=0; i<2; ++i) out << "ssrBias.pvari_"<< i << "\t"; - for (int i=0; i<2; ++i) - { - out << "ssrBias.ssrPhaseCh.signalIntInd_" << i << "\t"; - out << "ssrBias.ssrPhaseCh.signalWidIntInd_" << i << "\t"; - out << "ssrBias.ssrPhaseCh.signalDisconCnt_" << i << "\t"; - } - out << std::endl; - - // Body - for (auto& [Sat, ssrOut] : ssrOutMap) - { - out << epochNum << "\t"; - out << Sat.id() << "\t"; -// out << ssrOut.ssrEph.canExport<< "\t"; - out << ssrOut.ssrEph.t0 << "\t"; - out << ssrOut.ssrEph.udi << "\t"; - out << ssrOut.ssrEph.iod << "\t"; - out << ssrOut.ssrEph.iode << "\t"; - out << ssrOut.ssrEph.deph[0] << "\t"; - out << ssrOut.ssrEph.deph[1] << "\t"; - out << ssrOut.ssrEph.deph[2] << "\t"; - out << ssrOut.ssrEph.ddeph[0] << "\t"; - out << ssrOut.ssrEph.ddeph[1] << "\t"; - out << ssrOut.ssrEph.ddeph[2] << "\t"; - -// out << ssrOut.ssrClk.canExport<< "\t"; - out << ssrOut.ssrClk.t0 << "\t"; - out << ssrOut.ssrClk.udi << "\t"; - out << ssrOut.ssrClk.iod << "\t"; - out << ssrOut.ssrClk.dclk[0] << "\t"; - out << ssrOut.ssrClk.dclk[1] << "\t"; - out << ssrOut.ssrClk.dclk[2] << "\t"; - - out << ssrOut.ssrCodeBias.t0 << "\t"; - out << ssrOut.ssrPhasBias.t0 << "\t"; - out << ssrOut.ssrCodeBias.udi << "\t"; - out << ssrOut.ssrPhasBias.udi << "\t"; - out << ssrOut.ssrCodeBias.iod << "\t"; - out << ssrOut.ssrPhasBias.iod << "\t"; - for (auto& [key, val] : ssrOut.ssrCodeBias.obsCodeBiasMap) out << val.bias << "\t" << val.var << "\t"; - for (auto& [key, val] : ssrOut.ssrPhasBias.obsCodeBiasMap) out << val.bias << "\t" << val.var << "\t"; - - for (auto& [key, ssrPhaseCh] : ssrOut.ssrPhasBias.ssrPhaseChs) - { - out << ssrPhaseCh.signalIntInd << "\t"; - out << ssrPhaseCh.signalWidIntInd << "\t"; - out << ssrPhaseCh.signalDisconCnt << "\t"; - } - out << std::endl; - } - out << std::endl; -} - -void NtripRtcmStream::connectionError(const boost::system::error_code& err, std::string operation) -{ - if (acsConfig.output_log == false) - return; - - std::ofstream logStream(acsConfig.log_filename, std::ofstream::app); - - if (!logStream) - { - BOOST_LOG_TRIVIAL(warning) << "Warning: Error opening log file.\n"; - return; - } - - auto time = std::chrono::system_clock::to_time_t(system_clock::now()); - - bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("label", "connectionError")); - doc.append(kvp("Stream", url.path.substr(1,url.path.length()))); -// doc.append(kvp("Time", time)); - doc.append(kvp("BoostSysErrCode", err.value())); - doc.append(kvp("BoostSysErrMess", err.message())); - doc.append(kvp("SocketOperation", operation)); - - logStream << bsoncxx::to_json(doc) << std::endl; -} - -void NtripRtcmStream::serverResponse( - unsigned int status_code, - string http_version) -{ - if (acsConfig.output_log == false) - return; - - std::ofstream logStream(FileLog::path_log, std::ofstream::app); - - if (!logStream) - { - BOOST_LOG_TRIVIAL(warning) << "Warning: Error opening log file.\n"; - return; - } - - auto time = std::chrono::system_clock::to_time_t(system_clock::now()); - - bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("label", "serverResponse")); - doc.append(kvp("Stream", url.path.substr(1,url.path.length()))); -// doc.append(kvp("Time", time)); - doc.append(kvp("ServerStatus", (int)status_code)); - doc.append(kvp("VersionHTTP", http_version)); - - logStream << bsoncxx::to_json(doc) << std::endl; -} diff --git a/src/cpp/common/acsStream.hpp b/src/cpp/common/acsStream.hpp deleted file mode 100644 index 30acd4c36..000000000 --- a/src/cpp/common/acsStream.hpp +++ /dev/null @@ -1,362 +0,0 @@ - -#ifndef ACS_STREAM_H -#define ACS_STREAM_H - -#include -#include -#include -#include -#include -#include -#include -#include - - -using std::multimap; -using std::string; -using std::tuple; -using std::list; -using std::pair; -using std::map; - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace B_io = boost::iostreams; -namespace B_asio = boost::asio; - -using boost::asio::ip::tcp; - -#ifndef WIN32 -# include -# include -# include -# include -# include -#endif - - -#include "streamNav.hpp" -#include "streamObs.hpp" -#include "streamSp3.hpp" -#include "streamFile.hpp" -#include "streamRtcm.hpp" -#include "streamRinex.hpp" -#include "streamNtrip.hpp" - - - - -/** Object that streams RTCM data from NTRIP castors -*/ -struct NtripRtcmStream : NtripStream, RtcmStream -{ - NtripRtcmStream(const string& url_str) : NtripStream(url_str) - { - rtcmTraceFilename = ""; - rtcmMountPoint = url.path; - sourceString = url_str; - open(); - } - - void setUrl(const string& url_str) - { - sourceString = url_str; - NtripStream::setUrl(url_str); - } - - void open() - { -// connect(); - } - - ObsList getObs() override - { - //get all data available from the ntrip stream and convert it to an iostream for processing - getData(); - - B_io::basic_array_source input_source(receivedData.data(), receivedData.size()); - B_io::stream> inputStream(input_source); - - parseRTCM(inputStream); - - int pos = inputStream.tellg(); - if (pos < 0) - { - receivedData.clear(); - } - else - { - receivedData.erase(receivedData.begin(), receivedData.begin() + pos); - } - - //call the base function once it has been prepared - ObsList obsList = ObsStream::getObs(); - return obsList; - } - - void connectionError( - const boost::system::error_code& err, - string operation) override; - - void serverResponse( - unsigned int status_code, - string http_version) override; - - void getNav() override - { - //get all data available from the ntrip stream and convert it to an iostream for processing - getData(); - - B_io::basic_array_source input_source(receivedData.data(), receivedData.size()); - B_io::stream> inputStream(input_source); - - parseRTCM(inputStream); - - int pos = inputStream.tellg(); - if (pos < 0) - { - receivedData.clear(); - } - else - { - receivedData.erase(receivedData.begin(), receivedData.begin() + pos); - } - } -}; - -/** Object that streams RTCM data from a file. -* Overrides interface functions -*/ -struct FileRtcmStream : ACSFileStream, RtcmStream -{ - FileRtcmStream(const string& path) - { - sourceString = path; - setPath(path); - open(); - } - - void open() - { - openFile(); - } - - int lastObsListSize = -1; - - ObsList getObs() override - { -// getData(); not needed for files - FileState fileState = openFile(); - - if (obsListList.size() < 3) - { - parseRTCM(fileState.inputStream); - } - - //call the base function once it has been prepared - ObsList obsList = ObsStream::getObs(); - - lastObsListSize = obsList.size(); - return obsList; - } - - void getNav() override - { -// getData(); not needed for files - FileState fileState = openFile(); - - parseRTCM(fileState.inputStream); - } - - bool isDead() override - { - if (filePos < 0) - { - return true; - } - - FileState fileState = openFile(); - - if ( (lastObsListSize != 0) - ||(fileState.inputStream)) - { - return false; - } - else - { - return true; - } - } -}; - -/** Object that streams RINEX data from a file. -* Overrides interface functions -*/ -struct FileRinexStream : ACSFileStream, RinexStream -{ - FileRinexStream() - { - - } - - FileRinexStream(const string& path) - { - sourceString = path; - setPath(path); - open(); - } - - void open() - { - FileState fileState = openFile(); - - readRinexHeader(fileState.inputStream); - } - - int lastObsListSize = -1; - - ObsList getObs() override - { - FileState fileState = openFile(); - -// getData(); not needed for files - - if (obsListList.size() < 2) - { - parseRINEX(fileState.inputStream); - } - - //call the base function once it has been prepared - ObsList obsList = ObsStream::getObs(); - - lastObsListSize = obsList.size(); - return obsList; - } - - bool parse() - { - FileState fileState = openFile(); - - parseRINEX(fileState.inputStream); - - return true; - } - - bool isDead() override - { - if (filePos < 0) - { - return true; - } - - FileState fileState = openFile(); - - if ( lastObsListSize != 0 - ||fileState.inputStream) - { - return false; - } - else - { - return true; - } - } -}; - -/** Object that streams RINEX data from a file. -* Overrides interface functions -*/ -struct FileSp3Stream : ACSFileStream, SP3Stream -{ - FileSp3Stream() - { - - } - - FileSp3Stream(const string& path) - { - sourceString = path; - setPath(path); - open(); - } - - void open() - { - FileState fileState = openFile(); - - readSP3Header(fileState.inputStream); - } - - int lastObsListSize = -1; - - PseudoObsList getObs() override - { - FileState fileState = openFile(); - -// getData(); not needed for files - - if (obsListList.size() < 2) - { - parseSP3(fileState.inputStream); - } - - //call the base function once it has been prepared - PseudoObsList obsList = PseudoObsStream::getObs(); - - lastObsListSize = obsList.size(); - return obsList; - } - - bool parse() - { - FileState fileState = openFile(); - - parseSP3(fileState.inputStream); - - return true; - } - - bool isDead() override - { - if (filePos < 0) - { - return true; - } - - FileState fileState = openFile(); - - if ( lastObsListSize != 0 - ||fileState.inputStream) - { - return false; - } - else - { - return true; - } - } -}; - - -typedef std::shared_ptr ACSObsStreamPtr; -typedef std::shared_ptr ACSNavStreamPtr; -typedef std::shared_ptr ACSPseudoObsStreamPtr; - -extern multimap> ntripRtcmMultimap; -extern multimap obsStreamMultimap; -extern multimap navStreamMultimap; -extern multimap pseudoObsStreamMultimap; -extern map streamDOAMap; - -#endif diff --git a/src/cpp/common/algebra.cpp b/src/cpp/common/algebra.cpp index 7be2a248d..507f4c1ee 100644 --- a/src/cpp/common/algebra.cpp +++ b/src/cpp/common/algebra.cpp @@ -1,10 +1,7 @@ -#include #include -#include -using std::list; using std::pair; #include @@ -12,13 +9,14 @@ using std::pair; #include "eigenIncluder.hpp" #include "algebraTrace.hpp" -#include "streamTrace.hpp" +#include "binaryStore.hpp" #include "mongoWrite.hpp" #include "instrument.hpp" #include "acsConfig.hpp" #include "algebra.hpp" #include "common.hpp" #include "mongo.hpp" +#include "trace.hpp" // #pragma GCC optimize ("O0") @@ -44,6 +42,7 @@ using std::pair; * Internally, the data is stored in maps and Eigen matrices/vectors, but the accessors should be used rather than the vectors themselves to ensure that states have been initialised and are in the expected order. */ +const KFKey KFState::oneKey = {.type = KF::ONE}; struct KFStatistics { @@ -66,12 +65,12 @@ bool KFKey::operator <(const KFKey& b) const if (strCompare < 0) return true; if (strCompare > 0) return false; - - if (type < b.type) return true; - if (type > b.type) return false; if (Sat < b.Sat) return true; if (Sat > b.Sat) return false; + + if (type < b.type) return true; + if (type > b.type) return false; if (num < b.num) return true; else return false; @@ -83,12 +82,9 @@ bool KFKey::operator <(const KFKey& b) const */ void KFState::initFilterEpoch() { - ZAdditionMap. clear(); +// ZAdditionMap. clear(); initNoiseMap. clear(); - KFKey oneKey; - oneKey.type = KF::ONE; - for (auto& [key1, mapp] : stateTransitionMap) { if (key1 == oneKey) @@ -100,13 +96,15 @@ void KFState::initFilterEpoch() mapp.erase(oneKey); } - stateTransitionMap [oneKey][oneKey] = {1, 0}; + stateTransitionMap [oneKey][oneKey][0] = 1; +// ZTransitionMap [oneKey][oneKey] = 1; } /** Finds the position in the KF state vector of particular states. */ int KFState::getKFIndex( - KFKey key) ///< Key to search for in state + const KFKey key) ///< Key to search for in state +const { auto index = kfIndexMap.find(key); if (index == kfIndexMap.end()) @@ -116,13 +114,28 @@ int KFState::getKFIndex( return index->second; } +/** Finds the position in the KF state vector of particular states. +*/ +int KFState::getNoiseIndex( + const KFKey key) ///< Key to search for in state +const +{ + auto index = noiseIndexMap.find(key); + if (index == noiseIndexMap.end()) + { + return -1; + } + return index->second; +} + /** Returns the value and variance of a state within the kalman filter object */ bool KFState::getKFValue( - KFKey key, ///< Key to search for in state - double& value, ///< Output value - double* variance_ptr, ///< Optional variance output - double* adjustment_ptr) ///< Optional adjustment output + const KFKey key, ///< Key to search for in state + double& value, ///< Output value + double* variance_ptr, ///< Optional variance output + double* adjustment_ptr) ///< Optional adjustment output +const { auto a = kfIndexMap.find(key); if (a == kfIndexMap.end()) @@ -153,8 +166,8 @@ bool KFState::getKFValue( /** Returns the standard deviation of a state within the kalman filter object */ bool KFState::getKFSigma( - KFKey key, ///< Key to search for in state - double& sigma) ///< Output value + const KFKey key, ///< Key to search for in state + double& sigma) ///< Output value { auto a = kfIndexMap.find(key); if (a == kfIndexMap.end()) @@ -171,75 +184,61 @@ bool KFState::getKFSigma( return true; } -/** Sets the value of a state within the kalman filter object -*/ -bool KFState::setKFValue( - KFKey key, ///< Key to search for in state - double value) ///< Input value -{ - auto a = kfIndexMap.find(key); - if (a == kfIndexMap.end()) - { - return false; - } - - int index = a->second; - if (index >= x.size()) - { - return false; - } - - x(index) = value; - - return true; -} - /** Sets the process noise of a state within the kalman filter object */ bool KFState::setKFNoise( - KFKey kfKey, ///< Key to search for in state - double value) ///< Input value + const KFKey kfKey, ///< Key to search for in state + const double value) ///< Input value { procNoiseMap[kfKey] = value; return true; } - -/** Adds dynamics to a filter state by inserting off-diagonal, time dependent elements to transition matrix -*/ -void KFState::setKFTransRate( - KFKey dest, ///< Key to search for in state to change in transition - KFKey source, ///< Key to search for in state as source - double value, ///< Input value - InitialState initialState) ///< Initial state for rate state. +void KFState::setAccelerator( + const KFKey element, + const KFKey dotElement, + const KFKey dotDotElement, + const double value, + const InitialState initialState) { - addKFState(source, initialState); - - stateTransitionMap[dest][source] = {value, 1}; + addKFState(dotDotElement, initialState); + + //t^2 term + stateTransitionMap[element] [dotDotElement][2] = value; + + //t terms + stateTransitionMap[dotElement] [dotDotElement][1] = value; } /** Adds dynamics to a filter state by inserting off-diagonal, non-time dependent elements to transition matrix */ void KFState::setKFTrans( - KFKey dest, ///< Key to search for in state to change in transition - KFKey source, ///< Key to search for in state as source - double value, ///< Input value - InitialState initialState) ///< Initial state for rate state. + const KFKey dest, ///< Key to search for in state to change in transition + const KFKey source, ///< Key to search for in state as source + const double value, ///< Input value + const InitialState initialState) ///< Initial state. { addKFState(dest, initialState); - auto& [oldValue, rate] = stateTransitionMap[dest][source]; - - if (rate != 0) - { - std::cout << "ERROR: BAD TRANS SUM" << std::endl; - return; - } - - value += oldValue; + auto& transition = stateTransitionMap[dest][source][0]; - stateTransitionMap[dest][source] = {value, 0}; + transition += value; +} + +/** Adds dynamics to a filter state by inserting off-diagonal, time dependent elements to transition matrix +*/ +void KFState::setKFTransRate( + const KFKey integralKey, ///< Key to search for in state to change in transition + const KFKey rateKey, ///< Key to search for in state as source + const double value, ///< Input value + const InitialState initialRateState, ///< Initial state for rate state. + const InitialState initialIntegralState) ///< Initial state for the thing that is modified by the rate +{ + addKFState(rateKey, initialRateState); + addKFState(integralKey, initialIntegralState); + + stateTransitionMap[integralKey][rateKey][1] = value; } //todo aaron think about what happens when multiple states are removed at the same time - need to use the transition map contents as well as the z map contents? @@ -251,9 +250,9 @@ void KFState::setKFTrans( /** Remove a state from a kalman filter object. */ void KFState::removeState( - KFKey kfKey) ///< Key to search for in state + const KFKey kfKey) ///< Key to search for in state { - ZTransitionMap. erase(kfKey); +// ZTransitionMap. erase(kfKey); stateTransitionMap. erase(kfKey); procNoiseMap. erase(kfKey); gaussMarkovTauMap. erase(kfKey); @@ -265,8 +264,8 @@ void KFState::removeState( * Call consolidateKFState() to apply the list to the filter object */ bool KFState::addKFState( - KFKey kfKey, ///< The key to add to the state - InitialState initialState) ///< The initial conditions to add to the state + const KFKey kfKey, ///< The key to add to the state + const InitialState initialState) ///< The initial conditions to add to the state { auto iter = stateTransitionMap.find(kfKey); if (iter != stateTransitionMap.end()) @@ -281,15 +280,14 @@ bool KFState::addKFState( //this is a new state, add to the state transition matrix to create a new state. - KFKey ONE = {KF::ONE}; - ZAdditionMap [kfKey] = 1; - ZTransitionMap [kfKey][kfKey] = 1; - stateTransitionMap [kfKey][kfKey] = {1, 0}; - stateTransitionMap [kfKey][ONE] = {initialState.x, 0}; - initNoiseMap [kfKey] = initialState.P; - procNoiseMap [kfKey] = initialState.Q; - gaussMarkovTauMap [kfKey] = initialState.tau; - gaussMarkovMuMap [kfKey] = initialState.mu; +// ZAdditionMap [kfKey] = 1; +// ZTransitionMap [kfKey][kfKey] = 1; + stateTransitionMap [kfKey][kfKey] [0] = 1; + stateTransitionMap [kfKey][oneKey] [0] = initialState.x; + initNoiseMap [kfKey] = initialState.P; + procNoiseMap [kfKey] = initialState.Q; + gaussMarkovTauMap [kfKey] = initialState.tau; + gaussMarkovMuMap [kfKey] = initialState.mu; if (initialState.P == 0) { @@ -301,15 +299,76 @@ bool KFState::addKFState( } + /** Tries to add a noise element. * If it does not exist, it adds it to a list of states to be added. * Call consolidateKFState() to apply the list to the filter object */ void KFState::addNoiseElement( - ObsKey obsKey, - double variance) + const KFKey kfKey, + const double variance) +{ + noiseElementMap[kfKey] = variance; +} + +/** Add process noise and dynamics to filter object manually. BEWARE! + * Not recommended for ordinary use, likely to break things. Dont touch unless you really know what you're doing. + * Hint - you dont really know what you're doing + */ +void KFState::manualStateTransition( + Trace& trace, + GTime newTime, + MatrixXd& F, + MatrixXd& Q0) +{ + if (newTime != GTime::noTime()) + { + time = newTime; + } + + //output the state transition matrix to a trace file (used by RTS smoother) + if (rts_basename.empty() == false) + { + TransitionMatrixObject transitionMatrixObject; + transitionMatrixObject.rows = F.rows(); + transitionMatrixObject.cols = F.cols(); + + for (int row = 0; row < F.rows(); row++) + for (int col = 0; col < F.cols(); col++) + { + double transition = F(row,col);; + + if (transition == 0) + { + continue; + } + + transitionMatrixObject.forwardTransitionMap[{row, col}] = transition; + } + + spitFilterToFile(transitionMatrixObject, E_SerialObject::TRANSITION_MATRIX, rts_basename + FORWARD_SUFFIX); + } + + //compute the updated states and permutation and covariance matrices + VectorXd Fx = F * x; + if (simulate_filter_only == false) + { + dx = Fx - x; + x = (Fx ).eval(); + P = (F * P * F.transpose() + Q0 ).eval(); + } + + initFilterEpoch(); +} + +void KFState::noiseElementStateTransition() { - noiseElementMap[obsKey] = variance; + int row = 0; + for (auto& [key, value] : noiseElementMap) + { + noiseIndexMap[key] = row; + row++; + } } /** Add process noise and dynamics to filter object according to time gap. @@ -317,15 +376,14 @@ void KFState::addNoiseElement( */ void KFState::stateTransition( Trace& trace, ///< Trace file for output - GTime newTime) ///< Time of update for process noise and dynamics (s) + GTime newTime, ///< Time of update for process noise and dynamics (s) + MatrixXd* stm_ptr) ///< Optional pointer to output state transition matrix { - KFState& kfState = *this; - double tgap = 0; if ( newTime != GTime::noTime() &&time != GTime::noTime()) { - tgap = newTime - time; + tgap = (newTime - time).to_double(); } if ( newTime != GTime::noTime()) @@ -333,8 +391,6 @@ void KFState::stateTransition( time = newTime; } -// TestStack ts(__FUNCTION__); - int newStateCount = stateTransitionMap.size(); if (newStateCount == 0) { @@ -364,100 +420,103 @@ void KFState::stateTransition( { continue; } - auto& [value, tExp] = values; - - double tau = -1; - auto gmIter = gaussMarkovTauMap.find(sourceStateKey); - if (gmIter != gaussMarkovTauMap.end()) + for (auto& [tExp, value] : values) { - auto& [dummy, sourceTau] = *gmIter; - - tau = sourceTau; - } + double tau = -1; + + auto gmIter = gaussMarkovTauMap.find(sourceStateKey); + if (gmIter != gaussMarkovTauMap.end()) + { + auto& [dummy, sourceTau] = *gmIter; + + tau = sourceTau; + } - double scalar = 1; - - if (tau < 0) - { - //Random Walk model (special case for First Order Gauss Markov model when tau == inf) + double scalar = 1; + + if (tau < 0) + { + //Random Walk model (special case for First Order Gauss Markov model when tau == inf) + + for (int i = 0; i < tExp; i++) + { + scalar *= tgap / (i+1); + } + + // F(row, sourceIndex) = value * scalar; + F.coeffRef(row, sourceIndex) += value * scalar; + + continue; + } + + //First Order Gauss Markov model, Ref: Carpenter and Lee (2008) - A Stable Clock Error Model Using Coupled First- and Second-Order Gauss-Markov Processes - https://ntrs.nasa.gov/api/citations/20080044877/downloads/20080044877.pdf + double tempTerm = 1; + scalar = exp(-tgap/tau); + for (int i = 0; i < tExp; i++) { - scalar *= tgap / (i+1); + scalar = tau * (tempTerm - scalar); //recursive formula derived according to Ref: Carpenter and Lee (2008) + tempTerm *= tgap / (i+1); } -// F(row, sourceIndex) = value * scalar; - F.insert(row, sourceIndex) = value * scalar; + double transition = value * scalar; - continue; - } - - //First Order Gauss Markov model, Ref: Carpenter and Lee (2008) - A Stable Clock Error Model Using Coupled First- and Second-Order Gauss-Markov Processes - https://ntrs.nasa.gov/api/citations/20080044877/downloads/20080044877.pdf - - double tempTerm = 1; - scalar = exp(-tgap/tau); - - for (int i = 0; i < tExp; i++) - { - scalar = tau * (tempTerm - scalar); //recursive formula derived according to Ref: Carpenter and Lee (2008) - tempTerm *= tgap / (i+1); - } - - double transition = value * scalar; - -// F(row, sourceIndex) = transition; - F.insert(row, sourceIndex) = transition; - - - //Add state transitions to ONE element, to allow for tiedown to average value mu - //derived from integrating and distributing terms for v = (v0 - mu) * exp(-t/tau) + mu; - //tempTerm calculated above appears to be same as required for these terms too, (at least for tExp = 0,1) - - auto muIter = gaussMarkovMuMap.find(sourceStateKey); - if (muIter != gaussMarkovMuMap.end()) - { - auto& [dummy2, mu] = *muIter; + // F(row, sourceIndex) = transition; + F.coeffRef(row, sourceIndex) += transition; -// F(row, 0) = mu * (tempTerm - transition); - F.coeffRef(row, 0) = mu * (tempTerm - transition); + + //Add state transitions to ONE element, to allow for tiedown to average value mu + //derived from integrating and distributing terms for v = (v0 - mu) * exp(-t/tau) + mu; + //tempTerm calculated above appears to be same as required for these terms too, (at least for tExp = 0,1) + + auto muIter = gaussMarkovMuMap.find(sourceStateKey); + if (muIter != gaussMarkovMuMap.end()) + { + auto& [dummy2, mu] = *muIter; + + // F(row, 0) = mu * (tempTerm - transition); + F.coeffRef(row, 0) += mu * (tempTerm - transition); + } } } row++; } - for (auto& [kfKey1, map] : ZTransitionMap) - for (auto& [kfKey2, value] : map) - { - int index2 = getKFIndex(kfKey2); - - if ( (index2 < 0) - ||(index2 >= F.cols())) - { - continue; - } - - auto it = newKFIndexMap.find(kfKey1); - if (it == newKFIndexMap.end()) - { - std::cout << std::endl << "Bookkeeping error"; - continue; - } - - auto& [dummy, row] = *it; - -// F_z(row, index2) = value; - F_z.insert(row, index2) = value; - } - - - for (auto& [kfKey, value] : ZAdditionMap) - { - int row = newKFIndexMap[kfKey]; - - Z_plus(row) = value; - } + noiseElementStateTransition(); + +// for (auto& [kfKey1, map] : ZTransitionMap) +// for (auto& [kfKey2, value] : map) +// { +// int index2 = getKFIndex(kfKey2); +// +// if ( (index2 < 0) +// ||(index2 >= F.cols())) +// { +// continue; +// } +// +// auto it = newKFIndexMap.find(kfKey1); +// if (it == newKFIndexMap.end()) +// { +// std::cout << std::endl << "Bookkeeping error"; +// continue; +// } +// +// auto& [dummy, row] = *it; +// +// F_z.insert(row, index2) = value; +// } + + +// for (auto& [kfKey, value] : ZAdditionMap) +// { +// int row = newKFIndexMap[kfKey]; +// +// Z_plus(row) = value; +// } //scale and add process noise MatrixXd Q0 = MatrixXd::Zero(newStateCount, newStateCount); @@ -484,12 +543,11 @@ void KFState::stateTransition( } //add time dependent process noise - if (tgap) + if (tgap) for (auto& [dest, map] : stateTransitionMap) for (auto& [source, vals] : map) + for (auto& [tExp, val] : vals) { - auto& [val, tExp] = vals; - auto initIter = initNoiseMap.find(dest); if (initIter != initNoiseMap.end()) { @@ -552,11 +610,11 @@ void KFState::stateTransition( //Random Walk model (special case for First Order Gauss Markov model when tau == inf) if (tExp == 0) { Q0(destIndex, destIndex) += sourceProcessNoise / 1 * tgap;} - else if (tExp == 1) { Q0(destIndex, destIndex) += sourceProcessNoise / 3 * tgap * tgap * tgap; +// else if (tExp == 1) { Q0(destIndex, destIndex) += sourceProcessNoise / 3 * tgap * tgap * tgap; // Q0(sourceIndex, destIndex) += sourceProcessNoise / 2 * tgap * tgap; // Q0(destIndex, sourceIndex) += sourceProcessNoise / 2 * tgap * tgap; - } - else if (tExp == 2) { Q0(destIndex, destIndex) += sourceProcessNoise / 20 * tgap * tgap * tgap * tgap * tgap;} +// } +// else if (tExp == 2) { Q0(destIndex, destIndex) += sourceProcessNoise / 20 * tgap * tgap * tgap * tgap * tgap;} } else { @@ -602,6 +660,11 @@ void KFState::stateTransition( spitFilterToFile(transitionMatrixObject, E_SerialObject::TRANSITION_MATRIX, rts_basename + FORWARD_SUFFIX); } + if (stm_ptr) + { + *stm_ptr = F; + } + //compute the updated states and permutation and covariance matrices VectorXd Fx = F * x; if (F.rows() == F.cols()) @@ -614,25 +677,32 @@ void KFState::stateTransition( dx = VectorXd::Zero(F.rows()); } - { -// Instrument instrument("PPPalgebra1"); - Z = (F_z * Z * F_z.transpose() ).eval(); - } +// if (ZTransitionMap.empty() == false) +// { +// // Instrument instrument("PPPalgebra1"); +// Z = (F_z * Z * F_z.transpose() ).eval(); +// } { // Instrument instrument("PPPalgebra2"); x = (Fx ).eval(); } + if (simulate_filter_only) { -// Instrument instrument("PPPalgebra3"); - P = (F * P * F.transpose() + Q0 ).eval(); + Q0.setZero(); } { -// Instrument instrument("PPPalgebra4"); - Z += Z_plus.asDiagonal(); +// Instrument instrument("PPPalgebra3"); + P = (F * P * F.transpose() + Q0 ).eval(); } +// if (ZAdditionMap.empty() == false) +// { +// // Instrument instrument("PPPalgebra4"); +// Z += Z_plus.asDiagonal(); +// } // std::cout << "F_z" << std::endl << F_z << std::endl; -// std::cout << "F" << std::endl << F << std::endl; +// std::cout << "F" << std::endl << MatrixXd(F) << std::endl; // std::cout << "Z" << std::endl << Z << std::endl; +// std::cout << "Q0" << std::endl << Q0 << std::endl; //replace the index map with the updated version that corresponds to the updated state kfIndexMap = std::move(newKFIndexMap); @@ -672,7 +742,7 @@ void KFState::preFitSigmaCheck( measRatios = measVariations / measVariances; measRatios = measRatios.isFinite() .select(measRatios, 0); - trace << std::endl << "DOING PRE SIGMA CHECK: "; +// trace << std::endl << "DOING PRE SIGMA CHECK: "; } else if (w_test) { @@ -691,7 +761,7 @@ void KFState::preFitSigmaCheck( stateRatios = stateVariations / stateVariances; stateRatios = stateRatios.isFinite().select(stateRatios, 0); - trace << std::endl << "DOING W-TEST: "; +// trace << std::endl << "DOING W-TEST: "; } statistics.sumOfSquares = measRatios.sum(); @@ -706,7 +776,7 @@ void KFState::preFitSigmaCheck( double maxMeasRatio = measRatios .maxCoeff(&measIndex); //if any are outside the expected values, flag an error - if ( maxStateRatio > maxMeasRatio + if ( maxStateRatio > maxMeasRatio * 0.95 &&maxStateRatio > SQR(sigma_threshold)) { int chunkIndex = stateIndex + begX; @@ -735,21 +805,19 @@ void outputResiduals( Trace& trace, ///< Trace file to output to KFMeas& kfMeas, ///< Measurements, noise, and design matrix int iteration, ///< Number of iterations prior to this check + string suffix, ///< Suffix to use in header int begH, ///< Index of first measurement to process int numH) ///< Number of measurements to process { - trace << std::endl << "+RESIDUALS" << std::endl; - tracepdeex(2, trace, "#\t%2s\t%19s\t%8s\t%3s\t%7s\t%13s\t%13s\t%16s\n", "It", "Time", "Str", "Sat", "Type", "Prefit Res", "Postfit Res", "Meas Variance"); + string name = "RESIDUALS"; + name += suffix; + Block block(trace, name); + + tracepdeex(0, trace, "#\t%2s\t%22s\t%10s\t%4s\t%4s\t%5s\t%13s\t%13s\t%16s\t %s\n", "It", "Time", "Type", "Sat", "Str", "Num", "Prefit Res", "Postfit Res", "Meas Variance", "Comments"); for (int i = begH; i < begH + numH; i++) { - if (kfMeas.R(i,i) == 0) - { - continue; - } - - tracepdeex(2, trace, "%%\t%2d\t%19s\t%20s\t%13.4f\t%13.4f\t%16.9f\n", iteration, kfMeas.time.to_string(0).c_str(), ((string)kfMeas.obsKeys[i]).c_str(), kfMeas.V(i), kfMeas.VV(i - begH), kfMeas.R(i,i)); + tracepdeex(0, trace, "%%\t%2d\t%21s\t%20s\t%13.8f\t%13.8f\t%16.9f\t %s\n", iteration, kfMeas.time.to_string(2).c_str(), ((string)kfMeas.obsKeys[i]).c_str(), kfMeas.V(i), kfMeas.VV(i), kfMeas.R(i,i), kfMeas.obsKeys[i].comment.c_str()); } - trace << "-RESIDUALS" << std::endl; } /** Compare variances of measurements and filtered states to detect unreasonable values @@ -757,7 +825,6 @@ void outputResiduals( void KFState::postFitSigmaChecks( Trace& trace, ///< Trace file to output to KFMeas& kfMeas, ///< Measurements, noise, and design matrix - VectorXd& xp, ///< The post-filter state vector to compare with measurements VectorXd& dx, ///< The innovations from filtering to recalculate the deltas. int iteration, ///< Number of iterations prior to this check KFKey& badStateKey, ///< Key to the state that has worst ratio (only if worse than badMeasIndex) @@ -785,15 +852,10 @@ void KFState::postFitSigmaChecks( if (output_residuals) { - outputResiduals(trace, kfMeas, iteration, begH, numH); - } - - if (acsConfig.output_mongo_measurements) - { - mongoMeasResiduals(kfMeas.time, kfMeas.obsKeys, kfMeas.V, kfMeas.VV, kfMeas.R, "", begH, numH); + outputResiduals(trace, kfMeas, iteration, suffix, begH, numH); } - trace << std::endl << "DOING SIGMACHECK: "; +// trace << std::endl << "DOING SIGMACHECK: "; statistics.sumOfSquares = measRatios.sum(); statistics.averageRatio = measRatios.mean(); @@ -943,9 +1005,14 @@ int KFState::kFilter( switch (inverter) { default: + { + tracepdeex(1, trace, "\nWarning: kalman filter inverter type %s not supported, reverting", inverter._to_string()); + inverter = E_Inverter::LDLT; + continue; + } case E_Inverter::LDLT: { - auto QQ = Q.triangularView().adjoint(); + auto QQ = Q.triangularView().transpose(); LDLT solver; solver.compute(QQ); if (solver.info() != Eigen::ComputationInfo::Success) @@ -974,7 +1041,7 @@ int KFState::kFilter( } case E_Inverter::LLT: { - auto QQ = Q.triangularView().adjoint(); + auto QQ = Q.triangularView().transpose(); LLT solver; solver.compute(QQ); if (solver.info() != Eigen::ComputationInfo::Success) @@ -1065,27 +1132,39 @@ bool KFState::chiQC( VectorXd v = y - H * xp; double v_Wv = v.transpose() * W.asDiagonal() * v; - //trace << std::endl << "chiqcV" << v.rows() << std::endl; tracematpde(5, trace, v, 15, 5); + //trace << std::endl << "chiqcV" << v.rows() << std::endl; - int obsNumber = v.rows() - x.rows() + 1; - double val = v_Wv / (obsNumber); + dof = v.rows() - (x.rows() - 1); //ignore KF::ONE element -> -1 + chi = v_Wv; - double thres; - if (obsNumber <= 100) thres = chisqr_arr[obsNumber - 1] / (obsNumber); - else thres = 3; + if (dof < 1) + { + chiQCPass = true; + return true; + } + + boost::math::normal normDist; + + double alpha = cdf(complement(normDist, sigma_threshold)) * 2; //two-tailed + + boost::math::chi_squared chiSqDist(dof); + double thres = quantile(complement(chiSqDist, alpha)); + /* chi-square validation */ - if (val > thres) + if (chi > thres) { - tracepdeex(6, trace, " ChiSquare error detected"); + tracepdeex(5, trace, " ChiSquare error detected: dof:%d chi:%f thres:%f", dof, chi, thres); // auto variations = v.array().square(); // Eigen::MatrixXf::Index index; // trace << " -> LARGEe ERROR OF " << sqrt(variations.maxCoeff(&index)) << " AT " << index; + chiQCPass = false; return false; } + chiQCPass = true; return true; } @@ -1096,6 +1175,8 @@ KFMeas KFState::combineKFMeasList( GTime measTime, ///< Time to use for measurements and hence state transitions MatrixXd* noiseMatrix_ptr) ///< Optional pointer to use custom noise matrix { + Instrument instrument(__FUNCTION__); + int numMeas = kfEntryList.size(); KFMeas kfMeas; @@ -1111,8 +1192,9 @@ KFMeas KFState::combineKFMeasList( kfMeas.VV .resize(numMeas); kfMeas.Y .resize(numMeas); - kfMeas.R = MatrixXd::Zero(numMeas, numMeas); - kfMeas.H = MatrixXd::Zero(numMeas, x.rows()); + kfMeas.R = MatrixXd::Zero(numMeas, numMeas); + kfMeas.H = MatrixXd::Zero(numMeas, x.rows()); + kfMeas.H_star = MatrixXd::Zero(numMeas, noiseIndexMap.size()); kfMeas.obsKeys .resize(numMeas); kfMeas.metaDataMaps .resize(numMeas); @@ -1130,12 +1212,23 @@ KFMeas KFState::combineKFMeasList( int index = getKFIndex(kfKey); if (index < 0) { - std::cout << "hhuh?" << kfKey << std::endl; + std::cout << "Code error: Trying to create measurement for undefined key, check stateTransition() is called first: " << kfKey << std::endl; return KFMeas(); } kfMeas.H(meas, index) = value; } + for (auto& [kfKey, value] : entry.noiseEntryMap) + { + int index = getNoiseIndex(kfKey); + if (index < 0) + { + std::cout << "Code error: Trying to create measurement for undefined key, check stateTransition() or noiseElementStateTransition() is called first: " << kfKey << std::endl; + return KFMeas(); + } + kfMeas.H_star(meas, index) = value; + } + kfMeas.obsKeys [meas] = std::move(entry.obsKey); kfMeas.metaDataMaps [meas] = std::move(entry.metaDataMap); kfMeas.componentLists [meas] = std::move(entry.componentList); @@ -1151,13 +1244,13 @@ KFMeas KFState::combineKFMeasList( { VectorXd uncorrelatedNoise = VectorXd::Zero(noiseElementMap.size()); - map noiseIndexMap; + map noiseIndexMap; int noises = 0; - for (auto& [obsKey, variance] : noiseElementMap) + for (auto& [kfKey, variance] : noiseElementMap) { uncorrelatedNoise(noises) = variance; - noiseIndexMap[obsKey] = noises; + noiseIndexMap[kfKey] = noises; noises++; } @@ -1166,9 +1259,9 @@ KFMeas KFState::combineKFMeasList( meas = 0; for (auto& entry: kfEntryList) { - for (auto& [obsKey, value] : entry.noiseEntryMap) + for (auto& [kfKey, value] : entry.noiseEntryMap) { - int noiseIndex = noiseIndexMap[obsKey]; + int noiseIndex = noiseIndexMap[kfKey]; R_A.insert(meas, noiseIndex) = value; } @@ -1176,7 +1269,6 @@ KFMeas KFState::combineKFMeasList( meas++; } - Instrument instrument("PPPnoisELment"); // std::cout << R_A << std::endl; kfMeas.R = R_A * uncorrelatedNoise.asDiagonal() * R_A.transpose(); @@ -1223,75 +1315,43 @@ bool KFState::doMeasRejectCallbacks( return true; } -bool ObsKey::operator ==(const ObsKey& b) const -{ - if (str.compare(b.str) != 0) return false; - if (Sat != b.Sat) return false; - if (type.compare(b.type)!= 0) return false; - if (num != b.num) return false; - else return true; -} - -bool ObsKey::operator <(const ObsKey& b) const -{ - int typeCompare = type.compare(b.type); - if (typeCompare < 0) return true; - if (typeCompare > 0) return false; - - int strCompare = str.compare(b.str); - if (strCompare < 0) return true; - if (strCompare > 0) return false; - - if (Sat < b.Sat) return true; - if (Sat > b.Sat) return false; - - if (num < b.num) return true; - if (num > b.num) return false; - - else return false; -} - /** Kalman filter operation */ -int KFState::filterKalman( - Trace& trace, ///< Trace file for output - KFMeas& kfMeas, ///< Measurement object - bool innovReady, ///< Innovation already constructed - list* filterChunkList_ptr) ///< Optional ist of chunks for parallel processing of sub filters +void KFState::filterKalman( + Trace& trace, ///< Trace file for output + KFMeas& kfMeas, ///< Measurement object + bool innovReady, ///< Innovation already constructed + vector* filterChunkList_ptr) ///< Optional ist of chunks for parallel processing of sub filters { - KFState& kfState = *this; - + Instrument instrument(__FUNCTION__); + if (kfMeas.time != GTime::noTime()) { - kfState.time = kfMeas.time; - } - - if (kfState.rts_basename.empty() == false) - { - spitFilterToFile(kfState, E_SerialObject::FILTER_MINUS, kfState.rts_basename + FORWARD_SUFFIX); + time = kfMeas.time; } if (kfMeas.H.rows() == 0) { //nothing to be done, clean up and return early - if (kfState.rts_basename.empty() == false) + if (rts_basename.empty() == false) { - spitFilterToFile(kfState, E_SerialObject::FILTER_PLUS, kfState.rts_basename + FORWARD_SUFFIX); - spitFilterToFile(kfMeas, E_SerialObject::MEASUREMENT, kfState.rts_basename + FORWARD_SUFFIX); + spitFilterToFile(*this, E_SerialObject::FILTER_MINUS, rts_basename + FORWARD_SUFFIX); + spitFilterToFile(*this, E_SerialObject::FILTER_PLUS, rts_basename + FORWARD_SUFFIX); + spitFilterToFile(kfMeas, E_SerialObject::MEASUREMENT, rts_basename + FORWARD_SUFFIX); } - return 1; + return; } /* kalman filter measurement update */ if (innovReady == false) { - kfMeas.V = kfMeas.Y - kfMeas.H * kfState.x; + kfMeas.V = kfMeas.Y - kfMeas.H * x; kfMeas.VV = kfMeas.V; } - list dummyFilterChunkList; + vector dummyFilterChunkList; if (filterChunkList_ptr == nullptr) { filterChunkList_ptr = &dummyFilterChunkList; @@ -1328,7 +1388,7 @@ int KFState::filterKalman( KFKey badState; int badMeasIndex = -1; - kfState.preFitSigmaCheck(chunkTrace, kfMeas, badState, badMeasIndex, statistics, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); + preFitSigmaCheck(chunkTrace, kfMeas, badState, badMeasIndex, statistics, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); if (badState.type) { chunkTrace << std::endl << "Prefit check failed state test"; bool keepGoing = doStateRejectCallbacks (chunkTrace, kfMeas, badState); /*continue;*/ } //always fallthrough if (badMeasIndex >= 0) { chunkTrace << std::endl << "Prefit check failed measurement test"; bool keepGoing = doMeasRejectCallbacks (chunkTrace, kfMeas, badMeasIndex); continue; } //retry next iteration @@ -1356,31 +1416,49 @@ int KFState::filterKalman( { auto& chunkTrace = *filterChunk.trace_ptr; - bool pass = kfState.kFilter(chunkTrace, kfMeas, xp, Pp, dx, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); + bool pass = kFilter(chunkTrace, kfMeas, xp, Pp, dx, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); if (pass == false) { chunkTrace << "FILTER FAILED" << std::endl; - return 0; + return; } // chunkTrace << "\nFrom " << filterChunk.begH << " for " << filterChunk.numH; // chunkTrace << "\nStat " << filterChunk.begX << " for " << filterChunk.numX; // outputStates(chunkTrace, " Debug"); - + if (sigma_check == false) { - continue; + break; } KFKey badState; int badMeasIndex = -1; - kfState.postFitSigmaChecks(chunkTrace, kfMeas, xp, dx, i, badState, badMeasIndex, statistics, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); - + postFitSigmaChecks(chunkTrace, kfMeas, dx, i, badState, badMeasIndex, statistics, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); + bool stopIterating = false; if (badState.type) { chunkTrace << std::endl << "Postfit check failed state test"; bool keepGoing = doStateRejectCallbacks (chunkTrace, kfMeas, badState); /*continue;*/ } //always fallthrough - if (badMeasIndex >= 0) { chunkTrace << std::endl << "Postfit check failed measurement test"; bool keepGoing = doMeasRejectCallbacks (chunkTrace, kfMeas, badMeasIndex); continue; } //retry next iteration - else { chunkTrace << std::endl << "Postfit check passed"; break; } //all ok, finish + if (badMeasIndex >= 0) { chunkTrace << std::endl << "Postfit check failed measurement test"; bool keepGoing = doMeasRejectCallbacks (chunkTrace, kfMeas, badMeasIndex); stopIterating = false; } //retry next iteration + else { chunkTrace << std::endl << "Postfit check passed"; stopIterating = true; } //all ok, finish + + if ( stopIterating + ||i == max_filter_iter - 1) + { + statisticsMap["Filter iterations " + std::to_string(i+1)]++; + + break; + } + } + + if (outputMongoMeasurements) + { + mongoMeasResiduals (kfMeas.time, kfMeas, suffix, filterChunk.begH, filterChunk.numH); + } + if ( acsConfig.store_binary_measurements + && outputMongoMeasurements) + { + storeResiduals (kfMeas.time, kfMeas.obsKeys, kfMeas.V, kfMeas.VV, kfMeas.R, suffix, filterChunk.begH, filterChunk.numH); } testStatistics.sumOfSquaresPost += statistics.sumOfSquares; @@ -1398,17 +1476,17 @@ int KFState::filterKalman( switch (chi_square_mode) { - case E_ChiSqMode::INNOVATION: { testStatistics.chiSq += kfState.innovChiSquare(chunkTrace, kfMeas, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); break; } - case E_ChiSqMode::MEASUREMENT: { testStatistics.chiSq += kfState.measChiSquare( chunkTrace, kfMeas, dx, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); break; } - case E_ChiSqMode::STATE: { testStatistics.chiSq += kfState.stateChiSquare(chunkTrace, Pp, dx, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); break; } + case E_ChiSqMode::INNOVATION: { testStatistics.chiSq += innovChiSquare (chunkTrace, kfMeas, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); break; } + case E_ChiSqMode::MEASUREMENT: { testStatistics.chiSq += measChiSquare (chunkTrace, kfMeas, dx, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); break; } + case E_ChiSqMode::STATE: { testStatistics.chiSq += stateChiSquare (chunkTrace, Pp, dx, filterChunk.begX, filterChunk.numX, filterChunk.begH, filterChunk.numH); break; } default: break; } } - trace << std::endl << "Number of measurements:" << kfMeas.H.rows() << "\tNumber of states:" << kfState.x.rows() - 1; + trace << std::endl << "Number of measurements:" << kfMeas.H.rows() << "\tNumber of states:" << x.rows() - 1; - if (chi_square_mode == +E_ChiSqMode::STATE) testStatistics.dof = kfState.x.rows() - 1; - else testStatistics.dof = kfMeas. H.rows(); + if (chi_square_mode == +E_ChiSqMode::STATE) testStatistics.dof = x.rows() - 1; + else testStatistics.dof = kfMeas. H.rows(); testStatistics.chiSqPerDof = testStatistics.chiSq / testStatistics.dof; @@ -1428,25 +1506,36 @@ int KFState::filterKalman( << "\tChi-square per DOF: " << testStatistics.chiSqPerDof << std::endl; } - if (acsConfig.output_mongo_test_stats) + if (acsConfig.localMongo.output_test_stats) { - mongoTestStat(kfState, testStatistics); + mongoTestStat(*this, testStatistics); } -// if (pass) + if (rts_basename.empty() == false) { - kfState.x = std::move(xp); - kfState.P = std::move(Pp); + spitFilterToFile(*this, E_SerialObject::FILTER_MINUS, rts_basename + FORWARD_SUFFIX); } - if (kfState.rts_basename.empty() == false) + if (simulate_filter_only) { - spitFilterToFile(kfState, E_SerialObject::FILTER_PLUS, kfState.rts_basename + FORWARD_SUFFIX); - spitFilterToFile(kfMeas, E_SerialObject::MEASUREMENT, kfState.rts_basename + FORWARD_SUFFIX); + dx = VectorXd::Zero(x.rows()); + } + else + { + x = std::move(xp); + P = std::move(Pp); + } + + if (rts_basename.empty() == false) + { + spitFilterToFile(*this, E_SerialObject::FILTER_PLUS, rts_basename + FORWARD_SUFFIX); + spitFilterToFile(kfMeas, E_SerialObject::MEASUREMENT, rts_basename + FORWARD_SUFFIX); } initFilterEpoch(); - return 1; + noiseElementMap.clear(); + + return; } /** Perform least squares using the measurements in the KFMeas object @@ -1455,16 +1544,14 @@ int KFState::filterLeastSquares( Trace& trace, ///< Trace to output to KFMeas& kfMeas) ///< Measurements, noise, and design matrix { - KFState& kfState = *this; - trace << std::endl << " -------STARTING LS --------" << std::endl; //invert measurement noise matrix to get a weight matrix - kfMeas.W = (1 / kfMeas.R.diagonal().array()).matrix(); //todo, aaron straight inversion? + kfMeas.W = (1 / kfMeas.R.diagonal().array()).matrix(); - if (kfMeas.R.rows() < kfState.x.rows()) + if (kfMeas.R.rows() < x.rows()) { - trace << std::endl << "Insufficient measurements for least squares " << kfMeas.R.rows() << " " << kfState.x.rows(); + trace << std::endl << "Insufficient measurements for least squares " << kfMeas.R.rows() << " " << x.rows(); return 0; } @@ -1495,19 +1582,15 @@ int KFState::filterLeastSquares( // std::cout << std::endl << "postLSQ" << std::endl; - chiQCPass = kfState.chiQC(trace, kfMeas, x1); - if (chiQCPass == false) - { -// return 0; //todo aaron - } + chiQC(trace, kfMeas, x1); //copy results to outputs - for (int i = 0; i < kfState.x.rows(); i++) + for (int i = 0; i < x.rows(); i++) { - if (kfState.P(i,i) == 0) + if (P(i,i) == 0) { - kfState.P(i,i) = Qinv(i,i); - kfState.x(i) = x1(i); + P(i,i) = Qinv(i,i); + x(i) = x1(i); } } @@ -1624,9 +1707,9 @@ void KFState::leastSquareInitStates( leastSquareMeasSubs.H = leastSquareMeas.H(all, usedCols); //invert measurement noise matrix to get a weight matrix - leastSquareMeasSubs.W = (1 / leastSquareMeasSubs.R.diagonal().array()).matrix();//todo aaron straight inversion? + leastSquareMeasSubs.W = (1 / leastSquareMeasSubs.R.diagonal().array()).matrix(); - VectorXd w = (1 / leastSquareMeasSubs.R.diagonal().array()).matrix().col(0); //todo aaron straight inversion? + VectorXd w = (1 / leastSquareMeasSubs.R.diagonal().array()).matrix().col(0); for (int i = 0; i < w.rows(); i++) { @@ -1651,6 +1734,10 @@ void KFState::leastSquareInitStates( auto& H = leastSquareMeasSubs.H; auto& Y = leastSquareMeasSubs.Y; +// std::cout << "\nkfmeasY\n" << kfMeas.Y << "\n"; +// std::cout << "\nkfmeasV\n" << kfMeas.V << "\n"; +// std::cout << "\nY\n" << Y << "\n"; + //calculate least squares solution MatrixXd W = w.asDiagonal(); MatrixXd H_W = H.transpose() * W; @@ -1675,11 +1762,7 @@ void KFState::leastSquareInitStates( } // std::cout << std::endl << "postLSQ" << std::endl; - chiQCPass = chiQC(trace, leastSquareMeasSubs, x1); - if (chiQCPass == false) - { -// return 1; //todo aaron - } + chiQC(trace, leastSquareMeasSubs, x1); if (dx) { @@ -1702,6 +1785,7 @@ void KFState::leastSquareInitStates( { x(stateRowIndex) += newStateVal; P(stateRowIndex,stateRowIndex) = newStateCov; + kfMeas.VV = kfMeas.Y - H * *dx; } else { @@ -1709,7 +1793,6 @@ void KFState::leastSquareInitStates( P(stateRowIndex,stateRowIndex) = newStateCov; } - if (initCovars) { for (int j = 0; j < i; j++) @@ -1783,9 +1866,9 @@ void KFState::leastSquareInitStatesA( leastSquareMeas.H = kfMeas.H(leastSquareMeasIndicies, all); //invert measurement noise matrix to get a weight matrix - leastSquareMeas.W = (1 / leastSquareMeas.R.diagonal().array()).matrix(); //todo aaron straight inversion? + leastSquareMeas.W = (1 / leastSquareMeas.R.diagonal().array()).matrix(); - VectorXd w = (1 / leastSquareMeas.R.diagonal().array()).matrix().col(0); //todo aaron straight inversion? + VectorXd w = (1 / leastSquareMeas.R.diagonal().array()).matrix().col(0); for (int i = 0; i < w.rows(); i++) { @@ -1835,11 +1918,7 @@ void KFState::leastSquareInitStatesA( } // std::cout << std::endl << "postLSQ" << std::endl; - chiQCPass = chiQC(trace, leastSquareMeas, x1); - if (chiQCPass == false) - { -// return 1; //todo aaron - } + chiQC(trace, leastSquareMeas, x1); if (dx) { @@ -1890,6 +1969,7 @@ VectorXd KFState::getSubState( map& kfKeyMap, ///< List of keys to return within substate MatrixXd* covarMat_ptr, ///< Optional pointer to a matrix for output of covariance submatrix VectorXd* adjustVec_ptr) ///< Optional pointer to a vector for output of last adjustments +const { vector indices; indices.resize(kfKeyMap.size()); @@ -1910,6 +1990,79 @@ VectorXd KFState::getSubState( return subState; } +/** Get a portion of a state by passing in a list of keys. + * Only gets some aspects, as most aren't required + */ +void KFState::getSubState( + map& kfKeyMap, ///< List of keys to return within substate + KFState& subState) ///< Output state +const +{ + vector indices; + indices.resize(kfKeyMap.size()); + + subState.kfIndexMap.clear(); + for (auto& [kfKey, mapIndex] : kfKeyMap) + { + int stateIndex = getKFIndex(kfKey); + if (stateIndex >= 0) + { + indices[mapIndex] = stateIndex; + } + + subState.kfIndexMap[kfKey] = mapIndex; + } + + subState.time = time; + subState.x = x (indices); + subState.dx = dx(indices); +// subState.Z = Z (indices, indices); + subState.P = P (indices, indices); + + subState.stateTransitionMap .clear(); +// subState.ZTransitionMap .clear(); + + for (auto& [keyA, stmMap] : stateTransitionMap) + { + auto itA = kfKeyMap.find(keyA); + if (itA == kfKeyMap.end()) + { + continue; + } + + for (auto& [keyB, st] : stmMap) + { + auto itB = kfKeyMap.find(keyB); + if (itB == kfKeyMap.end()) + { + continue; + } + + subState.stateTransitionMap[keyA][keyB] = st; + } + } + +// for (auto& [keyA, stmMap] : ZTransitionMap) +// { +// auto itA = kfKeyMap.find(keyA); +// if (itA == kfKeyMap.end()) +// { +// continue; +// } +// +// for (auto& [keyB, st] : stmMap) +// { +// auto itB = kfKeyMap.find(keyB); +// if (itB == kfKeyMap.end()) +// { +// continue; +// } +// +// subState.ZTransitionMap[keyA][keyB] = st; //todo aaron, fix this +// } +// } +} + /** Output keys and states in human readable format */ void KFState::outputStates( @@ -1918,16 +2071,22 @@ void KFState::outputStates( int begX, ///< Index of first state element to process int numX) ///< Number of state elements to process { + Instrument instrument(__FUNCTION__); + tracepdeex(2, trace, "\n\n"); - trace << std::endl << "+STATES" << suffix << std::endl; + string name = "STATES"; + name += suffix; + Block block(trace, name); - tracepdeex(2, trace, "#\t%19s\t%20s\t%5s\t%3s\t%3s\t%13s\t%16s\t%10s\t%s\n", "Time", "Type", "Str", "Sat", "Num", "State", "Variance", "Adjust", "Comments"); + tracepdeex(2, trace, "#\t%22s\t%20s\t%5s\t%3s\t%3s\t%17s\t%17s\t%15s\t%s\n", "Time", "Type", "Str", "Sat", "Num", "State", "Variance", "Adjust", "Comments"); int endX; if (numX < 0) endX = x.rows(); else endX = begX + numX; + bool noAdjust = dx.isZero(); + for (auto& [key, index] : kfIndexMap) { if (index >= x.rows()) @@ -1947,19 +2106,31 @@ void KFState::outputStates( double _p = P(index, index); string type = KF::_from_integral(key.type)._to_string(); - tracepdeex(2, trace, "*\t%19s\t%20s\t%5s\t%3s\t%3d\t%13.4f\t%16.9f\t%10.3e\t%s\n", + char dStr[20]; + char xStr[20]; + char pStr[20]; + if (noAdjust) snprintf(dStr, sizeof(dStr), "%15.0s", ""); + else if (_dx == 0 || (fabs(_dx) > 0.0001 && fabs(_dx) < 1e8)) snprintf(dStr, sizeof(dStr), "%15.8f", _dx); + else snprintf(dStr, sizeof(dStr), "%15.4e", _dx); + + if (_x == 0 || (fabs(_x) > 0.0001 && fabs(_x) < 1e8)) snprintf(xStr, sizeof(xStr), "%17.7f", _x); + else snprintf(xStr, sizeof(xStr), "%17.3e", _x); + + if (_p == 0 || (fabs(_p) > 0.0001 && fabs(_p) < 1e8)) snprintf(pStr, sizeof(pStr), "%17.8f", _p); + else snprintf(pStr, sizeof(pStr), "%17.4e", _p); + + + tracepdeex(2, trace, "*\t%20s\t%20s\t%5s\t%3s\t%3d\t%s\t%s\t%s\t%s\n", time.to_string(0).c_str(), type.c_str(), key.str.c_str(), key.Sat.id().c_str(), key.num, - _x, - _p, - _dx, + xStr, + pStr, + dStr, key.comment.c_str()); } - - trace << "-STATES" << suffix << std::endl; } MatrixXi correlationMatrix( @@ -1982,14 +2153,24 @@ MatrixXi correlationMatrix( return correlations; } +void KFState::outputConditionNumber( + Trace& trace) +{ + Eigen::JacobiSVD svd(P.bottomRightCorner(P.rows()-1, P.cols()-1)); + double conditionNumber = svd.singularValues()(0) / svd.singularValues()(svd.singularValues().size()-1); + + tracepdeex(0, trace, "\n\n Condition number: %f", conditionNumber); +} + void KFState::outputCorrelations( Trace& trace) { tracepdeex(2, trace, "\n\n"); - trace << std::endl << "+CORRELATIONS" << std::endl; + Block block(trace, "CORRELATIONS"); - int skip = 0; + int skip = 0; + int total = kfIndexMap.size(); for (auto& [key, index] : kfIndexMap) { if (key.type == KF::ONE) @@ -1997,13 +2178,20 @@ void KFState::outputCorrelations( continue; } - tracepdeex(2, trace, "\n%28s", ""); + tracepdeex(2, trace, "%s ", KFKey::emptyString().c_str()); for (int i = 0; i < skip; i++) { tracepdeex(2, trace, "| "); } - trace << "> " << key; + trace << "> "; + + for (int i = 0; i < total - skip; i++) + { + tracepdeex(2, trace, "-----"); + } + + trace << key << std::endl; skip++; } @@ -2017,7 +2205,7 @@ void KFState::outputCorrelations( continue; } - trace << std::endl << key << " "; + trace << key << " : "; for (auto& [key2, index2] : kfIndexMap) { @@ -2028,14 +2216,14 @@ void KFState::outputCorrelations( int correlation = correlations(index, index2); - if (index == index2) tracepdeex(2, trace, "%4.0s ", ""); + if (index == index2) tracepdeex(2, trace, "%4.0s ", "100"); else if (fabs(correlation) > 100) tracepdeex(2, trace, "%4.0s ", "----"); else if (fabs(correlation) < 1) tracepdeex(2, trace, "%4.0s ", ""); else tracepdeex(2, trace, "%4.0f ", correlation); - } + + trace << std::endl; } - trace << std::endl << "-CORRELATIONS" << std::endl; } void KFState::outputMeasurements( @@ -2043,8 +2231,10 @@ void KFState::outputMeasurements( KFMeas& meas) { tracepdeex(2, trace, "\n\n"); - trace << std::endl << "+MEASUREMENTS" << std::endl; + Block block(trace, "MEASUREMENTS"); + + int total = kfIndexMap.size(); int skip = 0; for (auto& [key, index] : kfIndexMap) { @@ -2053,14 +2243,21 @@ void KFState::outputMeasurements( continue; } - tracepdeex(0, trace, "\n%4s\t%4s\t%6s\t%3s ", "", "", "", ""); + tracepdeex(0, trace, "%s ", KFKey::emptyString().c_str()); for (int i = 0; i < skip; i++) { tracepdeex(2, trace, "| "); } - trace << "> " << key; + trace << "> "; + + for (int i = 0; i < total - skip; i++) + { + tracepdeex(2, trace, "-------"); + } + + trace << key << std::endl; skip++; } @@ -2069,7 +2266,7 @@ void KFState::outputMeasurements( { auto& key = meas.obsKeys[i]; - trace << std::endl << key << " "; + trace << key << " : "; for (int j = 1; j < meas.H.cols(); j++) { @@ -2078,9 +2275,8 @@ void KFState::outputMeasurements( if (fabs(a) > 0.001) tracepdeex(2, trace, "%6.2f ", a); else tracepdeex(2, trace, "%6.2s ", ""); } + tracepdeex(2, trace, "\t : %16.4f\n", meas.V(i)); } - - trace << std::endl << "-MEASUREMENTS" << std::endl; } InitialState initialStateFromConfig( @@ -2093,21 +2289,23 @@ InitialState initialStateFromConfig( else init.estimate = kalmanModel.estimate .back(); if (index < kalmanModel.apriori_val .size()) init.x = kalmanModel.apriori_val [index]; else init.x = kalmanModel.apriori_val .back(); - if (index < kalmanModel.sigma .size()) init.P = SQR( kalmanModel.sigma [index]); - else init.P = SQR( kalmanModel.sigma .back()); - if (index < kalmanModel.proc_noise .size()) init.Q = SQR( kalmanModel.proc_noise [index]); - else init.Q = SQR( kalmanModel.proc_noise .back()); + if (index < kalmanModel.sigma .size()) init.P = SQR( kalmanModel.sigma [index]) * SGN(kalmanModel.sigma [index]); + else init.P = SQR( kalmanModel.sigma .back()) * SGN(kalmanModel.sigma .back()); if (index < kalmanModel.tau .size()) init.tau = kalmanModel.tau [index]; else init.tau = kalmanModel.tau .back(); if (index < kalmanModel.mu .size()) init.mu = kalmanModel.mu [index]; else init.mu = kalmanModel.mu .back(); - + if (index < kalmanModel.proc_noise .size()) init.Q = SQR( kalmanModel.proc_noise [index]) * SGN(kalmanModel.proc_noise[index]); + else init.Q = SQR( kalmanModel.proc_noise .back()) * SGN(kalmanModel.proc_noise.back()); + if (index < kalmanModel.comment .size()) init.comment = kalmanModel.comment [index]; + else init.comment = kalmanModel.comment .back(); + return init; } KFState mergeFilters( - list& kfStatePointerList, - bool includeTrop) + vector& kfStatePointerList, + bool includeTrop) { map stateValueMap; map> stateCovarMap; @@ -2119,15 +2317,17 @@ KFState mergeFilters( for (auto& [key1, index1] : kfState.kfIndexMap) { if ( key1.type != KF::REC_POS + &&key1.type != KF::REC_POS_RATE &&key1.type != KF::ONE &&key1.type != KF::TROP - &&key1.type != KF::TROP_GM) + &&key1.type != KF::TROP_GRAD) { continue; } + if ( includeTrop == false &&(key1.type == KF::TROP - || key1.type == KF::TROP_GM)) + || key1.type == KF::TROP_GRAD)) { continue; } @@ -2137,14 +2337,15 @@ KFState mergeFilters( for (auto& [key2, index2] : kfState.kfIndexMap) { if ( key2.type != KF::REC_POS + &&key2.type != KF::REC_POS_RATE &&key2.type != KF::TROP - &&key2.type != KF::TROP_GM) + &&key2.type != KF::TROP_GRAD) { continue; } if ( includeTrop == false &&(key2.type == KF::TROP - || key2.type == KF::TROP_GM)) + || key2.type == KF::TROP_GRAD)) { continue; } diff --git a/src/cpp/common/algebra.hpp b/src/cpp/common/algebra.hpp index 69406fe61..b661395b5 100644 --- a/src/cpp/common/algebra.hpp +++ b/src/cpp/common/algebra.hpp @@ -1,29 +1,31 @@ -#ifndef _KALMAN_HPP_ -#define _KALMAN_HPP_ +#pragma once #include "eigenIncluder.hpp" - +#include #include #include #include #include -#include +#include +#include #include -#include #include +using boost::algorithm::to_lower; +using std::lock_guard; using std::string; using std::vector; +using std::mutex; using std::tuple; -using std::list; using std::hash; +using std::pair; using std::map; -#include "streamTrace.hpp" #include "satSys.hpp" #include "gTime.hpp" +#include "trace.hpp" //forward declaration @@ -45,44 +47,46 @@ struct KFKey bool operator == (const KFKey& b) const; bool operator < (const KFKey& b) const; - - friend ostream& operator<<(ostream& os, const KFKey& kfKey) - { - tracepdeex(0, os, "%10s %4s %4s %3d", KF::_from_integral(kfKey.type)._to_string(), kfKey.Sat.id().c_str(), kfKey.str.c_str(), kfKey.num); -// os << KF::_from_integral(kfKey.type)._to_string() << ' ' << kfKey.Sat.id() << ' ' << kfKey.str << ' ' << kfKey.num; - return os; - } -}; - -struct ObsKey -{ - SatSys Sat = {}; ///< Satellite - string str = ""; ///< String (receiver ID) - string type = ""; ///< Substring (eg LC12-P) - int num = 0; - - friend ostream& operator<<(ostream& os, const ObsKey& obsKey) + + static string emptyString() { - tracepdeex(0, os, "%4s\t%4s\t%6s\t%3d", - obsKey.Sat.id() .c_str(), - obsKey.str .c_str(), - obsKey.type .c_str(), - obsKey.num); + KFKey key; + string str = key; + for (auto& c : str) + { + if (c != '\t') + c = ' '; + } - return os; + return str; } + + operator string() const + { + char buff[100]; + snprintf(buff, sizeof(buff), "%10s\t%4s\t%4s\t%5d", KF::_from_integral(type)._to_string(), Sat.id().c_str(), str.c_str(), num); + string str = buff; - bool operator == (const ObsKey& b) const; - bool operator < (const ObsKey& b) const; - - operator string() + return str; + } + + string commaString() const { char buff[100]; - snprintf(buff, sizeof(buff), "%5s\t%3s\t%5s", str.c_str(), Sat.id().c_str(), (type + std::to_string(num) ).c_str() ); + snprintf(buff, sizeof(buff), "%s,%s,%s,%d", KF::_from_integral(type)._to_string(), Sat.id().c_str(), str.c_str(), num); string str = buff; + to_lower(str); return str; } + + friend ostream& operator<<(ostream& os, const KFKey& kfKey) + { + string str = kfKey; + os << str; + + return os; + } template void serialize(ARCHIVE& ar, const unsigned int& version) @@ -91,28 +95,10 @@ struct ObsKey ar & str; ar & num; ar & type; - } -}; + ar & comment; + } -namespace std -{ - template<> struct hash - { - size_t operator()(ObsKey const& key) const - { - //create hashes of all parts and XOR them to get a complete hash -// string str; -// if (key.station_ptr == nullptr) str = "NO STREAM"; -// else str = key.station_ptr->id; - - size_t hashval = hash {}(key.str) << 0 - ^ hash {}(key.Sat) << 1 - ^ hash {}(key.type) << 2 - ^ hash {}(key.num) << 3; - return hashval; - } - }; -} +}; namespace std { @@ -160,10 +146,11 @@ struct KFMeas MatrixXd R; ///< Measurement noise for these observations VectorXd W; ///< Weight (inverse of noise) used in least squares MatrixXd H; ///< Design matrix between measurements and state + MatrixXd H_star; ///< Design matrix between measurements and noise states - vector obsKeys; ///< Optional labels for reporting when measurements are removed etc. - vector> metaDataMaps; - vector>> componentLists; + vector obsKeys; ///< Optional labels for reporting when measurements are removed etc. + vector> metaDataMaps; + vector>> componentLists; void removeMeas(int index) { @@ -179,11 +166,62 @@ struct KFMeas obsKeys.erase(obsKeys.begin() + index); - Y = ( Y (keepIndices) ).eval(); - V = ( V (keepIndices) ).eval(); - VV = ( VV (keepIndices) ).eval(); - R = ( R (keepIndices, keepIndices) ).eval(); - H = ( H (keepIndices, all) ).eval(); + Y = ( Y (keepIndices) ).eval(); + V = ( V (keepIndices) ).eval(); + VV = ( VV (keepIndices) ).eval(); + R = ( R (keepIndices, keepIndices) ).eval(); + H = ( H (keepIndices, all) ).eval(); + H_star = ( H_star (keepIndices, all) ).eval(); + } + + template + void serialize(ARCHIVE& ar, const unsigned int& version) + { + int rows = H.rows(); + int cols = H.cols(); + ar & rows; + ar & cols; + + if (ARCHIVE::is_saving::value) + { + //just wrote this, we are writing + map, double> H2; + + ar & obsKeys; + ar & time; + ar & VV; + + for (int i = 0; i < rows; i++) + for (int j = 0; j < cols; j++) + { + double value = H(i,j); + if (value) + { + H2[{i,j}] = value; + } + } + + ar & H2; + } + else + { + //we're reading + map, double> H2; + + ar & obsKeys; + ar & time; + ar & VV; + ar & H2; + + H = MatrixXd::Zero(rows,cols); + R = MatrixXd::Zero(rows,rows); + V = VectorXd::Zero(rows); + + for (auto & [index, value] : H2) + { + H(index.first, index.second) = value; + } + } } }; @@ -194,31 +232,29 @@ struct InitialState double estimate = false; double x = 0; ///< State value double P = 0; ///< State Covariance - double Q = 0; ///< Process Noise + double Q = 0; ///< Process Noise, -ve indicates infinite (throw away state) double tau = -1; ///< Correlation Time, default to -1 (inf) (Random Walk) double mu = 0; ///< Desired Mean Value + string comment; }; +struct KFState; struct KalmanModel; +struct KFMeasEntry; +struct KFStatistics; InitialState initialStateFromConfig( KalmanModel& kalmanModel, - int index); - -typedef list KFMeasList; + int index = 0); typedef std::ostream Trace; - -struct KFMeasEntry; -typedef list KFMeasEntryList; - -struct KFState; +typedef vector KFMeasList; +typedef vector KFMeasEntryList; typedef bool (*StateRejectCallback) (Trace& trace, KFState& kfState, KFMeas& meas, KFKey& key); typedef bool (*MeasRejectCallback) (Trace& trace, KFState& kfState, KFMeas& meas, int index); -struct KFStatistics; /** Kalman filter object. * @@ -226,33 +262,33 @@ struct KFStatistics; * * This object performs all operations on the kalman filter to ensure that edge cases are included and state kept in a valid configuration. */ -struct KFState +struct KFState_ { bool lsqRequired = false; ///< Uninitialised parameters require least squares calculation GTime time = {}; VectorXd x; ///< State - MatrixXd Z; ///< Permutation Matrix MatrixXd P; ///< State Covariance VectorXd dx; ///< Last filter update - map kfIndexMap; ///< Map from key to indexes of parameters in the state vector + map kfIndexMap; ///< Map from key to indexes of parameters in the state vector + map noiseIndexMap; ///< Map from key to indexes of parameters in the noise vector - map> ZTransitionMap; - map ZAdditionMap; - map>> stateTransitionMap; - map gaussMarkovTauMap; - map gaussMarkovMuMap; - map procNoiseMap; - map initNoiseMap; - map noiseElementMap; + map>> stateTransitionMap; + map gaussMarkovTauMap; + map gaussMarkovMuMap; + map procNoiseMap; + map initNoiseMap; + map noiseElementMap; - list stateRejectCallbacks; - list measRejectCallbacks; - - map metaDataMap; + vector stateRejectCallbacks; + vector measRejectCallbacks; + + map metaDataMap; bool chiQCPass = false; + double chi = 0; + int dof = 0; bool sigma_check = true; bool w_test = false; @@ -262,88 +298,151 @@ struct KFState string id = "KFState"; -// string rts_filename = ""; + string suffix = ""; + string rts_basename = ""; -// string rts_forward_filename = ""; int rts_lag = 0; int max_filter_iter = 1; int max_prefit_remv = 0; bool output_residuals = false; + bool outputMongoMeasurements = false; + bool simulate_filter_only = false; - int inverter = E_Inverter::INV; + E_Inverter inverter = E_Inverter::LDLT; + map statisticsMap; + map statisticsMapSum; + +// MatrixXd Z; ///< Permutation Matrix +// map> ZTransitionMap; +// map ZAdditionMap; +}; + + +struct KFState : KFState_ +{ + mutex kfStateMutex; + + static const KFKey oneKey; + + KFState( + const KFState &kfState) + : KFState_ (kfState), + kfStateMutex () + { + + } + KFState() { //initialise all filter state objects with a ONE element for later use. x = VectorXd ::Ones(1); - Z = MatrixXd ::Ones(1,1); +// Z = MatrixXd ::Ones(1,1); P = MatrixXd ::Zero(1,1); dx = VectorXd ::Zero(1); - KFKey oneKey = {KF::ONE}; kfIndexMap[oneKey] = 0; initFilterEpoch(); } + + KFState& operator=( + const KFState& kfState) + { + KFState_* thisKfState_ = (KFState_*)this; + KFState_* thatKfState_ = (KFState_*)&kfState; + + *thisKfState_ = *thatKfState_; + + return *this; + } - + template + void serialize(ARCHIVE& ar, const unsigned int& version) + { + ar & kfIndexMap; + ar & time; + ar & x; + ar & dx; + ar & P; + } + void initFilterEpoch(); int getKFIndex( - KFKey key); + const KFKey key) + const; + + int getNoiseIndex( + const KFKey key) + const; bool getKFValue( - KFKey key, - double& value, - double* variance = nullptr, - double* adjustment_ptr = nullptr); + const KFKey key, + double& value, + double* variance = nullptr, + double* adjustment_ptr = nullptr) + const; bool getKFSigma( - KFKey key, - double& sigma); - - bool setKFValue( - KFKey key, - double value); + const KFKey key, + double& sigma); bool setKFNoise( - KFKey key, - double value); - - void setKFTransRate( - KFKey dest, - KFKey source, - double value, - InitialState initialState = {}); - + const KFKey key, + double value); + + bool addKFState( + const KFKey kfKey, + const InitialState initialState = {}); + + void setAccelerator( + const KFKey element, + const KFKey dotElement, + const KFKey dotDotElement, + const double value, + const InitialState initialState = {}); + void setKFTrans( - KFKey dest, - KFKey source, - double value, - InitialState initialState = {}); + const KFKey dest, + const KFKey source, + const double value, + const InitialState initialState = {}); - bool addKFState( - KFKey kfKey, - InitialState initialState = {}); + void setKFTransRate( + const KFKey integral, + const KFKey rate, + const double value, + const InitialState initialRateState = {}, + const InitialState initialIntegralState = {}); void addNoiseElement( - ObsKey obsKey, - double variance); + const KFKey obsKey, + const double variance); void removeState( - KFKey kfKey); + const KFKey kfKey); + + void noiseElementStateTransition(); void stateTransition( Trace& trace, - GTime newTime); + GTime newTime, + MatrixXd* stm_ptr = nullptr); + + void manualStateTransition( + Trace& trace, + GTime newTime, + MatrixXd& stm, + MatrixXd& procNoise); void preFitSigmaCheck( Trace& trace, KFMeas& kfMeas, KFKey& badStateKey, - int& badMeasIndex, + int& badMeasIndex, KFStatistics& statistics, int begX, int numX, @@ -353,11 +452,10 @@ struct KFState void postFitSigmaChecks( Trace& trace, KFMeas& kfMeas, - VectorXd& xp, VectorXd& dx, int iteration, - KFKey& badStateKey, - int& badMeasIndex, + KFKey& badStateKey, + int& badMeasIndex, KFStatistics& statistics, int begX, int numX, @@ -412,6 +510,9 @@ struct KFState int begX = 0, int numX = -1); + void outputConditionNumber( + Trace& trace); + void outputCorrelations( Trace& trace); @@ -429,11 +530,11 @@ struct KFState KFMeas& kfMeas, int badIndex); - int filterKalman( - Trace& trace, - KFMeas& kfMeas, - bool innovReady = false, - list* filterChunkList_ptr = nullptr); + void filterKalman( + Trace& trace, + KFMeas& kfMeas, + bool innovReady = false, + vector* filterChunkList_ptr = nullptr); int filterLeastSquares( Trace& trace, @@ -461,7 +562,59 @@ struct KFState VectorXd getSubState( map& kfKeyMap, MatrixXd* covarMat_ptr = nullptr, - VectorXd* adjustVec_ptr = nullptr); + VectorXd* adjustVec_ptr = nullptr) + const; + + void getSubState( + map& kfKeyMap, + KFState& kfState) + const; + + void addNoiseElement( + const KFKey kfKey, + const double variance) + const + { + auto& kfState = *const_cast(this); lock_guard guard(kfState.kfStateMutex); kfState.addNoiseElement (kfKey, variance); + } + + void addNoiseEntry( + const KFKey kfKey, + const double value, + const double variance) + const + { + auto& kfState = *const_cast(this); lock_guard guard(kfState.kfStateMutex); kfState.addNoiseEntry (kfKey, value, variance); + } + + bool addKFState( + const KFKey kfKey, + const InitialState initialState = {}) + const + { + auto& kfState = *const_cast(this); lock_guard guard(kfState.kfStateMutex); return kfState.addKFState (kfKey, initialState); + } + + void setKFTrans( + const KFKey dest, + const KFKey source, + const double value, + const InitialState initialState = {}) + const + { + auto& kfState = *const_cast(this); lock_guard guard(kfState.kfStateMutex); kfState.setKFTrans (dest, source, value, initialState); + } + + void setKFTransRate( + const KFKey integral, + const KFKey rate, + const double value, + const InitialState initialRateState = {}, + const InitialState initialIntegralState = {}) + const + { + auto& kfState = *const_cast(this); lock_guard guard(kfState.kfStateMutex); kfState.setKFTransRate (integral, rate, value, initialRateState, initialIntegralState); + } }; /** Object to hold an individual measurement. @@ -470,76 +623,90 @@ struct KFState */ struct KFMeasEntry { - KFState* kfState_ptr; ///< Pointer to filter object that measurements are referencing - + KFState* kfState_ptr = nullptr; ///< Pointer to filter object that measurements are referencing + const KFState* constKfState_ptr = nullptr; ///< Pointer to filter object that measurements are referencing + double value = 0; ///< Value of measurement (for linear systems) double noise = 0; ///< Noise of measurement double innov = 0; ///< Innovation of measurement (for non-linear systems) - ObsKey obsKey = {}; ///< Optional labels to be used in output traces + KFKey obsKey = {}; ///< Optional labels to be used in output traces - list> componentList; + vector> componentList; map designEntryMap; - map noiseEntryMap; + map noiseEntryMap; map metaDataMap; KFMeasEntry( - KFState* kfState_ptr = nullptr, - ObsKey obsKey = {}) - : kfState_ptr (kfState_ptr), - obsKey (obsKey) + KFState* kfState_ptr, + KFKey obsKey = {}) + : kfState_ptr (kfState_ptr), + obsKey (obsKey) + { + + } + + KFMeasEntry( + const KFState* constKfState_ptr, + KFKey obsKey = {}) + : constKfState_ptr (constKfState_ptr), + obsKey (obsKey) { } + KFMeasEntry() + { + + } + /** Adds a noise element for this measurement */ void addNoiseEntry( - ObsKey obsKey, ///< Key to determine the origin of the noise - double value, ///< Noise entry matrix entry value - double variance) ///< Variance of noise element + const KFKey kfKey, ///< Key to determine the origin of the noise + const double value, ///< Noise entry matrix entry value + const double variance) ///< Variance of noise element { if ( value == 0 ||variance == 0) { return; } + if (kfState_ptr) { kfState_ptr ->addNoiseElement(kfKey, variance); } + if (constKfState_ptr) { constKfState_ptr->addNoiseElement(kfKey, variance); } - if (kfState_ptr) - { - kfState_ptr->addNoiseElement(obsKey, variance); - } - - noiseEntryMap[obsKey] += value; + noiseEntryMap[kfKey] += value; } /** Adds a design matrix entry for this measurement */ - bool addDsgnEntry( - KFKey kfKey, ///< Key to determine which state parameter is affected - double value, ///< Design matrix entry value - InitialState initialState = {}) ///< Initial conditions for new states + void addDsgnEntry( + const KFKey kfKey, ///< Key to determine which state parameter is affected + const double value, ///< Design matrix entry value + const InitialState initialState = {}) ///< Initial conditions for new states { if (value == 0) { - return false; + return; } - - bool retval = false; - if (kfState_ptr) + + if (initialState.Q < 0) { - retval = kfState_ptr->addKFState(kfKey, initialState); + addNoiseEntry(kfKey, value, initialState.P); + return; } + bool retval = false; + if (kfState_ptr) { kfState_ptr ->addKFState(kfKey, initialState); } + if (constKfState_ptr) { constKfState_ptr->addKFState(kfKey, initialState); } + designEntryMap[kfKey] += value; - - return retval; } /** Adds the measurement noise entry for this measurement */ void setNoise( - double value) ///< Measurement noise matrix entry value + const double value) ///< Measurement noise matrix entry value { if (value == 0) { @@ -563,7 +730,7 @@ struct KFMeasEntry /** Adds the actual measurement value for this measurement */ void setValue( - double value) ///< Actual measurement entry value + const double value) ///< Actual measurement entry value { this->value = value; } @@ -571,15 +738,15 @@ struct KFMeasEntry /** Adds the innovation value for this measurement */ void setInnov( - double value) ///< Innovation entry value + const double value) ///< Innovation entry value { this->innov = value; } }; KFState mergeFilters( - list& kfStatePointerList, - bool includeTrop = false); + vector& kfStatePointerList, + bool includeTrop = false); MatrixXi correlationMatrix( MatrixXd& P); @@ -588,6 +755,7 @@ void outputResiduals( Trace& trace, KFMeas& kfMeas, int iteration, + string suffix, int begH, int numH); @@ -613,6 +781,3 @@ int solve (const char *tr, const double *A, const double *Y, int n, int m, double *X); -extern double chisqr_arr[]; - -#endif diff --git a/src/cpp/common/algebraTrace.cpp b/src/cpp/common/algebraTrace.cpp index f08e95e11..610f31e04 100644 --- a/src/cpp/common/algebraTrace.cpp +++ b/src/cpp/common/algebraTrace.cpp @@ -20,6 +20,9 @@ using std::map; #include #include +map idStringMap; +map stringIdMap; + /** Returns the type of object that is located at the specified position in a file */ E_SerialObject getFilterTypeFromFile( @@ -50,15 +53,15 @@ E_SerialObject getFilterTypeFromFile( return E_SerialObject::NONE; } - serialize(serial, itemDelta); + serial & itemDelta; long int itemPosition = currentPosition - itemDelta; fileStream.seekg(itemPosition, fileStream.beg); - int type_int; - serialize(serial, type_int); - E_SerialObject type = E_SerialObject::_from_integral(type_int); + int typeInt; + serial & typeInt; + E_SerialObject type = E_SerialObject::_from_integral(typeInt); return type; } @@ -113,16 +116,16 @@ void outputPersistanceStates( binary_oarchive serial(fileStream, 1); //no header - serialize(serial, netKFState); + serial & netKFState; int stationMapSize = stationMap.size(); - serialize(serial, stationMapSize); + serial & stationMapSize; for (auto& [id, rec] : stationMap) { string tempId = id; - serialize(serial, tempId); - serialize(serial, rec.pppState); + serial & tempId; + serial & rec.pppState; } } @@ -144,7 +147,7 @@ void inputPersistanceStates( { KFState kfState; - serialize(serial, kfState); + serial & kfState; KFState& destKFState = netKFState; @@ -174,15 +177,15 @@ void inputPersistanceStates( } int stationMapSize; - serialize(serial, stationMapSize); + serial & stationMapSize; for (int i = 0; i < stationMapSize; i++) { string tempId; - serialize(serial, tempId); + serial & tempId; KFState kfState; - serialize(serial, kfState); + serial & kfState; KFState& destKFState = stationMap[tempId].pppState; diff --git a/src/cpp/common/algebraTrace.hpp b/src/cpp/common/algebraTrace.hpp index c62d57dfd..b21e854a2 100644 --- a/src/cpp/common/algebraTrace.hpp +++ b/src/cpp/common/algebraTrace.hpp @@ -1,6 +1,5 @@ -#ifndef __ALGEBRA_TRACE_HPP__ -#define __ALGEBRA_TRACE_HPP__ +#pragma once #include #include @@ -21,6 +20,7 @@ using std::map; #include #include "navigation.hpp" +#include "station.hpp" #include "algebra.hpp" #include "enum.h" @@ -30,6 +30,7 @@ BETTER_ENUM(E_SerialObject, int, NONE, FILTER_MINUS, FILTER_PLUS, + FILTER_SMOOTHED, TRANSITION_MATRIX, NAVIGATION_DATA, STRING, @@ -42,247 +43,19 @@ struct TransitionMatrixObject map, double> forwardTransitionMap; int rows; int cols; -}; - -typedef map, double> CovarAdjustObject; -typedef map StateAdjustObject; - -namespace boost::serialization -{ - template void serialize(ARCHIVE& ar, int& integer) {ar & integer; } - template void serialize(ARCHIVE& ar, long int& integer) {ar & integer; } - template void serialize(ARCHIVE& ar, short int& integer) {ar & integer; } - template void serialize(ARCHIVE& ar, size_t& size_type) {ar & size_type; } - template void serialize(ARCHIVE& ar, map& Map) {ar & Map; } - - template - void serialize(ARCHIVE& ar, VectorXd& vec) - { - int rows = vec.rows(); - ar & rows; - - vec.resize(rows); - - for (int row = 0; row < vec.rows(); row++) - { - ar & vec(row); - } - } - + template - void serialize(ARCHIVE& ar, MatrixXd& mat) + void serialize(ARCHIVE& ar, const unsigned int& version) { - int rows = mat.rows(); - int cols = mat.cols(); - + ar & forwardTransitionMap; ar & rows; ar & cols; - - mat.resize(rows, cols); - - for (int row = 0; row < mat.rows(); row++) - for (int col = 0; col < mat.cols(); col++) - { - ar & mat(row, col); - } - } - - template - void serialize(ARCHIVE& ar, GTime& time) - { - long int time_int = time.time; - double time_sec = time.sec; - ar & time_int; - ar & time_sec; - time.time = time_int; - time.sec = time_sec; - } - - template - void serialize(ARCHIVE& ar, E_Sys& sys) - { - short int sys_int = sys; - ar & sys_int; - sys = E_Sys::_from_integral(sys_int); - } - - - template - void serialize(ARCHIVE& ar, SatSys& Sat) - { - serialize(ar, Sat.sys); - ar & Sat.prn; - } - - template - void serialize(ARCHIVE& ar, KFKey& kfKey) - { - ar & kfKey.type; - ar & kfKey.num; - ar & kfKey.str; - serialize(ar, kfKey.Sat); - } - -// template -// void serialize(ARCHIVE& ar, pair& pair_) -// { -// serialize(ar, pair_.first); -// serialize(ar, pair_.second); -// } - - template - void serialize(ARCHIVE& ar, map& mapItem) - { - int num = mapItem.size(); - ar & num; - - if (ARCHIVE::is_saving::value) - { - //writing - for (auto& [kfKey, val] : mapItem) - { - KFKey key = kfKey; - - serialize(ar, key); - - ar & val; - } - } - else - { - //reading - for (int i = 0; i < num; i++) - { - KFKey kfKey; - - serialize(ar, kfKey); - - ar & mapItem[kfKey]; - } - } - } - - template - void serialize(ARCHIVE& ar, pair& pair_) - { - serialize(ar, pair_.first); - serialize(ar, pair_.second); - } - - template - void serialize(ARCHIVE& ar, string& str) - { - ar & str; - } - - template - void serialize(ARCHIVE& ar, map& mapItem) - { - int num = mapItem.size(); - ar & num; - - if (ARCHIVE::is_saving::value) - { - //writing - for (auto& [kfKey, val] : mapItem) - { - KEY key = kfKey; - - serialize(ar, key); - - ar & val; - } - } - else - { - //reading - for (int i = 0; i < num; i++) - { - KEY kfKey; - - serialize(ar, kfKey); - - ar & mapItem[kfKey]; - } - } - } - - template - void serialize(ARCHIVE& ar, TransitionMatrixObject& object) - { - ar & object.forwardTransitionMap; - ar & object.rows; - ar & object.cols; - } - - template - void serialize(ARCHIVE& ar, ObsKey& obsKey) - { - ar & obsKey.Sat; - ar & obsKey.str; - ar & obsKey.type; - ar & obsKey.num; } +}; - template - void serialize(ARCHIVE& ar, KFState& kfState) - { - serialize(ar, kfState.kfIndexMap); - serialize(ar, kfState.time); - serialize(ar, kfState.x); - serialize(ar, kfState.P); - } +extern map idStringMap; +extern map stringIdMap; - template - void serialize(ARCHIVE& ar, KFMeas& kfMeas) - { - int rows = kfMeas.H.rows(); - int cols = kfMeas.H.cols(); - ar & rows; - ar & cols; - - if (ARCHIVE::is_saving::value) - { - //just wrote this, we are writing - map, double> H; - - ar & kfMeas.obsKeys; - serialize(ar, kfMeas.time); - serialize(ar, kfMeas.VV); - - for (int i = 0; i < rows; i++) - for (int j = 0; j < cols; j++) - { - double value = kfMeas.H(i,j); - if (value) - { - H[{i,j}] = value; - } - } - - serialize(ar, H); - } - else - { - //we're reading - map, double> H; - - ar & kfMeas.obsKeys; - serialize(ar, kfMeas.time); - serialize(ar, kfMeas.VV); - serialize(ar, H); - - kfMeas.H = MatrixXd::Zero(rows,cols); - kfMeas.R = MatrixXd::Zero(rows,rows); - kfMeas.V = VectorXd::Zero(rows); - - for (auto & [index, value] : H) - { - kfMeas.H(index.first, index.second) = value; - } - } - } -} using boost::serialization::serialize; using boost::archive::binary_oarchive; @@ -313,12 +86,12 @@ void spitFilterToFile( long int pos = fileStream.tellp(); int type_int = type; - serialize(serial, type_int); - serialize(serial, object); + serial & type_int; + serial & object; long int end = fileStream.tellp(); long int delta = end - pos; - serialize(serial, delta); + serial & delta; } /* Retrieve an object from an archive @@ -347,23 +120,23 @@ bool getFilterObjectFromFile( long int currentPosition = fileStream.tellg(); - serialize(serial, itemDelta); + serial & itemDelta; long int itemPosition = currentPosition - itemDelta; fileStream.seekg(itemPosition, fileStream.beg); - int type_int; - serialize(serial, type_int); + int typeInt; + serial & typeInt; - E_SerialObject type = E_SerialObject::_from_integral(type_int); + E_SerialObject type = E_SerialObject::_from_integral(typeInt); if (type != expectedType) { std::cout << std::endl << "Error: Unexpected algebra file object type"; return false; } - serialize(serial, object); + serial & object; startPos = itemPosition; @@ -374,7 +147,6 @@ E_SerialObject getFilterTypeFromFile( long int& startPos, string filename); -#include "station.hpp" void inputPersistanceNav(); @@ -391,5 +163,3 @@ void outputPersistanceStates( void tryPrepareFilterPointers( KFState& kfState, StationMap* stationMap_ptr); - -#endif diff --git a/src/cpp/common/algebra_old.cpp b/src/cpp/common/algebra_old.cpp index 9104c4044..582c81dce 100644 --- a/src/cpp/common/algebra_old.cpp +++ b/src/cpp/common/algebra_old.cpp @@ -2,19 +2,17 @@ #include #include -#include -using std::list; using std::pair; #include "eigenIncluder.hpp" #include "algebraTrace.hpp" -#include "streamTrace.hpp" #include "testUtils.hpp" #include "algebra.hpp" #include "common.hpp" #include "acsQC.hpp" +#include "trace.hpp" [[deprecated]] double *mat(int n, int m) @@ -23,7 +21,6 @@ double *mat(int n, int m) if (n<=0||m<=0) return NULL; if (!(p=(double *)malloc(sizeof(double)*n*m))) { - fatalerr("matrix memory allocation error: n=%d,m=%d\n",n,m); } return p; } @@ -34,7 +31,6 @@ int *imat(int n, int m) if (n<=0||m<=0) return NULL; if (!(p=(int *)malloc(sizeof(int)*n*m))) { - fatalerr("integer matrix memory allocation error: n=%d,m=%d\n",n,m); } return p; } @@ -43,14 +39,9 @@ double *zeros(int n, int m) { double *p; -#if NOCALLOC - if ((p=mat(n,m))) for (n=n*m-1;n>=0;n--) p[n]=0.0; -#else if (n<=0||m<=0) return NULL; if (!(p=(double *)calloc(sizeof(double),n*m))) { - fatalerr("matrix memory allocation error: n=%d,m=%d\n",n,m); } -#endif return p; } [[deprecated]] @@ -389,6 +380,21 @@ int chiqc( matmul("TN", 1, m, m, 1, v, P, 0, vtp); /* vtpv */ matmul("NN", 1, 1, m, 1, vtp, v, 0, &vtpv); + const double chisqr_arr[100] = + { + /* chi-sqr(n) (alpha=0.001) */ + 10.8,13.8,16.3,18.5,20.5,22.5,24.3,26.1,27.9,29.6, + 31.3,32.9,34.5,36.1,37.7,39.3,40.8,42.3,43.8,45.3, + 46.8,48.3,49.7,51.2,52.6,54.1,55.5,56.9,58.3,59.7, + 61.1,62.5,63.9,65.2,66.6,68.0,69.3,70.7,72.1,73.4, + 74.7,76.0,77.3,78.6,80.0,81.3,82.6,84.0,85.4,86.7, + 88.0,89.3,90.6,91.9,93.3,94.7,96.0,97.4,98.7,100 , + 101 ,102 ,103 ,104 ,105 ,107 ,108 ,109 ,110 ,112 , + 113 ,114 ,115 ,116 ,118 ,119 ,120 ,122 ,123 ,125 , + 126 ,127 ,128 ,129 ,131 ,132 ,133 ,134 ,135 ,137 , + 138 ,139 ,140 ,142 ,143 ,144 ,145 ,147 ,148 ,149 + }; + if (ind == 0) { val = vtpv / (m - n); diff --git a/src/cpp/common/antenna.cpp b/src/cpp/common/antenna.cpp index e0b074473..063ad6791 100644 --- a/src/cpp/common/antenna.cpp +++ b/src/cpp/common/antenna.cpp @@ -2,23 +2,35 @@ // #pragma GCC optimize ("O0") -#include -#include -#include -#include -#include - -#include #include +#include +#include "eigenIncluder.hpp" +#include "coordinates.hpp" #include "navigation.hpp" #include "constants.hpp" #include "antenna.hpp" #include "common.hpp" #include "enums.h" -#include "eigenIncluder.hpp" +map roughFrequency = +{ + {F1, FREQ1}, + {F2, FREQ1}, + {F5, FREQ5}, + {F6, FREQ6}, + {F7, FREQ7}, + {F8, FREQ8}, + {G1, FREQ1_GLO}, + {G2, FREQ2_GLO}, + {G3, FREQ3_GLO}, + {G4, FREQ4_GLO}, + {G6, FREQ6_GLO}, + {B1, FREQ1_CMP}, + {B3, FREQ3_CMP}, + {I9, FREQ9_IRN} +}; /* decode antenna field */ int decodef(char *p, int n, double *v) @@ -94,41 +106,76 @@ bool findAntenna( /** linearly interpolate */ -double interp(double x1, double x2, double y1, double y2, double x) +template +TYPE interp(double x1, double x2, TYPE y1, TYPE y2, double x) { return y2-(y2-y1)*(x2-x)/(x2-x1); } + Vector3d makeAntPco( string id, E_Sys sys, - E_FType ft, - GTime time) + E_FType ftx, + GTime time, + E_Radio radio) { - if (ft == F1) return Vector3d::Zero(); - if (ft == F2) return Vector3d::Zero(); + auto& pcoFreqMap = nav.pcoMap[id][sys]; - Vector3d pco1 = antPco(id, sys, F1, time); - Vector3d pco2 = antPco(id, sys, F2, time); + if (pcoFreqMap.empty()) + return Vector3d::Zero(); + + if (roughFrequency.find(ftx) == roughFrequency.end()) + return Vector3d::Zero(); - if (pco1.isZero()) return Vector3d::Zero(); - if (pco2.isZero()) return Vector3d::Zero(); + double lamX = CLIGHT / roughFrequency[ftx]; + + Vector3d pco1 = Vector3d::Zero(); + Vector3d pco2 = Vector3d::Zero(); + double lam1 = 0; + double lam2 = 0; - double lam1 = lam_carr[F1]; - double lam2 = lam_carr[F2]; - double lamX = lam_carr[ft]; + for (auto& [ft, pcoFreq] : pcoFreqMap) + { + if (roughFrequency.find(ft) == roughFrequency.end()) + continue; + + double lam = CLIGHT / roughFrequency[ft]; + + Vector3d pco = antPco(id, sys, ft, time, radio); + + if (pco.isZero()) + continue; + + if (lam1 == 0) { lam1 = lam; pco1 = pco; } + else if (lam2 == 0) { lam2 = lam; pco2 = pco; } + else + { + double close1 = fabs(lam1 - lamX) - fabs(lam - lamX); + double close2 = fabs(lam2 - lamX) - fabs(lam - lamX); + + if (close1 > close2 && close1 > 0) { lam1 = lam; pco1 = pco; } + if (close2 > close1 && close2 > 0) { lam2 = lam; pco2 = pco; } + } + } + + if (lam1 == 0) + return Vector3d::Zero(); - if (lamX == 0) return Vector3d::Zero(); + if ( lam2 == 0 + || lam1 == lam2) + { + return pco1; + } double k32 = (lamX-lam2)/(lam1-lam2); double k31 = (lamX-lam1)/(lam1-lam2); - - Vector3d pco = k32 * pco1 - - k31 * pco2; - - return pco; + + Vector3d pco3 = k32 * pco1 + - k31 * pco2; + return pco3; } - + /** fetch pco */ Vector3d antPco( @@ -136,6 +183,7 @@ Vector3d antPco( E_Sys sys, E_FType ft, GTime time, + E_Radio radio, bool interp) { auto it0 = nav.pcoMap.find(id); @@ -145,7 +193,7 @@ Vector3d antPco( } auto& [dummy0, pcoSysFreqMap] = *it0; - + auto it1 = pcoSysFreqMap.find(sys); if (it1 == pcoSysFreqMap.end()) { @@ -154,11 +202,12 @@ Vector3d antPco( auto& [dummy1, pcoFreqMap] = *it1; + auto it2 = pcoFreqMap.find(ft); if (it2 == pcoFreqMap.end()) { - if (interp) return makeAntPco(id, sys, ft, time); - else return Vector3d::Zero(); + if (interp) return makeAntPco(id, sys, ft, time, radio); + else return Vector3d::Zero(); } auto& [dummy2, pcoTimeMap] = *it2; @@ -171,18 +220,19 @@ Vector3d antPco( auto& [dummy3, pco] = *it3; - return pco; + if (radio == +E_Radio::TRANSMITTER) return pco.satPco; + else return pco.recPco; } /** find and interpolate antenna pcv */ double antPcv( string id, ///< antenna id - E_Sys sys, + E_Sys sys, ///< satellite system E_FType ft, ///< frequency GTime time, ///< time - double aCos, ///< angle between target and antenna axis (radians) - double azi) ///< azimuth angle (radians) + AttStatus& attStatus, + VectorEcef e) { auto it0 = nav.pcvMap.find(id); if (it0 == nav.pcvMap.end()) @@ -216,18 +266,26 @@ double antPcv( auto& [dummy3, pcd] = *it3; - auto& pcvMap1D = pcd.PCVMap1D; - auto& pcvMap2D = pcd.PCVMap2D; + auto& pcvMap1D = pcd.elMap; + auto& pcvMap2D = pcd.azElMap; int nz = pcd.nz; int naz = pcd.naz; double zen1 = pcd.zenStart; double dzen = pcd.zenDelta; double dazi = pcd.aziDelta; - double zen = aCos * R2D; - azi *= R2D; - double pcv; + // Rotate relative look vector into local frame + Matrix3d ant2Ecef = rotBasisMat(attStatus.eXAnt, attStatus.eYAnt, attStatus.eZAnt); + + Vector3d localLook = ant2Ecef.transpose() * e; + + double az = atan2(localLook(0), localLook(1)); + double zen = acos(localLook.z()) * R2D; + + wrap2Pi(az); + + az *= R2D; /* select zenith angle range */ int zen_n; @@ -242,11 +300,13 @@ double antPcv( double xz1 = zen1 + dzen * (zen_n - 1); double xz2 = zen1 + dzen * (zen_n); - if ( naz == 0 - ||azi == 0) + + double pcv; + + if ( naz == 0 + ||az == 0) { - /* linear interpolate receiver pcv - non azimuth-dependent */ - /* interpolate */ + // linear interpolate receiver pcv - non azimuth-dependent double yz1 = pcvMap1D[zen_n - 1]; // lower bound double yz2 = pcvMap1D[zen_n]; // upper bound @@ -254,12 +314,13 @@ double antPcv( } else { - /* bilinear interpolate receiver pcv - azimuth-dependent */ - /* select azimuth angle range */ + // bilinear interpolate receiver pcv - azimuth-dependent + + // select azimuth angle range */ int az_n; for (az_n = 1; az_n < naz; az_n++) { - if ((dazi * az_n) >= azi) + if ((dazi * az_n) >= az) { break; } @@ -269,32 +330,26 @@ double antPcv( double xa2 = dazi * (az_n); double yz3 = pcvMap2D[az_n-1] [zen_n-1]; double yz1 = pcvMap2D[az_n-1] [zen_n]; - double yz4 = pcvMap2D[az_n] [zen_n-1]; double yz2 = pcvMap2D[az_n] [zen_n]; + double yz4 = pcvMap2D[az_n] [zen_n-1]; double yz2 = pcvMap2D[az_n] [zen_n]; - /* linear interpolation along zenith angle */ + // linear interpolation along zenith angle double ya1 = interp(xz1, xz2, yz3, yz1, zen); double ya2 = interp(xz1, xz2, yz4, yz2, zen); - /* linear interpolation along azimuth angle */ - pcv = interp(xa1, xa2, ya1, ya2, azi); + // linear interpolation along azimuth angle + pcv = interp(xa1, xa2, ya1, ya2, az); } return pcv; } -//============================================================================= -// radomeNoneAntennaType = radome2none(antennaType) -// -// e,g, "AOAD/M_T JPLA" => "AOAD/M_T NONE" -// -// Change the last four characters of antenna type to NONE -// This function is useful for when searching for an antenna model in ANTEX -// -// The IGS convention is to default to NONE for the radome if the calibration -// value is not available -//============================================================================= -//void radome2none(char *restrict antenna_type) -void radome2none(string& antenna_type) +/**Change the last four characters of antenna type to NONE + * e,g, "AOAD/M_T JPLA" => "AOAD/M_T NONE" + * This function is useful for when searching for an antenna model in ANTEX + * The IGS convention is to default to NONE for the radome if the calibration value is not available + */ +void radome2none( + string& antenna_type) { size_t length = antenna_type.size(); if (length != 20) @@ -302,34 +357,42 @@ void radome2none(string& antenna_type) printf("\n*** ERROR radome2none(): string length is less then 20 characters received %ld characters\n",length); return; } + antenna_type.replace(length - 4, 4, "NONE"); } map antexCodes = { - {"G01", L1 }, - {"G02", L2 }, - {"G05", L5 }, - {"R01", G1 }, - {"R02", G2 }, - {"E01", E1 }, - {"E05", E5A }, - {"E07", E5B }, - {"E08", E5AB }, - {"E06", E6 }, - {"C01", E1 }, - {"C02", E2 }, - {"C07", E5B }, - {"C06", E6 }, - {"J01", L1 }, - {"J02", L2 }, - {"J05", L5 }, - {"J06", LEX }, - {"S01", L1 }, - {"S05", L5 } + {"G01", F1 }, + {"G02", F2 }, + {"G05", F5 }, + {"R01", G1 }, + {"R02", G2 }, + {"R04", G4 }, + {"R06", G6 }, + {"E01", F1 }, + {"E05", F5 }, + {"E06", F6 }, + {"E07", F7 }, + {"E08", F8 }, + {"C01", F1 }, + {"C02", B1 }, + {"C05", F5 }, + {"C06", B3 }, + {"C07", F7 }, + {"C08", F8 }, + {"J01", F1 }, + {"J02", F2 }, + {"J05", F5 }, + {"J06", F6 }, + {"S01", F1 }, + {"S05", F5 }, + {"I05", F5 }, + {"I09", I9 } }; -/** Read antex file */ +/** Read antex file + */ int readantexf( string file, Navigation& nav) @@ -355,7 +418,8 @@ int readantexf( const PhaseCenterData pcv0 = {}; PhaseCenterData recPcv; PhaseCenterData freqPcv; - Vector3d pco = Vector3d::Zero(); + VectorEnu recPco; + Vector3d satPco = Vector3d::Zero(); string id; GTime time; @@ -370,7 +434,7 @@ int readantexf( if (irms) continue; - /* Read in the ANTEX header information */ + // Read in the ANTEX header information if (strlen(buff) < 60 ) { continue; } if (strstr(comment, "ANTEX VERSION / SYST")) { continue; } @@ -378,14 +442,16 @@ int readantexf( if (strstr(comment, "COMMENT")) { continue; } if (strstr(comment, "END OF HEADER")) { continue; } - /* Read in specific Antenna information now */ + // Read in specific Antenna information now if (strstr(comment, "START OF ANTENNA")) { recPcv = pcv0; freqPcv = pcv0; - pco = Vector3d::Zero(); + recPco = Vector3d::Zero(); + satPco = Vector3d::Zero(); id = ""; + time = GTime::noTime(); continue; } @@ -434,17 +500,18 @@ int readantexf( if (strstr(comment, "TYPE / SERIAL NO")) { - recPcv.type .assign(buff, 20); - recPcv.code .assign(buff+20, 20); - recPcv.svn .assign(buff+40, 4); - recPcv.cospar .assign(buff+50, 10); + recPcv.type .assign(buff, 20); + recPcv.code .assign(buff+20, 20); + recPcv.svn .assign(buff+40, 4); + recPcv.cospar .assign(buff+50, 10); - /* stack antenna pco and pcv */ + // stack antenna pco and pcv string satId = recPcv.code; if (satId.find_first_not_of(' ') == satId.npos) { id = recPcv.type; } else { id = recPcv.code; } boost::trim_right(id); + boost::trim_right(recPcv.type); continue; } @@ -507,7 +574,7 @@ int readantexf( continue; } - if (strstr(comment, "NORTH / EAST / UP")) + if (strstr(comment, "NORTH / EAST / UP")) // "NORTH / EAST / UP" for receiver and "X / Y / Z" for satellite { double neu[3]; if (decodef(buff, 3, neu) < 3) @@ -515,13 +582,13 @@ int readantexf( continue; } - /* assign pco value in ENU */ - Vector3d enu; - enu[0] = neu[1]; - enu[1] = neu[0]; - enu[2] = neu[2]; + recPco.n() = neu[0]; + recPco.e() = neu[1]; + recPco.u() = neu[2]; - pco = enu; + satPco.x() = neu[0]; + satPco.y() = neu[1]; + satPco.z() = neu[2]; continue; } @@ -533,7 +600,7 @@ int readantexf( string antexFCode; antexFCode.assign(&buff[3], 3); - + sys = SatSys::sysFromChar(antexFCode[0]); ft = antexCodes[antexFCode]; @@ -546,14 +613,21 @@ int readantexf( { noazi_flag = 0; - nav.pcvMap[id][sys][ft][time] = freqPcv; - nav.pcoMap[id][sys][ft][time] = pco; + nav.pcvMap[id][sys][ft][time] = freqPcv; + nav.pcoMap[id][sys][ft][time].recPco = recPco; + nav.pcoMap[id][sys][ft][time].satPco = satPco; + + if (id.size() <= 3) // filters out non-PRNS e.g. "3S-02-TSADM NONE" + { + nav.svnMap[SatSys(id.c_str())][time] = recPcv.svn; + nav.blocktypeMap[recPcv.svn] = recPcv.type; + } continue; } - if (strstr(comment, "START OF FREQ RMS")) { irms = 1; continue; } - if (strstr(comment, "END OF FREQ RMS")) { irms = 0; continue; } + if (strstr(comment, "START OF FREQ RMS")) { irms = 1; continue; } + if (strstr(comment, "END OF FREQ RMS")) { irms = 0; continue; } if ( irms == 0 && strstr(buff, "NOAZI")) @@ -564,8 +638,9 @@ int readantexf( strncpy(tmp, buff + offset, 8); tmp[8]='\0'; double pcv_val = atof(tmp); - freqPcv.PCVMap1D .push_back(pcv_val * 1e-3); + freqPcv.elMap.push_back(pcv_val * 1e-3); } + noazi_flag = 1; continue; @@ -583,7 +658,7 @@ int readantexf( strncpy(tmp, buff + offset, 8); tmp[8]='\0'; double pcv_val = atof(tmp); - freqPcv.PCVMap2D[num_azi_rd].push_back(pcv_val * 1e-3); + freqPcv.azElMap[num_azi_rd].push_back(pcv_val * 1e-3); } num_azi_rd++; diff --git a/src/cpp/common/antenna.hpp b/src/cpp/common/antenna.hpp index 53ee1f2a3..2f4b76ffd 100644 --- a/src/cpp/common/antenna.hpp +++ b/src/cpp/common/antenna.hpp @@ -1,28 +1,23 @@ -#ifndef ANTENNA_H -#define ANTENNA_H +#pragma once #include #include -#include #include using std::string; using std::vector; -using std::list; using std::map; #include "eigenIncluder.hpp" - - -#include "streamTrace.hpp" +#include "azElMapData.hpp" #include "satStat.hpp" #include "gTime.hpp" +#include "trace.hpp" #include "enums.h" - -struct PhaseCenterData +struct PhaseCenterData : AzElMapData { /* antenna parameter type */ E_FType ft; @@ -31,46 +26,42 @@ struct PhaseCenterData string svn; ///< SVN in satellites string cospar; ///< Cospar code satellites string calibModel; ///< name of the antenna calibration model - double aziDelta; ///< azimuth increment (degree) - double zenStart; - double zenStop; - double zenDelta; - int nz; ///< number of zenith intervals - int naz; ///< number of non-azimuth dependent intervals double tf[6]; ///< valid from YMDHMS double tu[6]; ///< valid until YMDHMS - - vector PCVMap1D; - map> PCVMap2D; +}; + +struct PhaseCenterOffset +{ + Vector3d satPco = Vector3d::Zero(); + Vector3d recPco = Vector3d::Zero(); }; //forward declaration for pointer below struct SatSys; +struct AttStatus; struct Navigation; -void satAntOff( +VectorEcef satAntOff( Trace& trace, GTime time, - Vector3d& rSat, + AttStatus& attStatus, SatSys& Sat, - map& lamMap, - Vector3d& dAnt, - SatStat* satStat_ptr = nullptr); + map& lamMap); -Vector3d satAntOff( +VectorEcef satAntOff( Trace& trace, GTime time, - Vector3d& rSat, + AttStatus& attStatus, SatSys& Sat, - E_FType ft, - SatStat* satStat_ptr = nullptr); + E_FType ft); Vector3d antPco( string id, E_Sys sys, E_FType ft, GTime time, + E_Radio radio, bool interp = false); double antPcv( @@ -78,10 +69,8 @@ double antPcv( E_Sys sys, E_FType ft, GTime time, - double aCos, - double azi = 0); - - + AttStatus& attStatus, + VectorEcef e); bool findAntenna( string code, @@ -98,4 +87,3 @@ int readantexf( void radome2none( string& antenna_type); -#endif diff --git a/src/cpp/common/api.cpp b/src/cpp/common/api.cpp new file mode 100644 index 000000000..a06574e8a --- /dev/null +++ b/src/cpp/common/api.cpp @@ -0,0 +1,16 @@ + + +// #pragma GCC optimize ("O0") + +#include "api.hpp" + + +vector oncePerEpochCallbacks; + +void callbacksOncePerEpoch() +{ + for (auto& callback : oncePerEpochCallbacks) + { + callback(); + } +} diff --git a/src/cpp/common/api.hpp b/src/cpp/common/api.hpp new file mode 100644 index 000000000..ce3552e13 --- /dev/null +++ b/src/cpp/common/api.hpp @@ -0,0 +1,13 @@ + +#pragma once + +#include + +using std::vector; + +typedef void (*apiCallback) (); + +extern vector oncePerEpochCallbacks; + +void callbacksOncePerEpoch(); + diff --git a/src/cpp/common/attitude.cpp b/src/cpp/common/attitude.cpp new file mode 100644 index 000000000..f2cfdf53a --- /dev/null +++ b/src/cpp/common/attitude.cpp @@ -0,0 +1,845 @@ + +// #pragma GCC optimize ("O0") + +/** \file +* ###References: +* +* 1. D.D.McCarthy, IERS Technical Note 21, IERS Conventions 1996, July 1996 +* 2. D.D.McCarthy and G.Petit, IERS Technical Note 32, IERS Conventions 2003, November 2003 +* 3. D.A.Vallado, Fundamentals of Astrodynamics and Applications 2nd ed, Space Technology Library, 2004 +* 4. J.Kouba, A Guide to using International GNSS Service (IGS) products, May 2009 +* 5. RTCM Paper, April 12, 2010, Proposed SSR Messages for SV Orbit Clock, Code Biases, URA +* 6. MacMillan et al., Atmospheric gradients and the VLBI terrestrial and celestial reference frames, Geophys. Res. Let., 1997 +* 7. G.Petit and B.Luzum (eds), IERS Technical Note No. 36, IERS Conventions (2010), 2010 +* 8. J.Kouba, A simplified yaw-attitude model for eclipsing GPS satellites, GPS Solutions, 13:1-12, 2009 +* 9. F.Dilssner, GPS IIF-1 satellite antenna phase center and attitude modeling, InsideGNSS, September, 2010 +* 10. F.Dilssner, The GLONASS-M satellite yaw-attitude model, Advances in Space Research, 2010 +* 11. IGS MGEX (http://igs.org/mgex) +*/ + + +#include + +#include + +using std::vector; + + +#include "eigenIncluder.hpp" +#include "observations.hpp" +#include "corrections.hpp" +#include "coordinates.hpp" +#include "navigation.hpp" +#include "ephPrecise.hpp" +#include "ephemeris.hpp" +#include "acsConfig.hpp" +#include "constants.hpp" +#include "planets.hpp" +#include "satStat.hpp" +#include "antenna.hpp" +#include "common.hpp" +#include "sinex.hpp" +#include "trace.hpp" +#include "enums.h" +#include "ppp.hpp" + + +/** exclude meas of eclipsing satellite (block IIA) +*/ +void testEclipse( + ObsList& obsList) +{ + /* unit vector of sun direction (ecef) */ + VectorEcef rsun; + planetPosEcef(obsList.front()->time, E_ThirdBody::SUN, rsun); + + Vector3d esun = rsun.normalized(); + + for (auto& obs : only(obsList)) + { + if (acsConfig.reject_eclipse[obs.Sat.sys] == false) + continue; + + if (obs.exclude) + { + continue; + } + + double r = obs.rSat.norm(); + if (r <= 0) + continue; + + /* only block IIA */ +// if (obs.satNav_ptr->pcv.type == "BLOCK IIA") //todo take from the satSys object +// continue; + + /* sun-earth-satellite angle */ + double cosa = obs.rSat.dot(esun) / r; + + if (cosa < -1) cosa = -1; + if (cosa > +1) cosa = +1; + + double ang = acos(cosa); + + /* test eclipse */ + if ( ang < PI / 2 + || r * sin(ang) > RE_WGS84) + continue; + +// trace(3, "eclipsing sat excluded %s sat=%s\n", obs.time.to_string(0).c_str(), obs.Sat.id().c_str()); + + obs.excludeEclipse = true; + } +} + + +struct SatGeom +{ + VectorEcef rSat; ///< Satellite position (ECEF) + VectorEcef vSatPrime; ///< Satellite velocity (ECEF + Earth rotation component) + VectorEcef rSun; ///< Sun position (ECEF) + VectorEcef rMoon; ///< Moon position (ECEF) + VectorEcef eNorm; ///< Normalised orbit normal vector (ECEF) + double beta = 0; ///< Sun elevation angle with respect to the orbital plane + double mu = 0; ///< Angle of sat from 'midnight' (when sat is at the furthest point from Sun in its orbit) +}; + +/** Calculates satellite orbit geometry - for use in calculating modelled yaw + */ +SatGeom satOrbitGeometry( + GObs& obs) ///< Observation +{ + SatGeom satGeom; + satGeom.rSat = obs.rSat; + + Vector3d& vSat = obs.satVel; + + Vector3d& rSat = satGeom.rSat; + Vector3d& vSatPrime = satGeom.vSatPrime; + VectorEcef& rSun = satGeom.rSun; + VectorEcef& rMoon = satGeom.rMoon; + Vector3d& eNorm = satGeom.eNorm; + double& beta = satGeom.beta; + double& mu = satGeom.mu; + + planetPosEcef(obs.time, E_ThirdBody::SUN, rSun); + planetPosEcef(obs.time, E_ThirdBody::MOON, rMoon); + + vSatPrime = vSat; + vSatPrime[0] -= OMGE * rSat[1]; + vSatPrime[1] += OMGE * rSat[0]; + + Vector3d n = rSat.cross(vSatPrime); //orbit-axis + Vector3d p = rSun.cross(n); //ascension? + + Vector3d eSat = rSat. normalized(); + Vector3d eSun = rSun. normalized(); + eNorm = n. normalized(); //orbit-axis + Vector3d ep = p. normalized(); //ascension? + + beta = asin(eNorm.dot(eSun)); //angle between sun and orbital plane + + double E = acos(eSat .dot(ep)); //angle between sat and ascension node? + if (eSat.dot(eSun) <= 0) mu = PI/2 - E; //sat on dark side + else mu = PI/2 + E; //sat on noon side + + wrapPlusMinusPi(beta); + wrapPlusMinusPi(mu); + + return satGeom; +} + +/** Calculate nominal (ideal) sat yaw for GPS sats +*/ +double nominalYawGps( + double beta, ///< Sun elevation angle with respect to the orbital plane + double mu) ///< Angle of sat from 'midnight' (when sat is at the furthest point from Sun in its orbit) +{ + if ( fabs(beta) < 1E-12 + &&fabs(mu) < 1E-12) + return PI; + + return atan2(-tan(beta), sin(mu)) + PI; +} + +/** Calculates proportion of circle 1 visible with overlapping circle 2 + */ +double circleAreaVisible( + double r1, ///< radius of circle 1 + double r2, ///< radius of circle 2 + double d) ///< distance between circle centres +{ + double intersection = 0; + if (d >= r1 + r2) // no overlap + { + intersection = 0; + } + else if (abs(r1 - r2) >= d) // full overlap + { + double smallerR = std::min(r1, r2); + intersection = PI * SQR(smallerR); + } + else // partial overlap + { + double area1 = PI * SQR(r1); + double area2 = PI * SQR(r2); + + double d1 = (SQR(r1) - SQR(r2) + SQR(d)) / (2 * d); + double d2 = (SQR(r2) - SQR(r1) + SQR(d)) / (2 * d); + intersection = SQR(r1) * acos(d1 / r1) - d1 * sqrt(SQR(r1) - SQR(d1)) + + SQR(r2) * acos(d2 / r2) - d2 * sqrt(SQR(r2) - SQR(d2)); // Ref: https://diego.assencio.com/?index=8d6ca3d82151bad815f78addf9b5c1c6 + } + + double area1 = PI * SQR(r1); + return (area1 - intersection) / area1; +} + +/** Calculates fraction of Sun's disk visible by spacecraft + * 0 = full eclipse (umbra) + * 0 < fraction < 1 = partial eclipse (within penumbra) + * 1 = no eclipse (outside penumbra) + */ +double sunVisibility( + Vector3d& rSat, ///< Satellite position (ECEF) + Vector3d& rSun, ///< Sun position (ECEF) + Vector3d& rMoon) ///< Moon position (ECEF) +{ + struct PosRadius + { + Vector3d pos = Vector3d::Zero(); + double radius = 0; + }; + Vector3d rEarth = Vector3d::Zero(); + + PosRadius earthPosRadius = {rEarth, RE_WGS84}; + PosRadius moonPosRadius = {rMoon, MoonRadius}; + + for (auto& bodyPosRadius : {earthPosRadius, moonPosRadius}) + { + Vector3d rBody = bodyPosRadius.pos; + double bodyRadius = bodyPosRadius.radius; + + Vector3d sunToSat = -rSun + rSat; + Vector3d sunToBody = -rSun + rBody; + Vector3d bodyToSat = -rBody + rSat; + + if (sunToSat.norm() < sunToBody.norm()) + continue; + + Vector3d unitSunToSat = sunToSat.normalized(); + double bodySatAlongSunSat = bodyToSat.dot( unitSunToSat); + Vector3d centreSeparation = bodyToSat.cross( unitSunToSat); + + double sunRadiusAngularSize = SunRadius / sunToSat.norm(); + double bodyRadiusAngularSize = bodyRadius / bodySatAlongSunSat; + double separationAngularSize = centreSeparation.norm() / bodySatAlongSunSat; + + double fraction = circleAreaVisible(sunRadiusAngularSize, bodyRadiusAngularSize, separationAngularSize); + if (fraction < 1) + return fraction; + } + return 1; // no eclipse from Earth or Moon +} + +/** Yaw model for GPS sats + * Ref: http://acc.igs.org/orbits/EclipseReadMe.pdf + * Returns false if no modelled yaw available +*/ +bool satYawGps( + SatSys& Sat, ///< Satellite ID + AttStatus& attStatus, ///< Satellite att status + GTime time, ///< Solution time + SatGeom& satGeom) ///< Satellite geometry +{ + Vector3d& rSat = satGeom.rSat; + Vector3d& vSatPrime = satGeom.vSatPrime; + Vector3d& rSun = satGeom.rSun; + Vector3d& rMoon = satGeom.rMoon; + double& beta = satGeom.beta; + double& mu = satGeom.mu; + + // Nominal behaviour + attStatus.nominalYaw = nominalYawGps(beta, mu); wrapPlusMinusPi(attStatus.nominalYaw); + + // Midnight/noon turns + double reqDyaw = attStatus.nominalYaw - attStatus.modelYaw; wrapPlusMinusPi(reqDyaw); + double dt = (time - attStatus.modelYawTime).to_double(); + + double modelYawRate; + if (dt == 0) modelYawRate = 0; + else modelYawRate = reqDyaw / dt; + + // Eclipse + double fractionSunVisible = sunVisibility(rSat, rSun, rMoon); + if (fractionSunVisible == 0) + { + if (attStatus.modelYawTime == GTime::noTime()) // Check sat not mid-way through eclipse on startup + return false; + + string bt = Sat.blockType().substr(0,7); + if (bt == "GPS-IIA") + return false; + + if (bt == "GPS-IIF") + { + if (attStatus.eclipseYawRate == 0) // start of eclipse + { + double eclipseMuRange = 2 * abs(mu); + double muRate = vSatPrime.norm() / rSat.norm(); + double eclipseDuration = eclipseMuRange / muRate; + double eclipseYawRange = 2 * abs(PI/2 - abs(attStatus.nominalYaw)); // note: assumes not already at max yaw rate + attStatus.eclipseYawRate = eclipseYawRange / eclipseDuration * SGN(modelYawRate); + } + modelYawRate = attStatus.eclipseYawRate; + } + } + else + { + attStatus.eclipseYawRate = 0; + } + + // Max yaw rate cap + double maxYawRate = 0; + bool maxYawRateFound = getSnxSatMaxYawRate(Sat.svn(), time, maxYawRate); + maxYawRate *= SGN(modelYawRate); + if ( maxYawRateFound + &&abs(modelYawRate) > abs(maxYawRate)) + { + modelYawRate = maxYawRate; + } + + attStatus.modelYaw += modelYawRate * dt; wrapPlusMinusPi(attStatus.modelYaw); + + return true; +} + +/** Calculate Sun position in Galileo orbital reference frame {Along, -Cross, -Radial} + */ +Vector3d sunPosOrf( + double beta, ///< Sun elevation angle with respect to the orbital plane + double mu) ///< Angle of sat from 'midnight' (when sat is at the furthest point from Sun in its orbit) +{ + Vector3d eSun; + eSun(0) = -sin(mu + PI) * cos(beta); + eSun(1) = -sin(beta); + eSun(2) = -cos(mu + PI) * cos(beta); + + return eSun; +} + +/** Calculate nominal (ideal) sat yaw for GAL-IOV sats. + * For use w/ ANTEX reference frame (+X axis pointing generally toward sun) + * (Side-note: Approximates nominalYawGps() + PI) + * Ref: https://www.gsc-europa.eu/support-to-developers/galileo-satellite-metadata#3.1 +*/ +double nominalYawGalIov( + Vector3d& eSunRac) ///< Unit vector to Sun in local reference frame (RAC) +{ + Vector3d eSunOrf; // Orbital reference frame + eSunOrf << eSunRac(1), -eSunRac(2), -eSunRac(0); + + return atan2( eSunOrf(1) / sqrt(1 - SQR(eSunOrf(2))), + eSunOrf(0) / sqrt(1 - SQR(eSunOrf(2)))); +} + +/** Yaw model for GAL IOV sats + * Ref: https://www.gsc-europa.eu/support-to-developers/galileo-satellite-metadata#3.1 + * Returns false if no modelled yaw available +*/ +bool satYawGalIov( + SatSys& Sat, ///< Satellite ID + AttStatus& attStatus, ///< Satellite att status + GTime time, ///< Solution time + SatGeom& satGeom) ///< Satellite geometry +{ + Vector3d& rSat = satGeom.rSat; + Vector3d& vSatPrime = satGeom.vSatPrime; + Vector3d& rSun = satGeom.rSun; + double& beta = satGeom.beta; + double& mu = satGeom.mu; + + Vector3d eSunRac = ecef2rac(rSat, vSatPrime) * (rSun - rSat); + eSunRac.normalize(); + attStatus.nominalYaw = nominalYawGalIov(eSunRac); wrapPlusMinusPi(attStatus.nominalYaw); + attStatus.modelYaw = attStatus.nominalYaw; + + // Midnight/noon turns + Vector3d eSunO = sunPosOrf(beta, mu); // note: this is approx. == eSunOrf - might be able to use eSunOrf directly? + double sinBetaX = sin(15 * D2R); + double sinBetaY = sin( 2 * D2R); + if ( abs(eSunO(0)) < sinBetaX + &&abs(eSunO(1)) < sinBetaY) + { + if (attStatus.modelYawTime == GTime::noTime()) // Check sat not mid-way through eclipse on startup + return false; + + if (attStatus.sunDeltaAtSwitch == 0) // i.e. start of eclipse switchover period + attStatus.sunDeltaAtSwitch = SGN(eSunO(1)); + + Vector3d eSunAux; + eSunAux(0) = eSunO(0); + eSunAux(1) = 0.5 * (sinBetaY * attStatus.sunDeltaAtSwitch + eSunO(1)) + +0.5 * (sinBetaY * attStatus.sunDeltaAtSwitch - eSunO(1)) * cos((PI * abs(eSunO(0)))/sinBetaX); + eSunAux(2) = sqrt(1 - SQR(eSunO(0)) - SQR(eSunAux(1))) * SGN(eSunO(2)); + + attStatus.modelYaw = nominalYawGalIov(eSunAux); + } + else + { + attStatus.sunDeltaAtSwitch = 0; // reset when exit eclipse switchover region + } + return true; +} + +/** Yaw model for GAL FOC sats + * Ref: https://www.gsc-europa.eu/support-to-developers/galileo-satellite-metadata#3.1 + * Returns false if no modelled yaw available +*/ +bool satYawGalFoc( + SatSys& Sat, ///< Satellite ID + AttStatus& attStatus, ///< Satellite yaw status + GTime time, ///< Solution time + SatGeom& satGeom) ///< Satellite geometry +{ + Vector3d& rSat = satGeom.rSat; + Vector3d& rSun = satGeom.rSun; + Vector3d& eNorm = satGeom.eNorm; + double& beta = satGeom.beta; + double& mu = satGeom.mu; + + // Note: GAL +X axis points towards deep space but ANTEX ref frame follows GPS Block II/IIA + // attitude convention where +X axis points towards Sun, so +PI rotation req'd for GAL + attStatus.nominalYaw = nominalYawGps(beta, mu) + PI; wrapPlusMinusPi(attStatus.nominalYaw); + attStatus.modelYaw = attStatus.nominalYaw; + + // Midnight/noon turns + Vector3d eSun = rSun.normalized(); + Vector3d eSat = rSat.normalized(); + Vector3d x = eNorm.cross(eSun); + Vector3d y = eNorm.cross(x); + + double colinearAngle; + if (eSat.dot(y) >= 0) colinearAngle = acos(eSat.dot(y)); + else colinearAngle = PI - acos(eSat.dot(y)); + + if ( beta < 4.1 * D2R + &&colinearAngle < 10 * D2R) + { + if (attStatus.modelYawTime == GTime::noTime()) // Check sat not mid-way through eclipse on startup + return false; + + if (attStatus.switchTime == GTime::noTime()) // start of switchover period + { + attStatus.switchTime = time; + attStatus.yawAtSwitch = attStatus.nominalYaw; + } + + double tMod = (time - attStatus.switchTime).to_double(); + double sign = SGN(attStatus.yawAtSwitch); + attStatus.modelYaw = 90 * D2R * sign + (attStatus.yawAtSwitch - 90 * D2R * sign) * cos(2 * PI/5656 * tMod); + } + else + { + attStatus.switchTime = {}; + attStatus.yawAtSwitch = 0; + } + return true; +} + +/** Calculates unit vectors of satellite-fixed coordinates (ECEF) given yaw (assuming Z+ is facing toward Earth) + */ +void yawToAttVecs( + Vector3d& rSat, ///< Sat position (ECEF) + Vector3d& satVel, ///< Sat velocity (ECEF) + double yaw, ///< Yaw (rad) + Vector3d& eXSat, ///< X+ unit vector of satellite-fixed coordinates (ECEF) + Vector3d& eYSat, ///< Y+ unit vector of satellite-fixed coordinates (ECEF) + Vector3d& eZSat) ///< Z+ unit vector of satellite-fixed coordinates (ECEF) +{ + Vector3d vSatPrime = satVel; + vSatPrime[0] -= OMGE * rSat[1]; + vSatPrime[1] += OMGE * rSat[0]; + Vector3d n = rSat.cross(vSatPrime); //orbit-axis + Vector3d en = n. normalized(); + Vector3d eSat = rSat. normalized(); + Vector3d ex = en.cross(eSat); + + double cosy = cos(yaw); + double siny = sin(yaw); + eXSat = siny * en - cosy * ex; + eYSat = cosy * en + siny * ex; + eZSat = eXSat.cross(eYSat); +} + +/** Calculates nominal & model yaw + * Returns false if no modelled yaw available +*/ +void satYaw( + GObs& obs, ///< Observation + AttStatus& attStatus) ///< Satellite att status. Use a disposable copy if calling inside multithreaded code +{ + SatGeom satGeom = satOrbitGeometry(obs); + + switch (obs.Sat.sys) + { + case E_Sys::GPS: + { + attStatus.modelYawValid = satYawGps (obs.Sat, attStatus, obs.time, satGeom); + break; + } + case E_Sys::GAL: + { + string bt = obs.Sat.blockType().substr(0,5); + if (bt == "GAL-1") attStatus.modelYawValid = satYawGalIov(obs.Sat, attStatus, obs.time, satGeom); + else if (bt == "GAL-2") attStatus.modelYawValid = satYawGalFoc(obs.Sat, attStatus, obs.time, satGeom); + else attStatus.modelYawValid = satYawGalFoc(obs.Sat, attStatus, obs.time, satGeom); + break; + } + default: + { + satYawGps (obs.Sat, attStatus, obs.time, satGeom); + attStatus.modelYawValid = false; + // BOOST_LOG_TRIVIAL(warning) << "Attitude model not implemented for " << obs.Sat.sys._to_string() << " in " << __FUNCTION__ << ", using GPS model"; + break; + } + } + + attStatus.nominalYawTime = obs.time; + if (attStatus.modelYawValid) attStatus.modelYawTime = obs.time; +} + +/** Recalls satellite nominal/model attitude + * Returns false if attitude is invalid +*/ +bool satAttModel( + Vector3d& rSat, ///< Satellite position (ECEF) + Vector3d& vSat, ///< Satellite velocity (ECEF) + AttStatus& attStatus, ///< Attitude status + E_Source source) ///< +{ + double yaw; + if (source == +E_Source::NOMINAL) yaw = attStatus.nominalYaw; //Nominal yaw only - no advanced noon/midnight turns + else yaw = attStatus.modelYaw; + + bool pass = false; + if ( attStatus.modelYawValid + ||source == +E_Source::NOMINAL) + { + pass = true; + } + + yawToAttVecs(rSat, vSat, yaw, attStatus.eXBody, attStatus.eYBody, attStatus.eZBody); + + return pass; +} + +/** Converts coords of frame A (expressed in frame G) into transformation matrix from A to G + * E.g. if eX/eY/eZ are body coordinates (frame A) in ECEF (frame G), matrix will + * transform from body frame to ECEF frame: ecef = rot * body. + */ +Matrix3d rotBasisMat( + Vector3d& eX, ///< X+ unit vector of new coordinates + Vector3d& eY, ///< Y+ unit vector of new coordinates + Vector3d& eZ) ///< Z+ unit vector of new coordinates +{ + Matrix3d rot; + rot.col(0) = eX; + rot.col(1) = eY; + rot.col(2) = eZ; + + return rot; +} + +/** Calculates antenna attitude - unit vectors of antenna-fixed coordinates (ECEF) +*/ +void antAtt( + Vector3d& bore, ///< Sensor boresight vector (body frame) + Vector3d& azim, ///< Sensor azimuth vector (body frame) + AttStatus& attStatus) ///< Attitude status +{ + Vector3d eE = azim.cross(bore); + Vector3d eN = azim; + Vector3d eU = bore; + + Matrix3d ant2Body = rotBasisMat(eE, eN, eU); + Matrix3d body2Ecef = rotBasisMat(attStatus.eXBody, attStatus.eYBody, attStatus.eZBody); + Matrix3d ant2Ecef = body2Ecef * ant2Body; + + attStatus.eXAnt = ant2Ecef.col(0); + attStatus.eYAnt = ant2Ecef.col(1); + attStatus.eZAnt = ant2Ecef.col(2); +} + +/** Retrieves precise attitude (from file) - unit vectors of satellite-fixed coordinates (ECEF) + * Returns false if no attitude available (e.g. not found in file, not enough data to interpolate, etc.) +*/ +bool preciseAttitude( + string id, ///< Satellite/receiver ID + GTime time, ///< Solution time + AttStatus& attStatus) ///< Attitude status +{ + auto attMapItr = nav.attMapMap.find(id); if (attMapItr == nav.attMapMap.end()) return false; + auto& [dummy, attMap] = *attMapItr; + auto entryItr2 = attMap.lower_bound(time); if (entryItr2 == attMap .end()) return false; + + auto entryItr1 = entryItr2; + if (entryItr1 != attMap.begin()) entryItr1--; + else if (entryItr2 != attMap.end()) entryItr2++; + else return false; + + auto& [dummy1, entry1] = *entryItr1; + auto& [dummy2, entry2] = *entryItr2; + Quaterniond quat1 = entry1.q; + Quaterniond quat2 = entry2.q; + GTime t1 = entry1.time; + GTime t2 = entry2.time; + + double frac = (time - t1).to_double() + / (t2 - t1).to_double(); + if ( frac < 0 + ||frac > 1) //note: Quaterniond::slerp only accepts frac = [0,1] + { + BOOST_LOG_TRIVIAL(error) + << "Insufficient precise attitude data to perform slerp in " << __FUNCTION__; + + return false; + } + + Quaterniond quatNow = quat1.slerp(frac, quat2); + + Matrix3d body2Ecef; + if (entry1.frame == +E_ObxFrame::ECI) + { + Matrix3d eci2Body = quatNow.toRotationMatrix(); + + Matrix3d body2Eci = eci2Body.transpose(); + + ERPValues erpv = geterp(nav.erp, time); + + Matrix3d i2tMatrix = Matrix3d::Identity(); + + eci2ecef(time, erpv, i2tMatrix); + + body2Ecef = i2tMatrix * body2Eci; + } + else if (entry1.frame == +E_ObxFrame::ECEF) + { + Matrix3d ecef2Body = quatNow.toRotationMatrix(); + + body2Ecef = ecef2Body.transpose(); + } + else if (entry1.frame == +E_ObxFrame::BCRS) + { + // Eugene to implement + } + else + { + BOOST_LOG_TRIVIAL(error) + << "Unknown frame type in " << __FUNCTION__ << ": " << entry1.frame._to_string(); + return false; + } + + attStatus.eXBody = body2Ecef.col(0); + attStatus.eYBody = body2Ecef.col(1); + attStatus.eZBody = body2Ecef.col(2); + + return true; +} + +/** Calculates satellite attitude - unit vectors of satellite-fixed coordinates (ECEF) + * Returns false if no attitude available (e.g. due to eclipse, not found in file, etc.) +*/ +bool satAtt( + SatSys& Sat, ///< Satellite ID + GTime time, ///< Solution time + VectorEcef& rSat, ///< Satellite position (ECEF) + VectorEcef& vSat, ///< Satellite velocity (ECEF) + vector attitudeTypes, ///< Attitude type + AttStatus& attStatus, ///< Attitude status + bool origGal) ///< Use original GAL frame of ref (rotate 180deg yaw from default GPS/antex) - affects GAL only +{ + bool valid = false; + for (auto attitudeType : attitudeTypes) + { + switch (attitudeType) + { + default: BOOST_LOG_TRIVIAL(error) << "Unknown attitudeType in " << __FUNCTION__ << ": " << attitudeType._to_string(); + case E_Source::NOMINAL: { valid = satAttModel ( rSat, vSat, attStatus, E_Source::NOMINAL); break; } + case E_Source::MODEL: { valid = satAttModel ( rSat, vSat, attStatus, E_Source::MODEL); break; } + case E_Source::PRECISE: { valid = preciseAttitude (Sat, time, attStatus); break; } + } + + if (valid) + { + break; + } + } + + if ( origGal == false + &&Sat.sys == +E_Sys::GAL) + { + attStatus.eXBody *= -1; + attStatus.eYBody *= -1; + } + + + if (valid) attStatus.var = acsConfig.model.sat_attitude.valid_var; + else attStatus.var = acsConfig.model.sat_attitude.invalid_var; + + return valid; +} + +/** Satellite attitude - calculates unit vectors of satellite-fixed coordinates (ECEF) + * Returns false if no attitude available (usually due to eclipse) +*/ +bool satAtt( + GObs& obs, ///< Observation data + vector attitudeTypes, ///< Attitude type + AttStatus& attStatus, ///< Attitude status + bool origGal = false) ///< Use original GAL frame of ref (rotate 180deg yaw from default GPS/antex) - affects GAL only +{ + return satAtt( + obs.Sat, + obs.time, + obs.rSat, + obs.satVel, + attitudeTypes, + attStatus, + origGal); +} + +/** Satellite attitude - calculates attitude of satellite as a quaternion (ECEF) +* Also transforms coordinates in body frame into ECEF +* Returns false if no attitude available (usually due to eclipse) +*/ +bool satQuat( + GObs& obs, ///< observation + vector attitudeTypes, ///< Attitude type + Quaterniond& quat, ///< Rotation of satellite from ECEF + bool origGal) ///< Use original GAL frame of ref (rotate 180deg yaw from default GPS/antex) - affects GAL only +{ + auto& attStatus = obs.satNav_ptr->attStatus; + + bool pass = satAtt(obs, attitudeTypes, attStatus, origGal); + + Matrix3d body2Ecef = rotBasisMat(attStatus.eXBody, attStatus.eYBody, attStatus.eZBody); + + quat = Quaterniond(body2Ecef); + + return pass; +} + +/** Update sat nominal/model yaws. + * Call outside of multithreading code + */ +void updateSatAtts( + GObs& obs) ///< observation +{ + auto& satNav = *obs.satNav_ptr; + auto& attStatus = satNav.attStatus; + + satYaw(obs, attStatus); + satAtt(obs, acsConfig.model.sat_attitude.sources, attStatus); + antAtt(satNav.antBoresight, satNav.antAzimuth, attStatus); +} + + +/** Nominal receiver attitude - unit vectors of receiver-fixed coordinates (ECEF) + * Orientation of receiver body frame for nominal receiver attitude: + * x -> east + * y -> north + * z -> up + */ +bool basicRecAttitude( + Station& rec, ///< Receiver position (ECEF) + AttStatus& attStatus) ///< Attitude status +{ + VectorPos pos = ecef2pos(rec.sol.sppRRec); + + Matrix3d E; + pos2enu(pos, E.data()); + + attStatus.eXBody = E.row(0); // x = east + attStatus.eYBody = E.row(1); // y = north + attStatus.eZBody = E.row(2); // z = up + + return true; +} + +void recAtt( + Station& rec, ///< Receiver + GTime time, + vector attitudeTypes) ///< Attitude type +{ + auto& attStatus = rec.attStatus; + + bool valid = false; + for (auto& attitudeType : attitudeTypes) + { + switch (attitudeType) + { + default: BOOST_LOG_TRIVIAL(error) << "Unknown attitudeType in " << __FUNCTION__ << ": " << attitudeType._to_string(); + case E_Source::MODEL: //fallthrough + case E_Source::NOMINAL: { valid = basicRecAttitude(rec, attStatus); break; } + case E_Source::PRECISE: { valid = preciseAttitude (rec.id, time, attStatus); break; } + } + + if (valid) + { + break; + } + } + + antAtt(rec.antBoresight, rec.antAzimuth, attStatus); +} + +/** phase windup model +*/ +void phaseWindup( + GObs& obs, ///< Observation detailing the satellite to apply model to + Station& rec, ///< Position of receiver (ECEF) + double& phw) ///< Output of phase windup result +{ + auto& attStatus = obs.satNav_ptr->attStatus; + Vector3d& eXSat = attStatus.eXAnt; + Vector3d& eYSat = attStatus.eYAnt; + Vector3d& eZSat = attStatus.eZAnt; + + Vector3d& eXRec = rec.attStatus.eXAnt; + Vector3d& eYRec = rec.attStatus.eYAnt; + Vector3d& eZRec = rec.attStatus.eZAnt; + + /* unit vector satellite to receiver */ + Vector3d look = obs.satStat_ptr->e; + + //Get axis of rotation between antenna boresight and look vector + Vector3d recAxis = +1 * eZRec .cross(look) .normalized(); + Vector3d satAxis = -1 * eZSat .cross(look) .normalized(); + + //We dont need 1,2 for the first axis, because they are common + + //Get another unit vector to finish the boresight, axis, coordinate set + Vector3d recQuad1 = +1 * eZRec .cross(recAxis) .normalized(); + Vector3d satQuad1 = -1 * eZSat .cross(satAxis) .normalized(); + + //Get another unit vector to finish the look vector, axis, coordinate set + Vector3d recQuad2 = look .cross(recAxis) .normalized(); + Vector3d satQuad2 = look .cross(satAxis) .normalized(); + + //Apply a zero-twist rotation to the antenna to align it with the look vector. + //Get projection of x axis on coordinate set1, then apply to coordinate set 2 + Vector3d recXnew = eXRec.dot(recAxis) * recAxis + eXRec.dot(recQuad1) * recQuad2; + Vector3d recYnew = eYRec.dot(recAxis) * recAxis + eYRec.dot(recQuad1) * recQuad2; + + Vector3d satXnew = eXSat.dot(satAxis) * satAxis + eXSat.dot(satQuad1) * satQuad2; + Vector3d satYnew = eYSat.dot(satAxis) * satAxis + eYSat.dot(satQuad1) * satQuad2; + + //Get angle offset by looking at receiver's new components alignment with satellite's new x component + double angleOffset = atan2(satXnew.dot(recYnew), -satYnew.dot(recYnew)); + + //Convert to a fraction of cycles (apply an offset to match old code) + double phaseFraction = angleOffset / (2 * PI) - 0.25; + + //keep phase windup continuous from previous result across cycles + phw = phaseFraction + floor(phw - phaseFraction + 0.5); +} diff --git a/src/cpp/common/attitude.hpp b/src/cpp/common/attitude.hpp new file mode 100644 index 000000000..95e0a2762 --- /dev/null +++ b/src/cpp/common/attitude.hpp @@ -0,0 +1,50 @@ + +#pragma once + +#include "eigenIncluder.hpp" +#include "trace.hpp" +#include "gTime.hpp" +#include "enums.h" + +/** Persistent data for yaw model +*/ +struct AttStatus +{ + double nominalYaw = 0; ///< Latest nominal yaw + GTime nominalYawTime = {}; ///< Time of latest nominal yaw + + bool modelYawValid = false; ///< Model yaw was calculated sucessfully + double modelYaw = 0; ///< Latest model yaw + GTime modelYawTime = {}; ///< Time of latest model yaw + double eclipseYawRate = 0; ///< (GPS-IIF) Calculated yaw rate to exit eclipse at nominal yaw + double sunDeltaAtSwitch = 0; ///< (GAL IOV) Sign (1/-1) of Sun y-position (orbital ref. frame) at switchover to modified yaw steering + double yawAtSwitch = 0; ///< (GAL FOC) Yaw at switchover to modified yaw steering + GTime switchTime = {}; ///< (GAL FOC) Time of switchover to modified yaw steering (due to noon/midnight turn) + + VectorEcef eXBody; ///< X+ unit vector of body-fixed coordinates (ECEF) + VectorEcef eYBody; ///< Y+ unit vector of body-fixed coordinates (ECEF) + VectorEcef eZBody; ///< Z+ unit vector of body-fixed coordinates (ECEF) + + VectorEcef eXAnt; ///< X+ unit vector of antenna-fixed coordinates (ECEF) + VectorEcef eYAnt; ///< Y+ unit vector of antenna-fixed coordinates (ECEF) + VectorEcef eZAnt; ///< Z+ unit vector of antenna-fixed coordinates (ECEF) + + double var = 0; +}; + +struct Station; +struct GObs; + +void recAtt( + Station& rec, + GTime time, + vector attitudeTypes); + +bool satAtt( + GObs& obs, + vector attitudeTypes, + AttStatus& attStatus, + bool origGal); + +void updateSatAtts( + GObs& obs); diff --git a/src/cpp/common/azElMapData.hpp b/src/cpp/common/azElMapData.hpp new file mode 100644 index 000000000..8b738bcf1 --- /dev/null +++ b/src/cpp/common/azElMapData.hpp @@ -0,0 +1,22 @@ + +#pragma once + +#include +#include + +using std::vector; +using std::map; + +template +struct AzElMapData +{ + double aziDelta; ///< azimuth increment (degree) + double zenStart; + double zenStop; + double zenDelta; + int nz; ///< number of zenith intervals + int naz; ///< number of non-azimuth dependent intervals + + vector elMap; + map> azElMap; +}; diff --git a/src/cpp/common/biasSINEX.hpp b/src/cpp/common/biasSINEX.hpp index b2e77cc1f..9bc5b3fdb 100644 --- a/src/cpp/common/biasSINEX.hpp +++ b/src/cpp/common/biasSINEX.hpp @@ -1,5 +1,5 @@ -#ifndef BIAS_SINEX_HPP -#define BIAS_SINEX_HPP + +#pragma once #include "navigation.hpp" #include "acsConfig.hpp" @@ -20,12 +20,7 @@ using std::array; using std::map; using std::set; -/** Struct for SINEX bias record -*------------------------------------------------------------------------------- -+BIAS/SOLUTION -*BIAS SVN_ PRN STATION__ OBS1 OBS2 BIAS_START____ BIAS_END______ UNIT __ESTIMATED_VALUE____ _STD_DEV___ __ESTIMATED_SLOPE____ _STD_DEV___ -*/ -struct SinexBias +struct BiasEntry { GTime tini; ///< start time GTime tfin; ///< end time @@ -39,32 +34,13 @@ struct SinexBias string name = ""; ///< receiver name for receiver bias SatSys Sat; ///< satellite prn for satellite bias / satellite system for receiver bias string source = "X"; -}; - -struct Deriv_OSB -{ - GTime tini; - GTime tfin; - GTime updated; - int iod = 0; - double Lbias = 0; ///< bias in meters - double Pbias = 0; ///< bias in meters - double Lvar = 0; ///< bias variance in meters^2 - double Pvar = 0; ///< bias variance in meters^2 - bool LValid = false; - bool PValid = false; -}; - -struct bias_opt -{ - bool SSR_biases = false; - bool non_SSR_biases = true; + + long int posInOutFile =-1; ///< Position this entry is written in biasSINEX file }; E_ObsCode str2code( string& input, - E_MeasType& measType, - double& lam); + E_MeasType& measType); string code2str( E_ObsCode code, @@ -72,7 +48,7 @@ string code2str( void pushBiasSinex( string id, - SinexBias entry); + BiasEntry entry); void initialiseBiasSinex(); @@ -80,7 +56,7 @@ void addDefaultBiasSinex(); bool decomposeDSBBias( string id, - SinexBias& DSB); + BiasEntry& DSB); bool decomposeTGDBias( SatSys Sat, @@ -115,28 +91,20 @@ bool getBiasSinex( double& bias, double& var); -void outp_bias( - Trace& trace, - GTime time, - string receiver, - SatSys Sat, - E_ObsCode code1, - E_ObsCode code2, - double bias, - double variance, - double updat, - E_MeasType measType); - int writeBiasSinex( Trace& trace, GTime time, - string biasfile); - - - -extern array>>>>, NUM_MEAS_TYPES> SINEXBiases; ///< Multi dimensional map, as SINEXBiases[measType][id][code1][code2][time] - -extern map> SINEXBiases_out; ///< Multi dimensional map, as SINEXBiases_out[key][ind] + string biasfile, + StationMap& stationMap); +bool queryBiasOutput( + Trace& trace, + GTime time, + SatSys Sat, + string Rec, + E_ObsCode obsCode, + double& bias_out, + double& variance, + E_MeasType type); -#endif +extern array>>>>, NUM_MEAS_TYPES> SINEXBiases; ///< Multi dimensional map, as SINEXBiases[measType][id][code1][code2][time] diff --git a/src/cpp/common/biasSINEXread.cpp b/src/cpp/common/biasSINEXread.cpp index c693678a1..d91096bec 100644 --- a/src/cpp/common/biasSINEXread.cpp +++ b/src/cpp/common/biasSINEXread.cpp @@ -9,14 +9,13 @@ #include "enums.h" -array>>>>, NUM_MEAS_TYPES> SINEXBiases; ///< Multi dimensional map, as SINEXBiases[measType][id][code1][code2][time] +array>>>>, NUM_MEAS_TYPES> SINEXBiases; ///< Multi dimensional map, as SINEXBiases[measType][id][code1][code2][time] /** Convert observation code string to enum code */ E_ObsCode str2code( string& input, ///< The input observation code string - E_MeasType& measType, ///< Measurement type of this observation - CODE/PHAS - as output - double& lam) ///< Wave length of this signal as output + E_MeasType& measType) ///< Measurement type of this observation - CODE/PHAS - as output { char cods[] = "Lxx"; cods[1] = input[1]; @@ -41,8 +40,6 @@ E_ObsCode str2code( code = E_ObsCode::NONE; } - lam = lambdas[code]; - return code; } @@ -69,7 +66,7 @@ string code2str( /** Convert time string in bias SINEX to gtime struct */ GTime sinex_time_text( - string& line) ///< Start/End time string in bias SINEX + string& line) ///< time system { double year; double doy; @@ -81,9 +78,26 @@ GTime sinex_time_text( { ep[0] = year; time = epoch2time(ep); - time = time + 86400 * (doy - 1) + tod; + time += 86400 * (doy - 1) + tod; } - + + if ( acsConfig.bias_time_system == "C") + time += 14; + + if ( acsConfig.bias_time_system == "TAI") + time -= 19; + + if ( acsConfig.bias_time_system == "R") + time -= 10800.0; + + if ( acsConfig.bias_time_system == "R" + || acsConfig.bias_time_system == "UTC") + { + double leap1 = leapSeconds(time); + double leap2 = leapSeconds(time + leap1 + 1); + time += leap2; + } + return time; } @@ -91,18 +105,15 @@ GTime sinex_time_text( */ void initialiseBiasSinex() { - SinexBias entry; - entry.tini.sec = 0; + BiasEntry entry; entry.bias = 0; entry.var = 0; entry.measType = CODE; entry.name = ""; entry.source = "init"; - for (int i = 0; i < E_Sys::_size(); i++) + for (E_Sys sys : E_Sys::_values()) { - E_Sys sys = E_Sys::_values()[i]; - auto sats = getSysSats(sys); if (acsConfig.process_sys[sys]) for (auto Sat : sats) @@ -121,8 +132,7 @@ void initialiseBiasSinex() */ void addDefaultBiasSinex() { - SinexBias entry; - entry.tini.sec = 0; + BiasEntry entry; entry.bias = 0; entry.var = 0; entry.measType = CODE; @@ -160,7 +170,7 @@ void addDefaultBiasSinex() */ void pushBiasSinex( string id, ///< Device ID - SinexBias entry) ///< Bias entry to push into the SINEXBiases map + BiasEntry entry) ///< Bias entry to push into the SINEXBiases map { //add forward bias to maps SINEXBiases [entry.measType] @@ -192,22 +202,34 @@ void pushBiasSinex( */ bool decomposeDSBBias( string id, ///< ID of the bias - SinexBias& DSB) ///< DSB to be decomposed + BiasEntry& DSB) ///< DSB to be decomposed { auto& Sat = DSB.Sat; + if (Sat.sys == +E_Sys::GLO) + return false; + if ( DSB.cod1 != acsConfig.clock_codesL1[Sat.sys] ||DSB.cod2 != acsConfig.clock_codesL2[Sat.sys]) { return false; } - double lam1 = lambdas[DSB.cod1]; - double lam2 = lambdas[DSB.cod2]; + E_FType ft1 = code2Freq[Sat.sys][DSB.cod1]; + E_FType ft2 = code2Freq[Sat.sys][DSB.cod2]; + double lam1 = nav.satNavMap[Sat].lamMap[ft1]; + double lam2 = nav.satNavMap[Sat].lamMap[ft2]; + + if ( lam1 == 0 + || lam2 == 0) + { + return false; + } + double c2 = -SQR(lam1) / (SQR(lam2) - SQR(lam1)); double c1 = c2 - 1; - SinexBias entry = DSB; + BiasEntry entry = DSB; entry.cod2 = E_ObsCode::NONE; entry.source += "*"; @@ -244,11 +266,11 @@ bool decomposeTGDBias( double bias = tgd * CLIGHT; double gamma = SQR(FREQ1) / SQR(FREQ2); - SinexBias entry; - entry.tini.sec = 1; - entry.measType = CODE; - entry.Sat = Sat; - entry.name = Sat.id(); + BiasEntry entry; + entry.tini.bigTime = 1; + entry.measType = CODE; + entry.Sat = Sat; + entry.name = Sat.id(); //covert TGD to P1-P2 DCB entry.cod1 = cod1; @@ -279,12 +301,12 @@ bool decomposeBGDBias( double gammaE1E5a = SQR(FREQ1) / SQR(FREQ5); double gammaE1E5b = SQR(FREQ1) / SQR(FREQ7); - SinexBias entry; - entry.tini.sec = 1; - entry.measType = CODE; - entry.Sat = Sat; - entry.name = ""; - entry.source = "bgd"; + BiasEntry entry; + entry.tini.bigTime = 1; + entry.measType = CODE; + entry.Sat = Sat; + entry.name = ""; + entry.source = "bgd"; //store BGD E5b/E1 as C1C-IF OSB entry.cod1 = cod1; @@ -333,7 +355,7 @@ void read_biasSINEX_head( /** Read data line in bias SINEX file */ int read_biasSINEX_line( - char* buff) ///< Line to read + char* buff) ///< time system "UTC", "TAI", etc. { int size = strlen(buff); @@ -343,7 +365,7 @@ int read_biasSINEX_line( return 0; } - SinexBias entry; + BiasEntry entry; entry.source = "bsx"; string type (buff + 1, 4); @@ -397,11 +419,19 @@ int read_biasSINEX_line( return 0; } - double lam1 = 0; E_MeasType dummy; - double dummy2 = 0; - entry.cod1 = str2code(cod1str, entry.measType, lam1); - entry.cod2 = str2code(cod2str, dummy, dummy2); + entry.cod1 = str2code(cod1str, entry.measType); + entry.cod2 = str2code(cod2str, dummy); + + + SatSys lamSat = Sat; + if (lamSat.prn == 0) + { + lamSat.prn++; + } + + int ft1 = code2Freq[Sat.sys][entry.cod1]; + double lam1 = nav.satNavMap[lamSat].lamMap[ft1]; /* decoding start/end times */ entry.tini = sinex_time_text(startTime); @@ -453,7 +483,7 @@ int read_biasSINEX_line( { // this seems to be a receiver // for ambiguous GLO receiver bias id (i.e. PRN not specified), duplicate bias entry for each satellite - for (int prn = MINPRNGLO; prn <= MAXPRNGLO; prn++) + for (int prn = 1; prn <= NSATGLO; prn++) { Sat.prn = prn; id = entry.name + ":" + Sat.id(); @@ -480,7 +510,7 @@ int read_biasSINEX_line( /** Read single bias SINEX file */ -int read_biasnx_fil( +int readBiasSinex( string& filename) ///< File to read { int nbia = 0; @@ -503,6 +533,18 @@ int read_biasnx_fil( if (buff[0] == '*') continue; /* comment line */ + if (strstr(buff, "TIME_SYSTEM")) + { + string timeSystem(buff + 40, 1); + if (timeSystem != " ") + { + if (timeSystem == "U") timeSystem = "UTC"; + else if (timeSystem == "T") timeSystem = "TAI"; + + acsConfig.bias_time_system = timeSystem; + } + } + if (strstr(buff, "%=BIA")) { read_biasSINEX_head(buff); @@ -559,16 +601,6 @@ int read_biasnx_fil( return nbia; } -/** Read and store values from SINEX files -*/ -int readBiasSinex( - string& file) ///< File to read -{ - int nbia = read_biasnx_fil(file); - - return nbia; -} - void setRestrictiveStartTime( GTime& current, GTime& potential) @@ -583,7 +615,7 @@ void setRestrictiveEndTime( GTime& current, GTime& potential) { - if ( current.time == 0 + if ( current.bigTime == 0 ||current < potential) { current = potential; @@ -595,13 +627,13 @@ void setRestrictiveEndTime( bool biasRecurser( Trace& trace, ///< Trace to output to GTime& time, ///< Time of bias to look up - SinexBias& output, ///< The bias entry retrieved + BiasEntry& output, ///< The bias entry retrieved const E_ObsCode& obsCode1, ///< Base code of observation to find biases for const E_ObsCode& obsCode2, ///< Secondary code of observation to find biases for const map>>>& obsObsBiasMap, ///< Bias map for given measrement type & device, as obsObsBiasMap[code1][code2][time] + BiasEntry, std::greater>>>& obsObsBiasMap, ///< Bias map for given measrement type & device, as obsObsBiasMap[code1][code2][time] set& checkedObscodes) ///< A list of all checked observation codes { checkedObscodes.insert(obsCode1); @@ -647,7 +679,7 @@ bool biasRecurser( continue; } - SinexBias pathB; + BiasEntry pathB; bool pass = biasRecurser(trace, time, pathB, secondaryKey, obsCode2, obsObsBiasMap, checkedObscodes); if (pass == false) continue; @@ -696,7 +728,7 @@ bool getBias( GTime time, ///< Time of bias to look up const string& id, ///< The id of the device to retrieve the bias of E_MeasType measType, ///< The measurement type to retrieve the bias of - SinexBias& output, ///< The bias entry retrieved + BiasEntry& output, ///< The bias entry retrieved E_ObsCode obsCode1, ///< Base code of observation to find biases for E_ObsCode obsCode2) ///< Secondary code of observation to find biases for { @@ -733,7 +765,7 @@ bool getBiasSinex( const int lv = 3; bias = 0; - var = 0; + var = SQR(acsConfig.no_bias_sigma); if (Sat.sys == +E_Sys::GLO) id = id + ":" + Sat.id(); else id = id + ":" + Sat.sysChar(); @@ -744,8 +776,16 @@ bool getBiasSinex( tracepdeex(lv, trace, "\nReading bias for %s, %s %4s-%4s ...", id.c_str(), type.c_str(), obsCode1._to_string(), obsCode2._to_string()); - SinexBias foundBias; + BiasEntry foundBias; + if ( acsConfig.ssrInOpts.one_freq_phase_bias + && measType == PHAS) + { + E_FType freq = code2Freq[Sat.sys][obsCode1]; + + obsCode1 = freq2CodeHax(Sat.sys, freq); + } + bool pass = getBias(trace, time, id, measType, foundBias, obsCode1, obsCode2); if (pass == false) { @@ -755,7 +795,7 @@ bool getBiasSinex( bias = foundBias.bias; var = foundBias.var; - tracepdeex(lv, trace, " %s: %11.4f from %6s,", type.c_str(), foundBias.bias, foundBias.source.c_str()); + tracepdeex(lv, trace, " %s: %11.4f from %-6s,", type.c_str(), foundBias.bias, foundBias.source.c_str()); return true; } diff --git a/src/cpp/common/biasSINEXwrite.cpp b/src/cpp/common/biasSINEXwrite.cpp index ee7148a7c..637d371ce 100644 --- a/src/cpp/common/biasSINEXwrite.cpp +++ b/src/cpp/common/biasSINEXwrite.cpp @@ -1,17 +1,41 @@ +// #pragma GCC optimize ("O0") #include "biasSINEX.hpp" #include "constants.hpp" +#include "GNSSambres.hpp" +#include "ppp.hpp" +#include "ionoModel.hpp" -int abs_strt[3] = {}; -int abs_nbia = 0; -int abs_updt = 0; -int rel_strt[3] = {}; -int rel_nbia = 0; -int rel_updt = 0; - -map> SINEXBiases_out; +map> SINEXBiases_out; +long int BottomOfFile = 0; +UYds StartTimeofFile; +string lastBiasSINEXFile = ""; +/* Adjust time reference for bias SINEX file (will be UTC by default) */ +void convertTime(GTime &time, string system) +{ + if (acsConfig.bias_time_system == "UTC") + return; + + if (acsConfig.bias_time_system == "R") + { + time += 10800.0; + return; + } + + double leap1 = leapSeconds(time); + double leap2 = leapSeconds(time + leap1 + 1); + time += leap2; + + if (acsConfig.bias_time_system == "C") + time -= 14; + + if (acsConfig.bias_time_system == "TAI") + time += 19; + + return; +} /** Determine if the bias is an OSB or DSB given observation codes */ @@ -25,76 +49,101 @@ string biasType( else return "NONE"; } -/** convert time to yds (doy in bias SINEX starts at 1) +/** Update bias SINEX first line */ -void sinex_time( - GTime time, ///< GTime to be converted to yds - int *yds) ///< Year, doy and seconds +void updateFirstLine( + GTime time, ///< Time of bias to write + Trace& trace, ///< Trace to output to + int numbias) ///< Number of biases to be written { - double ep[6], ep0[6] = {2000, 1, 1, 0, 0, 0}; - time2epoch(time, ep); + GTime now = timeGet(); + + convertTime(now,acsConfig.bias_time_system); - ep0[0] = ep[0]; - int toy = (int) (time - epoch2time(ep0)); + UYds yds_now = now; + UYds ydsTime = now; - yds[0] = (int) ep[0]; - yds[1] = toy / 86400 + 1; //doy[0]=toy/86400; - yds[2] = toy % 86400; + trace.seekp(0); + tracepdeex(0, trace, "%%=BIA 1.00 %3s %4d:%03d:%05d ", acsConfig.analysis_agency.c_str(), yds_now[0], yds_now[1], yds_now[2]); + tracepdeex(0, trace, "%3s %4d:%03d:%05d ",acsConfig.analysis_agency.c_str(), StartTimeofFile[0], StartTimeofFile[1], StartTimeofFile[2]); + tracepdeex(0, trace, "%4d:%03d:%05d A %8d\n", ydsTime[0], ydsTime[1], ydsTime[2], numbias); } -/** Write bias SINEX head +/** Write bias SINEX head for the first time */ -void write_bSINEX_head( - GTime time, ///< Time of bias to write - Trace& trace, ///< Trace to output to - int * yds0, ///< Year, doy and seconds - int numbiases, ///< Number of biases to write - string type, ///< Bias type - OSB and/or DSB - int updatetime, ///< Update time (seconds) - string mode) ///< Bias mode - ABSOLUTE and/or RELATIVE +void writeBSINEXHeader( + GTime time, ///< Time of bias to write + Trace& trace, ///< Trace to output to + double updateInterval) ///< Bias Update Interval (seconds) { - int yds[3]; - GTime now = timeget(); - sinex_time(now,yds); - - tracepdeex(0, trace, "%%=BIA 1.00 %3s %4d:%03d:%05d %3s %4d:%03d:%05d", acsConfig.analysis_agency.c_str(), yds[0], yds[1], yds[2], acsConfig.analysis_agency.c_str(), yds0[0], yds0[1], yds0[2]); - - sinex_time(time, yds); - tracepdeex(0, trace, " %4d:%03d:%05d %8d\n", yds[0], yds[1], yds[2], numbiases); + GTime tim =time; + convertTime(tim,acsConfig.bias_time_system); + StartTimeofFile = tim; + updateFirstLine(time, trace, 0); + tracepdeex(0, trace, "*-------------------------------------------------------------------------------\n"); tracepdeex(0, trace, "+FILE/REFERENCE\n"); - tracepdeex(0, trace, " DESCRIPTION AUS, Position Australia, Geoscience Australia\n"); //todo aaron, get name from config - tracepdeex(0, trace, " OUTPUT AUS %s estimates for day %3d, %4d\n", type.c_str(), yds0[1], yds0[0]); - tracepdeex(0, trace, " CONTACT ken.harima@ga.gov.au\n"); - tracepdeex(0, trace, " SOFTWARE Ginan\n"); - tracepdeex(0, trace, " INPUT Daily 30-sec observations from IGS stations\n"); + tracepdeex(0, trace, " DESCRIPTION %s, %s\n",acsConfig.analysis_agency.c_str(), acsConfig.analysis_center.c_str()); + tracepdeex(0, trace, " OUTPUT OSB estimates for day %3d, %4d\n", StartTimeofFile[1], StartTimeofFile[0]); + tracepdeex(0, trace, " CONTACT %s\n", acsConfig.ac_contact.c_str()); + tracepdeex(0, trace, " SOFTWARE %s\n", acsConfig.analysis_program.c_str()); + tracepdeex(0, trace, " INPUT %s\n", acsConfig.rinex_comment.c_str()); tracepdeex(0, trace, "-FILE/REFERENCE\n"); + + tracepdeex(0, trace, "*-------------------------------------------------------------------------------\n"); tracepdeex(0, trace, "+BIAS/DESCRIPTION\n"); tracepdeex(0, trace, " OBSERVATION_SAMPLING %12.0f\n", acsConfig.epoch_interval); - tracepdeex(0, trace, " PARAMETER_SPACING %12d\n", updatetime); - tracepdeex(0, trace, " DETERMINATION_METHO CLOCK_ANALYSIS\n"); - tracepdeex(0, trace, " BIAS_MODE %s\n", mode.c_str()); - tracepdeex(0, trace, " TIME_SYSTEM G \n"); - //tracepdeex(0, trace, " RECEIVER_CLOCK_REFERENCE_GNSS G \n"); - //tracepdeex(0, trace, " SATELLITE_CLOCK_REFERENCE_OBSERVABLES G L1C L2W\n"); + tracepdeex(0, trace, " PARAMETER_SPACING %12.0f\n", updateInterval); + tracepdeex(0, trace, " DETERMINATION_METHOD COMBINED_ANALYSIS\n"); + tracepdeex(0, trace, " BIAS_MODE ABSOLUTE\n"); + tracepdeex(0, trace, " TIME_SYSTEM %s \n",acsConfig.bias_time_system.c_str()); + + E_Sys refConst = acsConfig.receiver_reference_clk; + tracepdeex(0, trace, " RECEIVER_CLOCK_REFERENCE_GNSS %c\n", refConst._to_string()[0]); + + for (auto& [sys,solve] : acsConfig.solve_amb_for) + { + if (!solve) + continue; + + char sysChar; + switch (sys) + { + case E_Sys::GPS: sysChar = 'G'; break; + case E_Sys::GLO: sysChar = 'R'; break; + case E_Sys::GAL: sysChar = 'E'; break; + case E_Sys::QZS: sysChar = 'J'; break; + case E_Sys::BDS: sysChar = 'C'; break; + default: continue; + } + + E_ObsCode code1= acsConfig.clock_codesL1[sys]; + E_ObsCode code2= acsConfig.clock_codesL2[sys]; + tracepdeex(0, trace, " SATELLITE_CLOCK_REFERENCE_OBSERVABLES %c %s %s\n", sysChar,code1._to_string(),code2._to_string()); + } tracepdeex(0, trace, "-BIAS/DESCRIPTION\n"); + + tracepdeex(0, trace, "*-------------------------------------------------------------------------------\n"); tracepdeex(0, trace, "+BIAS/SOLUTION\n"); tracepdeex(0, trace, "*BIAS SVN_ PRN STATION__ OBS1 OBS2 BIAS_START____ BIAS_END______ UNIT __ESTIMATED_VALUE____ _STD_DEV___\n"); + + BottomOfFile = trace.tellp(); } /** print bias SINEX data line */ -int write_bSINEX_line( - SinexBias bias, ///< Bias entry to write - Trace& trace) ///< Trace to output to +int writeBSINEXLine( + GTime time, + BiasEntry& bias, ///< Bias entry to write + Trace& trace) ///< Stream to output to { string typstr = biasType(bias.cod1, bias.cod2); - if ( typstr != "OSB" - &&typstr != "DSB") + if ( typstr != "OSB") return 0; + string sat = " "; string svn = " "; if (bias.Sat.prn == 0) @@ -109,9 +158,20 @@ int write_bSINEX_line( svn = bias.Sat.svn(); } + string cod1 = code2str(bias.cod1, bias.measType); string cod2 = code2str(bias.cod2, bias.measType); + bool newbotton = false; + if (bias.posInOutFile < 0) + { + trace.seekp(BottomOfFile); + bias.posInOutFile = BottomOfFile; + newbotton = true; + } + else + trace.seekp(bias.posInOutFile); + tracepdeex(0, trace, " %-4s %4s %3s %-9s %-4s %-4s", typstr.c_str(), svn.c_str(), @@ -120,12 +180,16 @@ int write_bSINEX_line( cod1.c_str(), cod2.c_str()); - int tini[3]; - int tend[3]; - sinex_time(bias.tini, tini); - sinex_time(bias.tfin, tend); + GTime tim; + tim = bias.tini; + convertTime(tim,acsConfig.bias_time_system); + UYds tini = tim; + + tim = bias.tfin; + convertTime(tim,acsConfig.bias_time_system); + UYds tend = tim; - tracepdeex(0, trace, " %4d:%03d:%05d %4d:%03d:%05d %4s", + tracepdeex(0, trace, " %4d:%03d:%05d %4d:%03d:%05d %-4s", tini[0], tini[1], tini[2], @@ -134,177 +198,343 @@ int write_bSINEX_line( tend[2], "ns"); - traceFormatedFloat(trace, bias.bias * (1E9/CLIGHT), " %18.15fE%+01d"); - traceFormatedFloat(trace, sqrt(bias.var) * (1E9/CLIGHT), " %8.6fE%+01d"); + tracepdeex(0, trace, " %21.5f", bias.bias * (1E9/CLIGHT)); + tracepdeex(0, trace, " %11.6f", sqrt(bias.var) * (1E9/CLIGHT)); tracepdeex(0, trace, "\n"); + + if (newbotton) + BottomOfFile = trace.tellp(); + return 1; } +/** Adding/updating new bias entry + */ +int addBiasEntry( + Trace& trace, + GTime tini, + GTime tfin, + KFKey kfKey, + E_MeasType measType, + double bias, + double var) +{ + auto& biasMap = SINEXBiases_out[kfKey]; + int found = -1; + + for (auto& [ind, bias] : biasMap) + { + if (bias.tini != tini) continue; + if (bias.measType != measType) continue; + + found = ind; + break; + } + + tracepdeex(3,trace,"\n Searched %s bias for %s %2d %s: ",(measType==CODE)?"CODE ":"PHASE", kfKey.Sat.id().c_str(), kfKey.num, tini.to_string(0).c_str()); + + if (found >= 0) + { + biasMap[found].bias = bias; + + if (var < 1e-12) + var = 1e-12; + + biasMap[found].var = var; + tracepdeex(4,trace," found at index %d: %.4f %.4f", found, bias, var); + } + else + { + found = biasMap.size(); + BiasEntry entry; + entry.name = kfKey.str; + entry.Sat = kfKey.Sat; + entry.cod1 = E_ObsCode::_from_integral(kfKey.num); + entry.cod2 = E_ObsCode::NONE; + + entry.measType = measType; + entry.tini = tini; + entry.tfin = tfin; + + entry.bias = bias; + entry.var = var; + entry.slop = 0; + entry.slpv = 0; + entry.posInOutFile = -1; + biasMap[found] = entry; + + tracepdeex(4,trace," not found, stored at index %d: %.4f %.4f", found, bias, var); + } + return found; +} + +/** Store bias output to write into bias SINEX files +*/ +void updateBiasOutput( + Trace& trace, + GTime time, ///< Time of bias update + StationMap& stationMap, ///< stations for which to output receiver biases + E_MeasType measType) +{ + int nstore = 0; + double bias; + double bvar; + + double updateRate = 0; + if (measType == E_MeasType::CODE) updateRate = acsConfig.ambrOpts.code_output_interval; + if (measType == E_MeasType::PHAS) updateRate = acsConfig.ambrOpts.phase_output_interval; + + if (updateRate <= 0) + return; + + if (updateRate < 30) + updateRate = 30; + + GWeek week = time; + GTow tow = time; + + tow = updateRate * floor(tow / updateRate); + GTime tini = gpst2time (week, tow); + GTime tfin = tini + updateRate; + + KFKey key; + if (measType == E_MeasType::CODE) key.type = KF::CODE_BIAS; + if (measType == E_MeasType::PHAS) key.type = KF::PHASE_BIAS; + + for (E_Sys sys : E_Sys::_values()) + { + if (acsConfig.process_sys[sys] == false) + continue; + + auto sats = getSysSats(sys); + + for (auto& Sat : sats) + for (auto& obsCode : acsConfig.code_priorities[sys]) + if (queryBiasOutput(trace, time, Sat, "", obsCode, bias, bvar, measType)) + { + key.Sat = Sat; + key.str = ""; + key.num = obsCode; + + if (bias != 0) + addBiasEntry( trace, tini, tfin, key, measType, bias, bvar); + else if (key.type == KF::CODE_BIAS + && (obsCode == acsConfig.clock_codesL1[Sat.sys] + || obsCode == acsConfig.clock_codesL2[Sat.sys])) + { + bvar = 1e-12; + addBiasEntry( trace, tini, tfin, key, measType, bias, bvar); + } + + } + + if (acsConfig.ambrOpts.output_rec_bias == false) + continue; + + SatSys sat0; + sat0.sys = sys; + sat0.prn = 0; + + for (auto& [id, rec] : stationMap) + for (auto& obsCode : acsConfig.code_priorities[sys]) + if (queryBiasOutput(trace, time, sat0, id, obsCode, bias, bvar, measType)) + { + key.Sat = sat0; + key.str = id; + key.num = obsCode; + + if (bias != 0) + addBiasEntry( trace, tini, tfin, key, measType, bias, bvar); + } + + } +} + /** Write stored bias output to SINEX file * Return number of written biases (-1 if file not found) */ int writeBiasSinex( Trace& trace, ///< Trace to output to GTime time, ///< Time of bias to write - string biasfile) ///< File to write + string biasfile, ///< File to write + StationMap& stationMap) ///< stations for which to output receiver biases { - tracepdeex(2,trace,"Writing bias SINEX into: %s\n", biasfile.c_str()); + tracepdeex(3,trace,"Writing bias SINEX into: %s %s\n", biasfile.c_str(), time.to_string(0).c_str()); - std::ofstream outputStream(biasfile); + std::ofstream outputStream(biasfile, std::fstream::in | std::fstream::out); if (!outputStream) { tracepdeex(2, trace, "ERROR: cannot open bias SINEX output: %s\n", biasfile.c_str()); return -1; } - int nwrt=0; - - // if (opt.OSB_biases) write_bSINEX_head(time, outputStream, abs_strt, abs_nbia, "OSB", abs_updt, "ABSOLUTE"); - // else if (opt.DSB_biases) write_bSINEX_head(time, outputStream, rel_strt, rel_nbia, "DSB", rel_updt, "RELATIVE"); - // else - // { - // tracepdeex(2, trace, "ERROR: unsupported bias format\n"); - // return 0; - // } - write_bSINEX_head(time, outputStream, abs_strt, abs_nbia, "OSB+DSB", abs_updt, "ABSOLUTE+RELATIVE"); - - // for (auto& idObsObsBiasMap : SINEXBiases_out) - // for (auto& [id, obsObsBiasMap] : idObsObsBiasMap) - // for (auto& [code1, obsBiasMap] : obsObsBiasMap) - // for (auto& [code2, biasMap] : obsBiasMap) - // for (auto& [time, bias] : biasMap) - for (auto& [Key, biasMap] : SINEXBiases_out) - for (auto& [ind, bias] : biasMap) - { - // if (bias.name.empty() == false && opt.REC_biases == false) continue; //dont output this because we dont want receivers - // if (bias.name.empty() && opt.SAT_biases == false) continue; //dont output this because we dont want satellites - // if (bias.biasType == +E_BiasType::OSB && opt.OSB_biases == false) continue; //dont output this because we dont want OSB biases - // if (bias.biasType == +E_BiasType::DSB && opt.DSB_biases == false) continue; //dont output this because we dont want DSB biases - - nwrt += write_bSINEX_line(bias, outputStream); - } - - tracepdeex(0, outputStream, "-BIAS/SOLUTION\n%%=ENDBIA"); + if ( acsConfig.ambrOpts.code_output_interval <= 0 + && acsConfig.ambrOpts.phase_output_interval <= 0) + { + return 0; + } - return nwrt; -} - - -/**************************************************************************************************************************/ -/**************************************************************************************************************************/ -/**************************************************************************************************************************/ - -/** Store bias output to write into bias SINEX files -*/ -void outp_bias( - Trace& trace, ///< Trace to output to - GTime time, ///< Time of bias to write - string receiver, ///< Receiver to output bias of - SatSys Sat, ///< Satellite to output bias of - E_ObsCode code1, ///< Base code of observation to output for - E_ObsCode code2, ///< Secondary code of observation to output for - double bias, ///< Hardware bias - double variance, ///< Hardware bias variance - double updateInterval, ///< Update Interval of hardbias output (seconds) - E_MeasType measType) ///< Measurement type to output bias for -{ - KFKey key; - - string type = biasType(code1, code2); - if (type == "OSB") + if (biasfile != lastBiasSINEXFile) { - if (abs_updt <= 0) - abs_updt = (int) (updateInterval + 0.5); - - if (abs_strt[0] == 0) + tracepdeex(3, trace, "\nStarting new bias SINEX file: %s\n", biasfile.c_str()); + + double updt1; + double updt2; + + if (acsConfig.ambrOpts.code_output_interval > acsConfig.ambrOpts.phase_output_interval) { - sinex_time (time, abs_strt); - tracepdeex (2, trace, "\nInitializing absolute biases %04d:%03d:%05d", abs_strt[0], abs_strt[1], abs_strt[2]); + updt1 = acsConfig.ambrOpts.code_output_interval; + updt2 = acsConfig.ambrOpts.phase_output_interval; } - - key.type = KF::PHASE_BIAS; - } - else if (type == "DSB") - { - if (rel_updt <= 0) - rel_updt = (int) (updateInterval + 0.5); - - if (rel_strt[0] == 0) + else { - sinex_time (time, rel_strt); - tracepdeex (2, trace, "\nInitializing relative biases %04d:%03d:%05d", rel_strt[0], rel_strt[1], rel_strt[2]); + updt1 = acsConfig.ambrOpts.phase_output_interval; + updt2 = acsConfig.ambrOpts.code_output_interval; } - - key.type = KF::DCB; + + if (updt2==0) + updt2 = updt1; + + // int week; + // double tow = time2gpst(time, &week); + // tow = updt1 * floor (tow / updt1); + // GTime time0 = gpst2time (week, tow); + + GTime time0 = time.floorTime((int)updt1); + + SINEXBiases_out.clear(); + + writeBSINEXHeader(time0, outputStream, updt2); + + lastBiasSINEXFile = biasfile; } - else + + if (acsConfig.ambrOpts.code_output_interval > 0) updateBiasOutput(trace, time, stationMap, CODE); + if (acsConfig.ambrOpts.phase_output_interval > 0) updateBiasOutput(trace, time, stationMap, PHAS); + + int numbias=0; + for (auto& [key, biasMap] : SINEXBiases_out) + for (auto& [ind, bias] : biasMap) { - tracepdeex (2, trace, "ERROR: unsupported bias format\n"); - return; + if (biasType(bias.cod1, bias.cod2) != "OSB") + continue; + + numbias++; } - - int numcod = E_ObsCode::MAXCODE + 1; - key.num = numcod * code1._to_integral() + code2._to_integral(); - key.Sat = Sat; - key.str = receiver; - - if (receiver.empty() == false) + + updateFirstLine(time, outputStream, numbias); + + for (auto& [Key, biasMap] : SINEXBiases_out) + for (auto& [ind, bias] : biasMap) { - //this seems to be a receiver - if (Sat.sys != +E_Sys::GLO) - key.Sat.prn = 0; + if ((time-bias.tfin) > DTTOL) + continue; + + if (bias.measType!=CODE) + continue; + + tracepdeex(5,trace,"\n CODE bias for %s %2d %s ... at pos %d", bias.Sat.id().c_str(), bias.cod1._to_string(), ind, bias.posInOutFile); + + writeBSINEXLine(time, bias, outputStream); } - - SinexBias entry; - int week; - double tow = time2gpst(time, &week); - if (updateInterval != 0) - tow = updateInterval * floor (tow / updateInterval); - - entry.name = receiver; - entry.Sat = Sat; - entry.cod1 = code1; - entry.cod2 = code2; - - entry.measType = measType; - entry.tini = gpst2time (week, tow); - entry.tfin = gpst2time (week, tow + updateInterval); - - entry.bias = bias; - entry.var = variance; - entry.slop = 0; - entry.slpv = 0; - - tracepdeex (3, trace, "\nLoading bias for %s %s %s %d %d %s ", Sat.id().c_str(), Sat.svn().c_str(), receiver.c_str(), code1, code2, entry.tini.to_string (0)); - - auto& biasMap = SINEXBiases_out[key]; - int found = -1; - - for (auto& [ind, bias] : biasMap) + + for (auto& [Key, biasMap] : SINEXBiases_out) + for (auto& [ind, bias] : biasMap) { - if (bias.tini != entry.tini) continue; - if (bias.measType != entry.measType) continue; - - found = ind; - break; + if ((time-bias.tfin) > DTTOL) + continue; + + if (bias.measType==CODE) + continue; + + tracepdeex(5,trace,"\n PHASE bias for %s %2d %s ... at pos %d", bias.Sat.id().c_str(), bias.cod1._to_string(), ind, bias.posInOutFile); + + writeBSINEXLine(time, bias, outputStream); } + + outputStream.seekp(BottomOfFile); + + tracepdeex(0, outputStream, "-BIAS/SOLUTION\n%%=ENDBIA"); + + return numbias; +} - if (found < 0) +/** Find and combine biases from multiple sources: +bias inputs, WLNL biases from Ginan 1.0, UC biases from Ginan 2.0 +and DCB from ionosphere modules +*/ +bool queryBiasOutput( + Trace& trace, + GTime time, + SatSys Sat, + string Rec, + E_ObsCode obsCode, + double& bias, + double& variance, + E_MeasType type) +{ + bias = 0; + variance = 0; + E_FType ftyp = code2Freq[Sat.sys][obsCode]; + + tracepdeex(2,trace,"\n Searching %s bias for %s %s %s: ",(type==CODE)?"CODE ":"PHASE", Sat.id().c_str(), obsCode._to_string(), time.to_string(0).c_str()); + + if (acsConfig.process_ppp) /* Ginan 2.x */ { - found = biasMap.size(); - - if (type == "OSB") abs_nbia++; - else if (type == "DSB") rel_nbia++; - - tracepdeex (3, trace, "... new entry %4d", found); + double pppBias; + double pppVar; + + if (!queryBiasUC(trace, time, Sat, Rec, obsCode, pppBias, pppVar, type)) + return false; + + tracepdeex(2,trace,"found UC %.4f %.4e", bias, variance); + bias += pppBias; + variance += pppVar; } - else + else if (acsConfig.process_network) /* Ginan 1.x */ { - tracepdeex (3, trace, "... updating entry %4d", found); + double extBias; + double extVar; + getBiasSinex(trace, time, Sat.id(), Sat, obsCode, type, extBias, extVar); + + bias += extBias; + variance += extVar; + + if (bias!=0) + tracepdeex(4,trace,"found a-priory"); + + if ( type == PHAS + && acsConfig.ambrOpts.NLmode != +E_ARmode::OFF) + { + double WLNLbias; + double WLNLvar; + + if (!queryBiasWLNL(trace, Sat, Rec, ftyp, WLNLbias, WLNLvar)) + return false; + + tracepdeex(4,trace," plus WLNL"); + + bias += WLNLbias; + variance += WLNLvar; + } } - - tracepdeex (3, trace, "\n"); - biasMap[found] = entry; + + /* Ionosphere DCB */ + if ( type == CODE + && acsConfig.process_ionosphere) + { + double dcbBias; + double dcbVar; + + if (!queryBiasDCB(trace, Sat, Rec, ftyp, dcbBias, dcbVar)) + return false; + + tracepdeex(4,trace," plus DCB"); + + bias += dcbBias; + variance += dcbVar; + } + + return true; } - diff --git a/src/cpp/common/binaryStore.cpp b/src/cpp/common/binaryStore.cpp new file mode 100644 index 000000000..e083da203 --- /dev/null +++ b/src/cpp/common/binaryStore.cpp @@ -0,0 +1,166 @@ + + +// #pragma GCC optimize ("O0") + +#include "binaryStore.hpp" +#include "coordinates.hpp" +#include "acsConfig.hpp" +#include "algebra.hpp" + + +map>>> generalDataMap; +// map>> generalDataMap; +// map>> measDataMap; +// map>> stateDataMap; + + + +// map plotMap; + +void storeResiduals( + GTime time, + vector& obsKeys, + VectorXd& prefits, + VectorXd& postfits, + MatrixXd& variance, + string suffix, + int beg, + int num) +{ +// for (int i = beg; i < beg + num; i++) +// { +// auto& obsKey = obsKeys[i]; +// +// auto& measData = measDataMap[suffix][obsKey]; //todo aaron, gonna need mutexes probably +// +// +// auto it = measData.timeIndexMap.find(time); +// if (it == measData.timeIndexMap.end()) +// { +// measData.timeIndexMap[time] = measData.entries.size(); +// measData.entries.push_back({}); +// } +// +// auto& measDataEntry = measData.entries[measData.timeIndexMap[time]]; +// measDataEntry.time = time; +// measDataEntry.prefit = prefits [i]; +// measDataEntry.postfit = postfits [i]; +// measDataEntry.variance = variance (i,i); +// } + + for (int i = beg; i < beg + num; i++) + { + auto& obsKey = obsKeys[i]; + + generalDataMap[suffix][obsKey][E_Component::PREFIT] .push_back({time, prefits (i)}); + generalDataMap[suffix][obsKey][E_Component::POSTFIT] .push_back({time, postfits (i)}); + generalDataMap[suffix][obsKey][E_Component::VARIANCE] .push_back({time, variance (i,i)}); + + + //todo aaron, gonna need mutexes probably + } +} + +void storeResiduals( + GTime time, + VectorXd& rtsPostfits, + string suffix) +{ + +} + +void storeStates( + KFState& kfState, + string suffix) +{ + if (acsConfig.store_binary_states == false) + { + return; + } + + auto time = kfState.time; + + for (auto& [kfKey, index] : kfState.kfIndexMap) + { + if (kfKey.type == KF::ONE) + { + continue; + } + generalDataMap[suffix][kfKey][E_Component::X] .push_back({time, kfState.x (index) }); + generalDataMap[suffix][kfKey][E_Component::P] .push_back({time, kfState.P (index,index) }); + generalDataMap[suffix][kfKey][E_Component::DX] .push_back({time, kfState.dx(index) }); + + + + //todo aaron, gonna need mutexes probably + } + + for (auto& [kfKey, index] : kfState.kfIndexMap) + { + if ( kfKey.type != KF::REC_POS + ||kfKey.num != 0) + { + continue; + } + + Vector3d recPos; + + for (int i = 0; i < 3; i++) + { + auto key = kfKey; + key.num = i; + + kfState.getKFValue(key, recPos(i)); + } + + VectorPos pos = ecef2pos(recPos); + + for (int i = 0; i < 3; i++) + { + auto key = kfKey; + key.num = i; + generalDataMap[suffix][key][E_Component::LLH].push_back({time, pos[i] * R2D}); + } + } + /* + + for (auto& [kfKey, index] : kfState.kfIndexMap) + { + + auto& stateData = stateDataMap[""][kfKey]; //todo aaron, gonna need mutexes probably + + auto it = stateData.timeIndexMap.find(time); + if (it == stateData.timeIndexMap.end()) + { + stateData.timeIndexMap[time] = stateData.entries.size(); + stateData.entries.push_back({}); + } + + auto& stateDataEntry = stateData.entries[stateData.timeIndexMap[time]]; + if (suffix == " apriori") + { + stateDataEntry.apriori = kfState.x [index]; + stateDataEntry.time = kfState.time; + } + else if (suffix == " rts") + { + stateDataEntry.rts = kfState.x [index]; + stateDataEntry.time = kfState.time; + } + else + { + stateDataEntry.time = kfState.time; + stateDataEntry.x = kfState.x [index]; + stateDataEntry.P = kfState.P (index,index); + stateDataEntry.dx = kfState.dx(index); + } + } +*/ +} + +// PlotData plotData; +// plotData.time = kfState.time; +// plotData.prefit = kfState.x[index]; +// +// plotMap[str + suffix].data.push_back(plotData); + diff --git a/src/cpp/common/binaryStore.hpp b/src/cpp/common/binaryStore.hpp new file mode 100644 index 000000000..58699ebfc --- /dev/null +++ b/src/cpp/common/binaryStore.hpp @@ -0,0 +1,72 @@ + +#pragma once + +#include "algebra.hpp" + + +// struct MeasDataEntry +// { +// GTime time; +// double prefit = 0; +// double postfit = 0; +// double rtsPostfit = 0; +// double variance = 0; +// }; + +// struct StateDataEntry +// { +// GTime time; +// double x = 0; +// double dx = 0; +// double P = 0; +// double apriori = 0; +// double rts = 0; +// }; + +struct GeneralDataEntry +{ + GTime time; + double data; +}; + + +template +struct AlgebraData +{ + vector entries; + map timeIndexMap; +}; + +extern map>>> generalDataMap; + +// extern map>> generalDataMap; +// extern map>> measDataMap; +// extern map>> stateDataMap; + + +void storeResiduals( + GTime time, + vector& obsKeys, + VectorXd& prefits, + VectorXd& postfits, + MatrixXd& variance, + string suffix, + int beg, + int num); + +void storeResiduals( + GTime time, + VectorXd& rtsPostfits, + string suffix = ""); + +void storeStates( + KFState& kfState, + string sufflx = ""); + +// struct Plotter +// { +// bool plotted = false; +// vector data; +// }; +// +// extern map plotMap; diff --git a/src/cpp/common/cache.hpp b/src/cpp/common/cache.hpp new file mode 100644 index 000000000..0bee362e8 --- /dev/null +++ b/src/cpp/common/cache.hpp @@ -0,0 +1,38 @@ + +#pragma once + +#include + +template +struct Cache : TYPE +{ + std::function lambda; + + TYPE output; + + bool initialised = false; + + Cache(){} + + Cache& uninit() + { + initialised = false; + + return *this; + } + + const TYPE& useCache( + std::function lambda) + { + if (initialised) + return output; + + this->lambda = lambda; + + output = lambda(); + + initialised = true; + + return output; + } +}; diff --git a/src/cpp/common/common.cpp b/src/cpp/common/common.cpp index 509eeeebc..93bf3f495 100644 --- a/src/cpp/common/common.cpp +++ b/src/cpp/common/common.cpp @@ -3,230 +3,123 @@ #include -#include "common.hpp" +#include + #include "constants.hpp" +#include "common.hpp" +const double ura_eph[] = ///< URA values (ref [3] 20.3.3.3.1.1) +{ + 2.4, 3.4, 4.85, 6.85, 9.65, 13.65, 24, 48, 96, 192, 384, 768, 1536, 3072, 6144 +}; + +/** URA index to URA value (m) +* GLOBAL POSITIONING SYSTEM +* STANDARD POSITIONING SERVICE +* SIGNAL SPECIFICATION +* 2nd Ed, June 2,1995 +* see section - 2.5.3 User Range Accuracy +*/ double svaToUra(int sva) { - /* - GLOBAL POSITIONING SYSTEM - STANDARD POSITIONING SERVICE - SIGNAL SPECIFICATION - 2nd Ed, June 2,1995 - see section - 2.5.3 User Range Accuracy - */ double ura = 0; - if (sva <= 6) + + if (sva < 0) + ura = -1; + else if (sva <= 6) { ura = 10 * pow(2, 1 + ((double)sva / 2.0)); ura = round(ura) / 10.0; } - else if (sva != 15) + else if (sva < 15) ura = pow(2, (double)sva - 2.0); else ura = -1; + return ura; } +/** URA value (m) to URA index +*/ +int uraToSva(double ura) +{ + int sva = 0; + + if (ura < 0) + sva = 15; + else + { + for (sva = 0; sva < 15; sva++) + if (ura_eph[sva] >= ura) + break; + } + return sva; +} +/** Galileo SISA index to SISA value (m) +* EUROPEAN GNSS (GALILEO) OPEN SERVICE SIGNAL-IN-SPACE INTERFACE CONTROL DOCUMENT +* Issue 2.0, January 2021 +* See Section, 5.1.12. Signal In Space Accuracy (SISA) +*/ double svaToSisa(int sva) { - /* - EUROPEAN GNSS (GALILEO) OPEN SERVICE - SIGNAL-IN-SPACE - INTERFACE CONTROL - DOCUMENT - Issue 2.0, January 2021 - See Section, 5.1.12. Signal In Space Accuracy (SISA) - */ - - double sisa; - if (sva <= 49) sisa = 0.0 + (sva - 0) * 0.01; - else if (sva <= 74) sisa = 0.5 + (sva - 50) * 0.02; - else if (sva <= 99) sisa = 1.0 + (sva - 75) * 0.04; - else if (sva <= 125) sisa = 2.0 + (sva - 100) * 0.16; - else sisa = -1; - return sisa; + if (sva < 0) return -1; + else if (sva <= 49) return (0.0 + (sva - 0) * 0.01); + else if (sva <= 74) return (0.5 + (sva - 50) * 0.02); + else if (sva <= 99) return (1.0 + (sva - 75) * 0.04); + else if (sva <= 125) return (2.0 + (sva - 100) * 0.16); + else return -1; } +/** Galileo SISA value (m) to SISA index +*/ int sisaToSva(double sisa) { - if (sisa < 0) - { - BOOST_LOG_TRIVIAL(error) << "Error converting SISA to SVA, value is less than zero."; - return -1; - } - - if (sisa <= 0.49) return (int)((((sisa - 0.0) / 0.01) + 0) + 0.5); - else if (sisa <= 0.98) return (int)((((sisa - 0.5) / 0.02) + 50) + 0.5); - else if (sisa <= 1.96) return (int)((((sisa - 1.0) / 0.04) + 75) + 0.5); - else if (sisa <= 6.00) return (int)((((sisa - 2.0) / 0.16) + 100) + 0.5); - else - { - BOOST_LOG_TRIVIAL(warning) << "Warning: SISA is too large SVA undefined."; - return -1; - } + if (sisa < 0) return 255; + else if (sisa <= 0.49) return (int)((((sisa - 0.0) / 0.01) + 0) + 0.5); + else if (sisa <= 0.98) return (int)((((sisa - 0.5) / 0.02) + 50) + 0.5); + else if (sisa <= 1.96) return (int)((((sisa - 1.0) / 0.04) + 75) + 0.5); + else if (sisa <= 6.00) return (int)((((sisa - 2.0) / 0.16) + 100) + 0.5); + else return 255; } -/* crc-24q parity -------------------------------------------------------------- +/** crc-24q parity * compute crc-24q parity for sbas, rtcm3 -* args : unsigned char *buff I data -* int len I data length (bytes) -* return : crc-24Q parity -* notes : see reference [2] A.4.3.3 Parity -*-----------------------------------------------------------------------------*/ +* see reference [2] A.4.3.3 Parity +*/ unsigned int crc24q( - const unsigned char *buff, - int len) + const unsigned char* buff, ///< data + int len) ///< data length (bytes) { // trace(4,"%s: len=%d\n",__FUNCTION__, len); unsigned int crc = 0; - for (int i=0;i> 16) ^ buff[i]]; return crc; } -void setbitu( - unsigned char* buff, - int pos, - int len, - unsigned int data) +/** Wrap angle between (-pi, pi] + */ +void wrapPlusMinusPi( + double& angle) ///< Angle to wrap { - unsigned int mask=1u<<(len-1); - - if ( len<=0 - ||len>32) - { - return; - } - - unsigned long int invalid = (1ul<= invalid) - { - std::cout << "Warning: " << __FUNCTION__ << " has data outside range\n"; - } - - for (int i = pos; i < pos + len; i++, mask >>= 1) - { - if (data&mask) buff[i/8] |= (1u<<(7-i%8)); - else buff[i/8] &= ~(1u<<(7-i%8)); - } + while (angle <= -PI) angle += 2 * PI; + while (angle > PI) angle -= 2 * PI; } -void setbits( - unsigned char* buff, - int pos, - int len, - int data) +/** Wrap angle between [0, 2pi) + */ +void wrap2Pi( + double& angle) ///< Angle to wrap { - unsigned int mask=1u<<(len-1); - - if ( len<=0 - ||len>32) - { - return; - } - - long int invalid = (1ul<<(len-1)); - - if ( +data >= invalid - ||-data >= invalid) - { - std::cout << "Warning: " << __FUNCTION__ << " has data outside range, setting invalid\n"; - data = -invalid; - } - - for (int i = pos; i < pos + len; i++, mask >>= 1) - { - if (data&mask) buff[i/8] |= (1u<<(7-i%8)); - else buff[i/8] &= ~(1u<<(7-i%8)); - } -} - -int setbituInc( - unsigned char* buff, - int pos, - int len, - unsigned int var) -{ - setbitu(buff, pos, len, var); - return pos + len; -} - -int setbitsInc( - unsigned char* buff, - int pos, - int len, - int var) -{ - setbits(buff, pos, len, var); - return pos + len; + while (angle < 0) angle += 2 * PI; + while (angle >= 2 * PI) angle -= 2 * PI; } -/* extract unsigned/signed bits ------------------------------------------------ -* extract unsigned/signed bits from byte data -* args : unsigned char *buff I byte data -* int pos I bit position from start of data (bits) -* int len I bit length (bits) (len<=32) -* return : extracted unsigned/signed bits -*-----------------------------------------------------------------------------*/ -unsigned int getbitu( - const unsigned char* buff, - int pos, - int len) -{ - unsigned int bits = 0; - for (int i=pos;i>(7-i%8))&1u); - - return bits; -} -int getbits( - const unsigned char* buff, - int pos, - int len) -{ - unsigned int bits = getbitu(buff, pos, len); - - - long int invalid = (1ul<<(len-1)); - - if (bits == -invalid) - { - std::cout << "warning: invalid number received on " << __FUNCTION__ << " " << invalid << " " << len << std::endl; - } - - if ( len<=0 - ||len>=32 - ||!(bits&(1u<<(len-1)))) - { - return (int)bits; - } - return (int)(bits|(~0u< /* constants/macros */ #define SQR(x) ((x)*(x)) -#define POW2(x) ((x)*(x)) #define POW4(x) ((x)*(x)*(x)*(x)) #define SQRT(x) ((x)<=0.0?0.0:sqrt(x)) #define ROUND(x) (int)floor((x)+0.5) -#define MAX(x,y) ((x)>(y)?(x):(y)) -#define MIN(x,y) ((x)<(y)?(x):(y)) #define SWAP(x,y) do {double tmp_; tmp_=x; x=y; y=tmp_;} while (0) #define SGN(x) ((x)<=0.0?-1.0:1.0) @@ -20,6 +16,12 @@ #include "erp.hpp" #include "enums.h" +using std::multimap; +using std::vector; +using std::pair; + +struct SatSys; +struct SatPos; struct Average { @@ -36,107 +38,232 @@ void lowPassFilter( /* coordinates transformation */ -void ecef2enu(const double *pos, const double *r, double *e); -void enu2ecef(const double *pos, const double *e, double *r); -void xyz2enu (const double *pos, double *E); - -void enu2ecef( - const double* pos, - const Vector3d& e, - Vector3d& r); - - -//forward declarations -struct prcopt_t; -struct StationOptions; -struct Obs; -struct SatSys; -struct ERPValues; -struct IERS; - -void eci2ecef( - const GTime tutc, - ERPValues& erpv, - Matrix3d& U, - double* gmst = nullptr, - Matrix3d* dU = nullptr); - -void eci2ecef_sofa( - const double mjdUTC, - IERS& iers, - Matrix3d& U, - Matrix3d& dU); - -void eci2ecef_sofa( - const double mjdUTC, - IERS& iers, - Vector3d& rSat_eci, - Vector3d& vSat_eci, - Vector3d& rSat_ecef, - Vector3d& vSat_ecef); - -void ecef2eci_sofa( - const double mjdUTC, - IERS& iers, - Vector3d& rSat_ecef, - Vector3d& vSat_ecef, - Vector3d& rSat_eci, - Vector3d& vSat_eci); - +void wrapPlusMinusPi( + double& angle); - -Matrix3d R_x( - double Angle); - -Matrix3d R_y( - double Angle); - -Matrix3d R_z( - double Angle); - - -void ecef2pos(const double *r, double *pos); -void ecef2pos(Vector3d& r, double *pos); -void pos2ecef(const double *pos, Vector3d& r); +void wrap2Pi( + double& angle); double geodist(Vector3d& rs, Vector3d& rr, Vector3d& e); double sagnac( - Vector3d& rSource, - Vector3d& rDest); + Vector3d& rSource, + Vector3d& rDest, + Vector3d vel = Vector3d::Zero()); -/* satellites, systems, codes functions */ - -double satazel(const double *pos, const double *e, double *azel); - -unsigned int getbitu (const unsigned char *buff, int pos, int len); -int getbits (const unsigned char *buff, int pos, int len); -unsigned int getbituInc (const unsigned char *buff, int& pos, int len); -int getbitsInc (const unsigned char *buff, int& pos, int len); -int setbitsInc(unsigned char *buff,int pos,int len,const int var); -int setbituInc(unsigned char *buff,int pos,int len,const unsigned int var); +double satazel( + const VectorPos& pos, + const VectorEcef& e, + double* azel); unsigned int crc24q (const unsigned char *buff, int len); -/* positioning models */ void dops(int ns, const double *azel, double elmin, double *dop); int readblq(string file, const char *sta, double *otlDisplacement); - -int satexclude(SatSys& sat, E_Svh svh); - -extern int epoch; -extern GTime tsync; +bool satFreqs( + E_Sys sys, + E_FType& frq1, + E_FType& frq2, + E_FType& frq3); int sisaToSva(double sisa); double svaToSisa(int sva); +int uraToSva(double ura); double svaToUra(int sva); + void replaceTimes( string& str, ///< String to replace macros within boost::posix_time::ptime time_time); ///< Time to use for replacements void updatenav( - Obs& obs); -#endif + SatPos& obs); + + + +/** An iterator that trys to cast elements to the desired type before using them + */ +template< + typename OUTTYPE, + typename INTYPE, + typename VOIDTYPE> +struct IteratorType +{ + typename INTYPE::iterator ptr_ptr; + typename INTYPE::iterator endPtr_ptr; + + IteratorType( + typename INTYPE::iterator startPtr_ptr, + typename INTYPE::iterator endPtr_ptr) + : ptr_ptr (startPtr_ptr), + endPtr_ptr (endPtr_ptr) + { + ptr_ptr--; + incrementUntilGood(); + } + + bool operator !=(IteratorType rhs) + { + return ptr_ptr != rhs.ptr_ptr; + } + + OUTTYPE& operator*() + { + return static_cast(**ptr_ptr); + } + + void incrementUntilGood() + { + while (1) + { + ++ptr_ptr; + if (ptr_ptr == endPtr_ptr) + return; + + try + { + (void) dynamic_cast(**ptr_ptr); + //no throw, sucess, stop + return; + } + catch(...){} + } + } + + void operator++() + { + incrementUntilGood(); + } +}; + +/** An iterator that trys to cast elements to the desired type before using them + */ +template< + typename OUTTYPE, + typename INTYPE, + typename KEYTYPE> +struct MapIteratorType +{ + typename INTYPE::iterator ptr_ptr; + typename INTYPE::iterator endPtr_ptr; + + MapIteratorType( + typename INTYPE::iterator startPtr_ptr, + typename INTYPE::iterator endPtr_ptr) + : ptr_ptr (startPtr_ptr), + endPtr_ptr (endPtr_ptr) + { + if (ptr_ptr == endPtr_ptr) + return; + + try + { + (void) dynamic_cast(*ptr_ptr->second); + //no throw, sucess, stop + return; + } + catch(...){} + + incrementUntilGood(); + } + + bool operator !=(MapIteratorType rhs) + { + return ptr_ptr != rhs.ptr_ptr; + } + + const pair operator*() + { + auto& thing = *ptr_ptr->second; + return {ptr_ptr->first, dynamic_cast(thing)}; + } + + void incrementUntilGood() + { + while (1) + { + ++ptr_ptr; + if (ptr_ptr == endPtr_ptr) + return; + + try + { + (void) dynamic_cast(*ptr_ptr->second); + //no throw, sucess, stop + return; + } + catch(...){} + } + } + + void operator++() + { + incrementUntilGood(); + } +}; + +/** An object just for templating the other functions without over-verbosity + */ +template < + template typename ITERATOR, + typename TYPE, + typename KEYTYPE, + typename INTYPE> +struct Typer +{ + INTYPE& baseContainer; + + Typer( + INTYPE& baseContainer) + : baseContainer (baseContainer) + { + + } + + ITERATOR begin() { return ITERATOR(baseContainer.begin(), baseContainer.end()); } + const ITERATOR begin() const { return ITERATOR(baseContainer.begin(), baseContainer.end()); } + ITERATOR end() { return ITERATOR(baseContainer.end(), baseContainer.end()); } + const ITERATOR end() const { return ITERATOR(baseContainer.end(), baseContainer.end()); } +}; + + +/** Use only a subset of a vector that can be cast to a desired type + */ +template< + typename OUT, + typename ENTRY + > +Typer< + IteratorType, + OUT, + void, + vector> +only( + vector& in) +{ + return Typer >(in); +} + + +/** Use only a subset of a map that can be cast to a desired type + */ +template< + typename OUT, + typename KEYTYPE, + typename VALUE> +Typer< + MapIteratorType, + OUT, + KEYTYPE, + multimap> +only( + multimap& in) +{ + return Typer >(in); +} + + +extern int epoch; +extern GTime tsync; diff --git a/src/cpp/common/constants.cpp b/src/cpp/common/constants.cpp index ac2e88dcf..052d7006a 100644 --- a/src/cpp/common/constants.cpp +++ b/src/cpp/common/constants.cpp @@ -12,167 +12,194 @@ using std::map; #include - -const E_FType ftypes[E_ObsCode::NUM_CODES] = +map> code2Freq = { - [E_ObsCode::NONE] = FTYPE_NONE, - [E_ObsCode::L1C] = F1, - [E_ObsCode::L1P] = F1, - [E_ObsCode::L1W] = F1, - [E_ObsCode::L1Y] = F1, - [E_ObsCode::L1M] = F1, - [E_ObsCode::L1N] = F1, - [E_ObsCode::L1S] = F1, - [E_ObsCode::L1L] = F1, - [E_ObsCode::L1E] = F1, - [E_ObsCode::L1A] = F1, - [E_ObsCode::L1B] = F1, - [E_ObsCode::L1X] = F1, - [E_ObsCode::L1Z] = F1, - [E_ObsCode::L2C] = F2, - [E_ObsCode::L2D] = F2, - [E_ObsCode::L2S] = F2, - [E_ObsCode::L2L] = F2, - [E_ObsCode::L2X] = F2, - [E_ObsCode::L2P] = F2, - [E_ObsCode::L2W] = F2, - [E_ObsCode::L2Y] = F2, - [E_ObsCode::L2M] = F2, - [E_ObsCode::L2N] = F2, - [E_ObsCode::L5I] = F5, - [E_ObsCode::L5Q] = F5, - [E_ObsCode::L5X] = F5, - [E_ObsCode::L7I] = F7, - [E_ObsCode::L7Q] = F7, - [E_ObsCode::L7X] = F7, - [E_ObsCode::L6A] = F6, - [E_ObsCode::L6B] = F6, - [E_ObsCode::L6C] = F6, - [E_ObsCode::L6X] = F6, - [E_ObsCode::L6Z] = F6, - [E_ObsCode::L6S] = F6, - [E_ObsCode::L6L] = F6, - [E_ObsCode::L8I] = F8, - [E_ObsCode::L8Q] = F8, - [E_ObsCode::L8X] = F8, - [E_ObsCode::L2I] = F2, - [E_ObsCode::L2Q] = F2, - [E_ObsCode::L6I] = F6, - [E_ObsCode::L6Q] = F6, - [E_ObsCode::L3I] = F3, - [E_ObsCode::L3Q] = F3, - [E_ObsCode::L3X] = F3, - [E_ObsCode::L1I] = F1, - [E_ObsCode::L1Q] = F1 -}; + { E_Sys::GPS, + { + {E_ObsCode::NONE, FTYPE_NONE}, + {E_ObsCode::L1C, F1 }, + {E_ObsCode::L1S, F1 }, + {E_ObsCode::L1L, F1 }, + {E_ObsCode::L1X, F1 }, + {E_ObsCode::L1P, F1 }, + {E_ObsCode::L1W, F1 }, + {E_ObsCode::L1Y, F1 }, + {E_ObsCode::L1M, F1 }, + {E_ObsCode::L1N, F1 }, + {E_ObsCode::L2C, F2 }, + {E_ObsCode::L2D, F2 }, + {E_ObsCode::L2S, F2 }, + {E_ObsCode::L2L, F2 }, + {E_ObsCode::L2X, F2 }, + {E_ObsCode::L2P, F2 }, + {E_ObsCode::L2W, F2 }, + {E_ObsCode::L2Y, F2 }, + {E_ObsCode::L2M, F2 }, + {E_ObsCode::L2N, F2 }, -const double lambdas[E_ObsCode::NUM_CODES] = -{ - [E_ObsCode::NONE] = 0, - [E_ObsCode::L1C] = CLIGHT/FREQ1, - [E_ObsCode::L1P] = CLIGHT/FREQ1, - [E_ObsCode::L1W] = CLIGHT/FREQ1, - [E_ObsCode::L1Y] = CLIGHT/FREQ1, - [E_ObsCode::L1M] = CLIGHT/FREQ1, - [E_ObsCode::L1N] = CLIGHT/FREQ1, - [E_ObsCode::L1S] = CLIGHT/FREQ1, - [E_ObsCode::L1L] = CLIGHT/FREQ1, - [E_ObsCode::L1E] = CLIGHT/FREQ1, - [E_ObsCode::L1A] = CLIGHT/FREQ1, - [E_ObsCode::L1B] = CLIGHT/FREQ1, - [E_ObsCode::L1X] = CLIGHT/FREQ1, - [E_ObsCode::L1Z] = CLIGHT/FREQ1, - [E_ObsCode::L2C] = CLIGHT/FREQ2, - [E_ObsCode::L2D] = CLIGHT/FREQ2, - [E_ObsCode::L2S] = CLIGHT/FREQ2, - [E_ObsCode::L2L] = CLIGHT/FREQ2, - [E_ObsCode::L2X] = CLIGHT/FREQ2, - [E_ObsCode::L2P] = CLIGHT/FREQ2, - [E_ObsCode::L2W] = CLIGHT/FREQ2, - [E_ObsCode::L2Y] = CLIGHT/FREQ2, - [E_ObsCode::L2M] = CLIGHT/FREQ2, - [E_ObsCode::L2N] = CLIGHT/FREQ2, - [E_ObsCode::L5I] = CLIGHT/FREQ5, - [E_ObsCode::L5Q] = CLIGHT/FREQ5, - [E_ObsCode::L5X] = CLIGHT/FREQ5, - [E_ObsCode::L7I] = CLIGHT/FREQ7, - [E_ObsCode::L7Q] = CLIGHT/FREQ7, - [E_ObsCode::L7X] = CLIGHT/FREQ7, - [E_ObsCode::L6A] = CLIGHT/FREQ6, - [E_ObsCode::L6B] = CLIGHT/FREQ6, - [E_ObsCode::L6C] = CLIGHT/FREQ6, - [E_ObsCode::L6X] = CLIGHT/FREQ6, - [E_ObsCode::L6Z] = CLIGHT/FREQ6, - [E_ObsCode::L6S] = CLIGHT/FREQ6, - [E_ObsCode::L6L] = CLIGHT/FREQ6, - [E_ObsCode::L8I] = CLIGHT/FREQ8, - [E_ObsCode::L8Q] = CLIGHT/FREQ8, - [E_ObsCode::L8X] = CLIGHT/FREQ8, - [E_ObsCode::L2I] = CLIGHT/FREQ2, - [E_ObsCode::L2Q] = CLIGHT/FREQ2, - [E_ObsCode::L6I] = CLIGHT/FREQ6, - [E_ObsCode::L6Q] = CLIGHT/FREQ6, - [E_ObsCode::L3I] = CLIGHT/FREQ2, - [E_ObsCode::L3Q] = CLIGHT/FREQ2, - [E_ObsCode::L3X] = CLIGHT/FREQ2, - [E_ObsCode::L1I] = CLIGHT/FREQ1, - [E_ObsCode::L1Q] = CLIGHT/FREQ1 -}; + {E_ObsCode::L5I, F5 }, + {E_ObsCode::L5Q, F5 }, + {E_ObsCode::L5X, F5 } + } + }, + { E_Sys::GLO, + { + {E_ObsCode::NONE, FTYPE_NONE}, + {E_ObsCode::L1C, G1 }, + {E_ObsCode::L1P, G1 }, -const double gpst0[]={1980,1, 6,0,0,0}; /* gps time reference */ -const double gst0 []={1999,8,22,0,0,0}; /* galileo system time reference */ -const double bdt0 []={2006,1, 1,0,0,0}; /* beidou time reference */ + {E_ObsCode::L2C, G2 }, + {E_ObsCode::L2P, G2 }, -const double leaps[MAXLEAPS+1][7]= -{ - /* leap seconds (y,m,d,h,m,s,utc-gpst) */ - {2017,1,1,0,0,0,-18}, - {2015,7,1,0,0,0,-17}, - {2012,7,1,0,0,0,-16}, - {2009,1,1,0,0,0,-15}, - {2006,1,1,0,0,0,-14}, - {1999,1,1,0,0,0,-13}, - {1997,7,1,0,0,0,-12}, - {1996,1,1,0,0,0,-11}, - {1994,7,1,0,0,0,-10}, - {1993,7,1,0,0,0, -9}, - {1992,7,1,0,0,0, -8}, - {1991,1,1,0,0,0, -7}, - {1990,1,1,0,0,0, -6}, - {1988,1,1,0,0,0, -5}, - {1985,7,1,0,0,0, -4}, - {1983,7,1,0,0,0, -3}, - {1982,7,1,0,0,0, -2}, - {1981,7,1,0,0,0, -1}, - {0} -}; + {E_ObsCode::L3I, G3 }, + {E_ObsCode::L3Q, G3 }, + {E_ObsCode::L3X, G3 }, -double chisqr_arr[100] = -{ - /* chi-sqr(n) (alpha=0.001) */ - 10.8,13.8,16.3,18.5,20.5,22.5,24.3,26.1,27.9,29.6, - 31.3,32.9,34.5,36.1,37.7,39.3,40.8,42.3,43.8,45.3, - 46.8,48.3,49.7,51.2,52.6,54.1,55.5,56.9,58.3,59.7, - 61.1,62.5,63.9,65.2,66.6,68.0,69.3,70.7,72.1,73.4, - 74.7,76.0,77.3,78.6,80.0,81.3,82.6,84.0,85.4,86.7, - 88.0,89.3,90.6,91.9,93.3,94.7,96.0,97.4,98.7,100 , - 101 ,102 ,103 ,104 ,105 ,107 ,108 ,109 ,110 ,112 , - 113 ,114 ,115 ,116 ,118 ,119 ,120 ,122 ,123 ,125 , - 126 ,127 ,128 ,129 ,131 ,132 ,133 ,134 ,135 ,137 , - 138 ,139 ,140 ,142 ,143 ,144 ,145 ,147 ,148 ,149 -}; + {E_ObsCode::L4A, G4 }, + {E_ObsCode::L4B, G4 }, + {E_ObsCode::L4X, G4 }, + + {E_ObsCode::L6A, G6 }, + {E_ObsCode::L6B, G6 }, + {E_ObsCode::L6X, G6 } + } + }, -map lam_carr = -{ - {F1, CLIGHT/FREQ1}, - {F2, CLIGHT/FREQ2}, - {F5, CLIGHT/FREQ5}, - {F6, CLIGHT/FREQ6}, - {F8, CLIGHT/FREQ8} + { E_Sys::GAL, + { + {E_ObsCode::NONE, FTYPE_NONE}, + {E_ObsCode::L1A, F1 }, + {E_ObsCode::L1B, F1 }, + {E_ObsCode::L1C, F1 }, + {E_ObsCode::L1X, F1 }, + {E_ObsCode::L1Z, F1 }, + + {E_ObsCode::L5I, F5 }, + {E_ObsCode::L5Q, F5 }, + {E_ObsCode::L5X, F5 }, + + {E_ObsCode::L6A, F6 }, + {E_ObsCode::L6B, F6 }, + {E_ObsCode::L6C, F6 }, + {E_ObsCode::L6X, F6 }, + {E_ObsCode::L6Z, F6 }, + + {E_ObsCode::L7I, F7 }, + {E_ObsCode::L7Q, F7 }, + {E_ObsCode::L7X, F7 }, + + {E_ObsCode::L8I, F8 }, + {E_ObsCode::L8Q, F8 }, + {E_ObsCode::L8X, F8 } + } + }, + + { E_Sys::BDS, + { + {E_ObsCode::NONE, FTYPE_NONE}, + {E_ObsCode::L1D, F1 }, + {E_ObsCode::L1P, F1 }, + {E_ObsCode::L1X, F1 }, + {E_ObsCode::L1S, F1 }, + {E_ObsCode::L1L, F1 }, + {E_ObsCode::L1Z, F1 }, + {E_ObsCode::L1A, F1 }, + {E_ObsCode::L1N, F1 }, + + {E_ObsCode::L2I, B1 }, + {E_ObsCode::L2Q, B1 }, + {E_ObsCode::L2X, B1 }, + + {E_ObsCode::L5D, F5 }, + {E_ObsCode::L5P, F5 }, + {E_ObsCode::L5X, F5 }, + + {E_ObsCode::L6I, B3 }, + {E_ObsCode::L6Q, B3 }, + {E_ObsCode::L6X, B3 }, + {E_ObsCode::L6D, B3 }, + {E_ObsCode::L6P, B3 }, + {E_ObsCode::L6Z, B3 }, + {E_ObsCode::L6A, B3 }, + + {E_ObsCode::L7I, F7 }, + {E_ObsCode::L7Q, F7 }, + {E_ObsCode::L7X, F7 }, + {E_ObsCode::L7D, F7 }, + {E_ObsCode::L7P, F7 }, + {E_ObsCode::L7Z, F7 }, + + {E_ObsCode::L8D, F8 }, + {E_ObsCode::L8P, F8 }, + {E_ObsCode::L8Z, F8 } + } + }, + + { E_Sys::QZS, + { + {E_ObsCode::NONE, FTYPE_NONE}, + {E_ObsCode::L1C, F1 }, + {E_ObsCode::L1E, F1 }, + {E_ObsCode::L1S, F1 }, + {E_ObsCode::L1L, F1 }, + {E_ObsCode::L1X, F1 }, + {E_ObsCode::L1Z, F1 }, + {E_ObsCode::L1B, F1 }, + + {E_ObsCode::L2S, F2 }, + {E_ObsCode::L2L, F2 }, + {E_ObsCode::L2X, F2 }, + + {E_ObsCode::L5I, F5 }, + {E_ObsCode::L5Q, F5 }, + {E_ObsCode::L5X, F5 }, + {E_ObsCode::L5D, F5 }, + {E_ObsCode::L5P, F5 }, + {E_ObsCode::L5Z, F5 }, + + {E_ObsCode::L6S, F6 }, + {E_ObsCode::L6L, F6 }, + {E_ObsCode::L6X, F6 }, + {E_ObsCode::L6E, F6 }, + {E_ObsCode::L6Z, F6 } + } + }, + + { E_Sys::IRN, + { + /* NavIC F1 in the works... */ + + {E_ObsCode::NONE, FTYPE_NONE}, + {E_ObsCode::L5A, F5 }, + {E_ObsCode::L5B, F5 }, + {E_ObsCode::L5C, F5 }, + {E_ObsCode::L5X, F5 }, + + {E_ObsCode::L9A, I9 }, + {E_ObsCode::L9B, I9 }, + {E_ObsCode::L9C, I9 }, + {E_ObsCode::L9X, I9 } + } + }, + + { E_Sys::SBS, + { + {E_ObsCode::NONE, FTYPE_NONE}, + {E_ObsCode::L1C, F1 }, + + {E_ObsCode::L5I, F5 }, + {E_ObsCode::L5Q, F5 }, + {E_ObsCode::L5X, F5 } + } + } }; + + + + const unsigned int tbl_CRC24Q[]= { 0x000000,0x864CFB,0x8AD50D,0x0C99F6,0x93E6E1,0x15AA1A,0x1933EC,0x9F7F17, @@ -213,8 +240,8 @@ const boost::bimap mCodes_gps = boost::assign::list_of mCodes_qzs = boost::assign::list_of mCodes_bds = boost::assign::list_of::relation> - (E_ObsCode::L1I,0) - (E_ObsCode::L1Q,1) - (E_ObsCode::L1X,2) - (E_ObsCode::L7I,3) - (E_ObsCode::L7Q,4) - (E_ObsCode::L7X,5) - (E_ObsCode::L6I,6) - (E_ObsCode::L6Q,7) - (E_ObsCode::L6X,8); - -const boost::bimap mCodes_sds = boost::assign::list_of::relation> + (E_ObsCode::L2I,0) + (E_ObsCode::L2Q,1) + (E_ObsCode::L2X,2) + (E_ObsCode::L6I,3) + (E_ObsCode::L6Q,4) + (E_ObsCode::L6X,5) + (E_ObsCode::L7I,6) + (E_ObsCode::L7Q,7) + (E_ObsCode::L7X,8) + (E_ObsCode::L1D,9) + (E_ObsCode::L1P,10) + (E_ObsCode::NONE,11) + (E_ObsCode::L5D,12) + (E_ObsCode::L5P,13) + (E_ObsCode::NONE,14) + (E_ObsCode::L1A,15); + +const boost::bimap mCodes_sbs = boost::assign::list_of::relation> (E_ObsCode::L1C,0) (E_ObsCode::L5I,1) - (E_ObsCode::L5Q,2) - (E_ObsCode::L5X,3); + (E_ObsCode::L5Q,2); + + + +map> codeHax = +{ + { E_Sys::GPS, + { + {F1, E_ObsCode::L1C }, + {F2, E_ObsCode::L2W }, + {F5, E_ObsCode::L5I } + } + }, + + { E_Sys::GLO, + { + {G1, E_ObsCode::NONE }, + {G2, E_ObsCode::NONE }, + {G3, E_ObsCode::L3I }, + {G4, E_ObsCode::L4B }, + {G6, E_ObsCode::L6B } + } + }, + + { E_Sys::GAL, + { + {F1, E_ObsCode::L1C }, + {F5, E_ObsCode::L5I }, + {F6, E_ObsCode::L6C }, + {F7, E_ObsCode::L7I }, + {F8, E_ObsCode::L8I } + } + }, + + { E_Sys::BDS, + { + {F1, E_ObsCode::L1P }, + {B1, E_ObsCode::L2I }, + {F5, E_ObsCode::L5P }, + {B3, E_ObsCode::L6I }, + {F7, E_ObsCode::L7P }, + {F8, E_ObsCode::L8P }, + } + }, + + { E_Sys::QZS, + { + {F1, E_ObsCode::L1C }, + {F2, E_ObsCode::L2L }, + {F5, E_ObsCode::L5I }, + {F6, E_ObsCode::L6S } + } + }, + + { E_Sys::IRN, + { + {F5, E_ObsCode::L1A }, + {I9, E_ObsCode::L9A } + } + }, + + { E_Sys::SBS, + { + {F1, E_ObsCode::L1C }, + {F1, E_ObsCode::L5I } + } + } +}; + +E_ObsCode freq2CodeHax( + E_Sys sys, + E_FType ft) +{ + if (codeHax.find(sys) == codeHax.end()) + return E_ObsCode::NONE; + + if (codeHax[sys].find(ft) == codeHax[sys].end()) + return E_ObsCode::NONE; + + return codeHax[sys][ft]; +} diff --git a/src/cpp/common/constants.hpp b/src/cpp/common/constants.hpp index f9ba0d3fe..7430d5ccb 100644 --- a/src/cpp/common/constants.hpp +++ b/src/cpp/common/constants.hpp @@ -1,7 +1,5 @@ -#ifndef __CONSTANTS___HPP_ -#define __CONSTANTS___HPP_ - +#pragma once #include @@ -26,11 +24,12 @@ using std::map; #define FREQ2_GLO 1.24600E9 /* GLONASS G2 base frequency (Hz) */ #define DFRQ2_GLO 0.43750E6 /* GLONASS G2 bias frequency (Hz/n) */ #define FREQ3_GLO 1.202025E9 /* GLONASS G3 frequency (Hz) */ +#define FREQ4_GLO 1.600995E9 /* GLONASS G4 (CDMA G1) frequency (Hz) */ +#define FREQ6_GLO 1.248060E9 /* GLONASS G6 (CDMA G2) frequency (Hz) */ #define FREQ1_CMP 1.561098E9 /* BeiDou B1 frequency (Hz) */ -#define FREQ2_CMP 1.20714E9 /* BeiDou B2 frequency (Hz) */ -#define FREQ3_CMP 1.26852E9 /* BeiDou B3 frequency (Hz) */ - - +#define FREQ2_CMP 1.207140E9 /* BeiDou B2 frequency (Hz) */ +#define FREQ3_CMP 1.268520E9 /* BeiDou B3 frequency (Hz) */ +#define FREQ9_IRN 2.492028E9 /* NavIC / IRNSS S9 frequency (Hz) */ #define PI 3.141592653589793238462643383279502884197169399375105820974 /* pi */ #define PI2 (PI*2) /* pi*2 */ @@ -58,14 +57,17 @@ using std::map; #define MU_CMP 3.986004418E14 /* earth gravitational constant ref [9] */ #define MU MU_GPS -#define MOMENTUM_SCALE 10000000.0 #define RE_WGS84 6378137.0 /* earth semimajor axis (WGS84) (m) */ #define FE_WGS84 (1.0/298.257223563) /* earth flattening (WGS84) */ #define IONO_HEIGHT 350000.0 /* ionosphere height (m) */ +#define RE_MEAN 6371000.0 ///< mean Earth radius (m) +#define RE_IGRF 6371200.0 ///< geomagnetic conventional mean Earth radius for IGRF model (m) + #define JD2MJD 2400000.5 /* JD to MJD */ +#define S_IN_DAY 86400.0 /* Number of seconds in a day */ #define AUPerDay (AU/8.64e04) /* AU/Day (IAU 2009)[m/s] */ #define GM_Earth 3.986004418e14 ///< Geocentric gravitation constant (WGS84) [m^3/s^2] @@ -158,46 +160,29 @@ using std::map; #define MOLARDRY 0.028965 /* molar mass dry air (kg/mol) */ #define UGAS 8.3143 /* universal gas constant (J/K/mol) */ -#define TSYS_GPS 0 /* time system: GPS time */ -#define TSYS_UTC 1 /* time system: UTC */ -#define TSYS_GLO 2 /* time system: GLONASS time */ -#define TSYS_GAL 3 /* time system: Galileo time */ -#define TSYS_QZS 4 /* time system: QZSS time */ -#define TSYS_CMP 5 /* time system: BeiDou time */ - /* End of macro definitions for ACS PDE */ -#define MAXOBSTYPE 256 /* max number of obs type in RINEX */ +#define MAXOBSTYPE 256 /* max number of obs type in RINEX */ #define DTTOL 0.005 /* tolerance of time difference (s) */ #define MAXDTOE 7200.0 /* max time difference to GPS Toe (s) */ #define MAXDTOE_QZS 3600.0 /* max time difference to QZS Toe (s) */ -#define MAXDTOE_GAL 1800.0 /* max time difference to GAL Toe (s) */ +#define MAXDTOE_GAL 9600.0 /* max time difference to GAL Toe (s) */ #define MAXDTOE_CMP 3600.0 /* max time difference to BDS Toe (s) */ #define MAXDBDSTOE 3600.0 /* max time difference to ephem Toe (s) for BDS */ -#define MAXDTOE_GLO 1800.0 /* max time difference to GLO Toe (s) */ +#define MAXDTOE_GLO 7200.0 /* max time difference to GLO Toe (s) */ #define MAXDTOE_SBS 360.0 /* max time difference to SBAS Toe (s) */ -#define MAXLEAPS 64 /* max number of leap seconds table */ - -#define SOLQ_NONE 0 /* solution status: no solution */ -#define SOLQ_FIX 1 /* solution status: fix */ -#define SOLQ_FLOAT 2 /* solution status: float */ -#define SOLQ_SBAS 3 /* solution status: SBAS */ -#define SOLQ_DGPS 4 /* solution status: DGPS/DGNSS */ -#define SOLQ_SINGLE 5 /* solution status: single */ -#define SOLQ_PPP 6 /* solution status: PPP */ - -#define P2_5 0.03125 /* 2^-5 */ -#define P2_6 0.015625 /* 2^-6 */ -#define P2_10 0.0009765625 /* 2^-10 */ +#define P2_5 3.125000000000000E-02 /* 2^-5 */ +#define P2_6 1.562500000000000E-02 /* 2^-6 */ +#define P2_10 9.765625000000000E-04 /* 2^-10 */ #define P2_11 4.882812500000000E-04 /* 2^-11 */ #define P2_15 3.051757812500000E-05 /* 2^-15 */ #define P2_17 7.629394531250000E-06 /* 2^-17 */ #define P2_19 1.907348632812500E-06 /* 2^-19 */ #define P2_20 9.536743164062500E-07 /* 2^-20 */ #define P2_21 4.768371582031250E-07 /* 2^-21 */ -#define P2_23 1.192092895507810E-07 /* 2^-23 */ +#define P2_23 1.192092895507813E-07 /* 2^-23 */ #define P2_24 5.960464477539063E-08 /* 2^-24 */ #define P2_27 7.450580596923828E-09 /* 2^-27 */ #define P2_28 3.725290298461914E-09 /* 2^-28 */ @@ -206,42 +191,34 @@ using std::map; #define P2_31 4.656612873077393E-10 /* 2^-31 */ #define P2_32 2.328306436538696E-10 /* 2^-32 */ #define P2_33 1.164153218269348E-10 /* 2^-33 */ -#define P2_34 5.820766091346740E-11 /* 2^-34 */ +#define P2_34 5.820766091346741E-11 /* 2^-34 */ #define P2_35 2.910383045673370E-11 /* 2^-35 */ -#define P2_38 3.637978807091710E-12 /* 2^-38 */ +#define P2_38 3.637978807091713E-12 /* 2^-38 */ #define P2_39 1.818989403545856E-12 /* 2^-39 */ -#define P2_40 9.094947017729280E-13 /* 2^-40 */ +#define P2_40 9.094947017729282E-13 /* 2^-40 */ #define P2_41 4.547473508864641E-13 /* 2^-41 */ #define P2_43 1.136868377216160E-13 /* 2^-43 */ #define P2_46 1.421085471520200E-14 /* 2^-46 */ #define P2_48 3.552713678800501E-15 /* 2^-48 */ #define P2_50 8.881784197001252E-16 /* 2^-50 */ #define P2_55 2.775557561562891E-17 /* 2^-55 */ -#define P2_59 1.734723475976810E-18 /* 2^-59 */ -#define P2_66 1.355252715606880E-20 /* 2^-66 */ +#define P2_59 1.734723475976807E-18 /* 2^-59 */ +#define P2_66 1.355252715606881E-20 /* 2^-66 */ #define SMOOTHED_SUFFIX "_smoothed" #define FORWARD_SUFFIX "_forward" #define BACKWARD_SUFFIX "_backward" -extern const E_FType ftypes [E_ObsCode::NUM_CODES]; -extern const double lambdas [E_ObsCode::NUM_CODES]; +extern map> code2Freq; -#define mjdJ2000 51544.5 /* modified Julian date of J2000.0 */ #define Arcs 3600.0*180.0/PI /* Arcseconds per radian */ -extern const double gpst0[]; /* gps time reference */ -extern const double gst0 []; /* galileo system time reference */ -extern const double bdt0 []; /* beidou time reference */ extern const unsigned int tbl_CRC24Q[]; -extern const double leaps[MAXLEAPS+1][7]; #define NUM_DAT_ORB_INTP 10 /* number of data for orbit interpolation */ #define NUM_ORD_ORB_INTP 10 /* orders of orbit interpolation */ -extern map lam_carr; /* carrier wave length (m) {L1,L2,...} */ - const unsigned char RTCM_PREAMBLE = 0xD3; extern const boost::bimap mCodes_gps; @@ -251,4 +228,4 @@ extern const boost::bimap mCodes_qzs; extern const boost::bimap mCodes_bds; extern const boost::bimap mCodes_sbs; -#endif +extern E_ObsCode freq2CodeHax (E_Sys sys, E_FType ft); diff --git a/src/cpp/common/corrections.cpp b/src/cpp/common/corrections.cpp index 3c780f77d..3da2a9d1f 100644 --- a/src/cpp/common/corrections.cpp +++ b/src/cpp/common/corrections.cpp @@ -4,13 +4,14 @@ #include #include "observations.hpp" -#include "streamTrace.hpp" +#include "coordinates.hpp" #include "acsConfig.hpp" #include "constants.hpp" #include "satStat.hpp" #include "algebra.hpp" #include "common.hpp" #include "gTime.hpp" +#include "trace.hpp" #include "enums.h" @@ -23,10 +24,10 @@ * return : ionospheric delay (L1) (m) *-----------------------------------------------------------------------------*/ double ionmodel( - GTime t, - const double* ion, - const double* pos, - const double* azel) + GTime t, + const double* ion, + const VectorPos& pos, + const double* azel) { const double ion_default[] = /* 2004/1/1 */ { @@ -34,7 +35,7 @@ double ionmodel( 0.1167E+06, -0.2294E+06, -0.1311E+06, 0.1049E+07 }; - if ( pos[2] < -1E3 + if ( pos.hgt() < -1000 ||azel[1] <= 0) { return 0; @@ -50,19 +51,20 @@ double ionmodel( double psi = 0.0137 / (azel[1] / PI + 0.11) - 0.022; /* subionospheric latitude/longitude (semi-circle) */ - double phi = pos[0] / PI + psi * cos(azel[0]); + double phi = pos.lat() / PI + psi * cos(azel[0]); if (phi > +0.416) phi = +0.416; else if (phi < -0.416) phi = -0.416; - double lam = pos[1] / PI + psi * sin(azel[0]) / cos(phi * PI); + double lam = pos.lon() / PI + psi * sin(azel[0]) / cos(phi * PI); /* geomagnetic latitude (semi-circle) */ phi += 0.064 * cos((lam - 1.617) * PI); /* local time (s) */ - int week; - double tt = 43200 * lam + time2gpst(t, &week); + // int week; + // double tt = 43200 * lam + time2gpst(t, &week); + double tt = GTow(t) + 43200.0 * lam; tt -= floor(tt / 86400) * 86400; /* 0<=tt<86400 */ /* slant factor */ @@ -77,23 +79,27 @@ double ionmodel( return CLIGHT * f * (fabs(x) < 1.57 ? 5E-9 + amp * (1 + x * x * (-0.5 + x * x / 24)) : 5E-9); } -/* ionosphere mapping function ------------------------------------------------- -* compute ionospheric delay mapping function by single layer model -* args : double *pos I receiver position {lat,lon,h} (rad,m) -* double *azel I azimuth/elevation angle {az,el} (rad) -* return : ionospheric mapping function -*-----------------------------------------------------------------------------*/ -double ionmapf(Vector3d& rr, const double el) + +/** ionosphere mapping function +*/ +double ionmapf( + const VectorPos& pos, ///< receiver position in geocentric spherical coordinates + const double* azel, ///< satellite azimuth/elevation angle (rad) + E_IonoMapFn mapFn, ///< model of mapping function + double hion) ///< layer height (km) { - double pos[3]; - ecef2pos(rr.data(), pos); + double alpha = 1; + switch (mapFn) + { + case E_IonoMapFn::SLM: // fallthrough + case E_IonoMapFn::MLM: break; // same to SLM but need to call the function multiple times + case E_IonoMapFn::MSLM: alpha = 0.9782; break; + case E_IonoMapFn::KLOBUCHAR: return 1 + 16 * pow(0.53 - azel[1] / PI, 3); + } - if (pos[2] >= IONO_HEIGHT) - return 1; + double rp = RE_MEAN / (RE_MEAN + hion) * sin(alpha * (PI / 2 - azel[1])); - double rRec = RE_WGS84 + pos[2]; - double rIon = RE_WGS84 + IONO_HEIGHT; - return 1 / cos( asin( rRec / rIon * cos(el)) ); + return 1 / sqrt(1 - SQR(rp)); } /* ionospheric pierce point position ------------------------------------------- * compute ionospheric pierce point (ipp) position and slant factor @@ -101,35 +107,41 @@ double ionmapf(Vector3d& rr, const double el) * double *azel I azimuth/elevation angle {az,el} (rad) * double re I earth radius (km) * double hion I altitude of ionosphere (km) -* double *posp O pierce point position {lat,lon,h} (rad,m) +* double *posp O pierce point position {lat,lon,r} (rad,m) in geocentric spherical coordinate system * return : slant factor * notes : see ref [2], only valid on the earth surface * fixing bug on ref [2] A.4.4.10.1 A-22,23 *-----------------------------------------------------------------------------*/ -double ionppp(const double* pos, const double* azel, double re, - double hion, double* posp) +double ionppp( + const VectorPos& pos, + const double* azel, + double re, + double hion, + VectorPos& posp) { - double cosaz, rp, ap, sinap, tanap; - - rp = re / (re + hion) * cos(azel[1]); - ap = PI / 2 - azel[1] - asin(rp); - sinap = sin(ap); - tanap = tan(ap); - cosaz = cos(azel[0]); - posp[0] = asin(sin(pos[0]) * cos(ap) + cos(pos[0]) * sinap * cosaz); - - if ( (pos[0] > +70 * D2R && +tanap * cosaz > tan(PI / 2 - pos[0])) - ||(pos[0] < -70 * D2R && -tanap * cosaz > tan(PI / 2 + pos[0]))) + double ri = re + hion; + double rp = re / ri * cos(azel[1]); + double ap = PI / 2 - azel[1] - asin(rp); + double sinap = sin(ap); + double tanap = tan(ap); + double cosaz = cos(azel[0]); + posp[0] = asin(sin(pos.lat()) * cos(ap) + cos(pos.lat()) * sinap * cosaz); + + if ( (pos.lat() > +70 * D2R && +tanap * cosaz > tan(PI / 2 - pos.lat())) + ||(pos.lat() < -70 * D2R && -tanap * cosaz > tan(PI / 2 + pos.lat()))) { - posp[1] = pos[1] + PI - asin(sinap * sin(azel[0]) / cos(posp[0])); - } + posp.lon() = pos.lon() + PI - asin(sinap * sin(azel[0]) / cos(posp.lat())); + } else - { - posp[1] = pos[1] + asin(sinap * sin(azel[0]) / cos(posp[0])); + { + posp.lon() = pos.lon() + asin(sinap * sin(azel[0]) / cos(posp.lat())); } - return 1 / sqrt(1 - rp * rp); + posp[2] = ri * 1000; // geocentric radius + + return 1 / sqrt(1 - SQR(rp)); } + /* troposphere model ----------------------------------------------------------- * compute tropospheric delay by standard atmosphere and saastamoinen model * args : gtime_t time I time @@ -138,27 +150,32 @@ double ionppp(const double* pos, const double* azel, double re, * double humi I relative humidity * return : tropospheric delay (m) *-----------------------------------------------------------------------------*/ -double tropmodel(GTime time, const double* pos, const double* azel, double humi) +double tropmodel( + GTime time, + const VectorPos& pos, + const double* azel, + double humi) { const double temp0 = 15; /* temparature at sea level */ - double hgt, pres, temp, e, z, trph, trpw; - if ( pos[2] < -100 - || 1E4 < pos[2] + if ( pos.hgt() < -100 + || pos.hgt() > +10000 || azel[1] <= 0) + { return 0; - + } + /* standard atmosphere */ - hgt = pos[2] < 0 ? 0 : pos[2]; + double hgt = pos.hgt() < 0 ? 0 : pos.hgt(); - pres = 1013.25 * pow(1 - 2.2557E-5 * hgt, 5.2568); - temp = temp0 - 6.5E-3 * hgt + ZEROC; - e = 6.108 * humi * exp((17.15 * temp - 4684) / (temp - 38.45)); + double pres = 1013.25 * pow(1 - 2.2557E-5 * hgt, 5.2568); + double temp = temp0 - 6.5E-3 * hgt + ZEROC; + double e = 6.108 * humi * exp((17.15 * temp - 4684) / (temp - 38.45)); /* saastamoninen model */ - z = PI / 2 - azel[1]; - trph = 0.0022768 * pres / (1 - 0.00266 * cos(2 * pos[0]) - 0.00028 * hgt / 1E3) / cos(z); - trpw = 0.002277 * (1255 / temp + 0.05) * e / cos(z); + double z = PI / 2 - azel[1]; + double trph = 0.0022768 * pres / (1 - 0.00266 * cos(2 * pos.lat()) - 0.00028 * hgt / 1E3) / cos(z); + double trpw = 0.002277 * (1255 / temp + 0.05) * e / cos(z); return trph + trpw; } @@ -167,22 +184,22 @@ double tropmodel(GTime time, const double* pos, const double* azel, double humi) * compute tropospheric delay by standard atmosphere and saastamoinen model */ double tropacs( - const double* pos, ///< receiver position {lat,lon,h} (rad,m) - const double* azel, ///< azimuth/elevation angle {az,el} (rad) - double* map) ///< optional mapping function output + const VectorPos& pos, ///< receiver position {lat,lon,h} (rad,m) + const double* azel, ///< azimuth/elevation angle {az,el} (rad) + double* map) ///< optional mapping function output { const double temp0 = 15; /* temparature at sea level */ - if ( pos[2] < -100 - ||pos[2] > 1E4 - ||azel[1] <= 0) + if ( pos.hgt() < -100 + || pos.hgt() > +10000 + || azel[1] <= 0) { return 0; } /* standard atmosphere */ /* consider the ellipsoid or geoid height */ - double hgt = pos[2]; + double hgt = pos.hgt(); /* standard atmosphere temperature, pressure */ double temp = temp0 - 6.5E-3 * hgt + ZEROC; @@ -229,7 +246,7 @@ double tropacs( map[i] = (1 + a[i] / (1 + b[i] / (1 + c[i]))) / (cos(z) + a[i] / (cos(z) + b[i] / (cos(z) + c[i]))); } - double zhd = 0.002277 * (pres / (1 - 0.00266 * cos(2 * pos[0]) - 0.00028 * hgt / 1E3)); + double zhd = 0.002277 * (pres / (1 - 0.00266 * cos(2 * pos.lat()) - 0.00028 * hgt / 1E3)); return zhd; } @@ -256,10 +273,10 @@ double mapf(double el, double a, double b, double c) (sinel + c)))); } double nmf( - GTime time, - const double pos[], - const double azel[], - double* mapfw) + GTime time, + const VectorPos& pos, + const double azel[], + double* mapfw) { /* ref [5] table 3 */ /* hydro-ave-a,b,c, hydro-amp-a,b,c, wet-a,b,c at latitude 15,30,45,60,75 */ @@ -280,8 +297,8 @@ double nmf( const double aht[] = { 2.53E-5, 5.49E-3, 1.14E-3}; /* height correction */ double el = azel[1]; - double lat = pos[0] * R2D; - double hgt = pos[2]; + double lat = pos.latDeg(); + double hgt = pos.hgt(); if (el <= 0) { @@ -291,8 +308,10 @@ double nmf( return 0; } + UYds yds = time; + /* year from doy 28, added half a year for southern latitudes */ - double y = (time2doy(time) - 28) / 365.25 + (lat < 0 ? 0.5 : 0); + double y = (yds.doy - 28) / 365.25 + (lat < 0 ? 0.5 : 0); double cosy = cos(2 * PI * y); lat = fabs(lat); @@ -328,20 +347,20 @@ double nmf( * ftp://web.haystack.edu/pub/aen/nmf/NMF_JGR.pdf *-----------------------------------------------------------------------------*/ double tropmapf( - GTime time, - const double pos[], - const double azel[], - double* mapfw) + GTime time, + const VectorPos& pos, + const double azel[], + double* mapfw) { // trace(4, "tropmapf: pos=%10.6f %11.6f %6.1f azel=%5.1f %4.1f\n", -// pos[0]*R2D, -// pos[1]*R2D, +// pos.latDeg(), +// pos.lonDeg(), // pos[2], // azel[0]*R2D, // azel[1]*R2D); - if ( pos[2] < -1000 - ||pos[2] > 20000) + if ( pos.hgt() < -1000 + ||pos.hgt() > +20000) { if (mapfw) *mapfw = 0; diff --git a/src/cpp/common/corrections.hpp b/src/cpp/common/corrections.hpp index c86f2f51d..f73258804 100644 --- a/src/cpp/common/corrections.hpp +++ b/src/cpp/common/corrections.hpp @@ -1,26 +1,51 @@ -#ifndef __CORRECTIONS__HPP__ -#define __CORRECTIONS__HPP__ + +#pragma once #include using std::string; #include "eigenIncluder.hpp" -#include "observations.hpp" #include "gTime.hpp" +#include "enums.h" struct Navigation; -/* atmosphere models ---------------------------------------------------------*/ -double ionmodel(GTime t, const double *ion, const double *pos, const double *azel); -double ionmapf(Vector3d&rr, const double el); -double ionppp(const double *pos, const double *azel, double re, double hion, double *pppos); -bool iontec(GTime time, const Navigation *nav, const double *pos, const double *azel, int opt, double&delay, double&var); -void readtec(string file, Navigation *nav); +double ionmodel( + GTime t, + const double* ion, + const VectorPos& pos, + const double* azel); + +double ionmapf( + const VectorPos& pos, + const double* azel, + E_IonoMapFn mapFn, + double hion); + +double ionppp( + const VectorPos& pos, + const double* azel, + double re, + double hion, + VectorPos& pppos); + +bool iontec( + GTime time, + const Navigation* nav, + const VectorPos& pos, + const double* azel, + E_IonoMapFn mapFn, + E_IonoFrame frame, + double& delay, + double& var); + +void readTec( + string file, + Navigation* nav); double relativity1( - Vector3d& rSat, - Vector3d& satVel); + Vector3d& rSat, + Vector3d& satVel); -#endif diff --git a/src/cpp/common/cost.cpp b/src/cpp/common/cost.cpp new file mode 100644 index 000000000..4c6ac4f23 --- /dev/null +++ b/src/cpp/common/cost.cpp @@ -0,0 +1,304 @@ + +#include + +#include + +#include "coordinates.hpp" +#include "acsConfig.hpp" +#include "cost.hpp" +#include "ppp.hpp" +#include "EGM96.h" + + +static map > filePosMap; +static map startTimeMap; +static map numSamplesMap; + + +/** Replaces first instance of string 'toReplace' with 'replaceWith' within 's' +*/ +bool replaceStr( + string& s, ///< String to modify + string toReplace, ///< String to replace + string replaceWith) ///< String to replace with +{ + std::size_t pos = s.find(toReplace); + if (pos == string::npos) return false; + s.replace(pos, toReplace.length(), replaceWith); + return true; +} + +/** Outputs troposphere COST file +*/ +void outputCost( + string filename, ///< Filename + Station& rec, ///< Receiver + GTime time, ///< Time of solution + KFState& kfState) ///< KF object containing positioning & trop solutions +{ + std::ofstream fout(filename, std::fstream::in | std::fstream::out); + fout.seekp(0, fout.end); // seek to end of file + bool firstWrite = (fout.tellp() == 0); // file is empty if current position is 0 + + if (firstWrite) + startTimeMap[filename] = time; + long int duration = (time - startTimeMap[filename]).to_int(); + if (duration % acsConfig.cost_time_interval != 0) + return; + + if (firstWrite) + { + tracepdeex(0, fout, "%-20s %-20s %-20s\n", + acsConfig.cost_format, // Format name & version number + acsConfig.cost_project, // Project name + acsConfig.cost_status); // File status + + string locationName = rec.snx.id_ptr->desc; + boost::trim(locationName); + + bool commaReplaced = replaceStr(locationName, ", ", " ("); + if (commaReplaced) + locationName.push_back(')'); + + tracepdeex(0, fout, "%-4s %-9s %-60s\n", + rec.snx.id_ptr->sitecode .c_str(), // Rec ID + rec.snx.id_ptr->domes .c_str(), // DOMES ID + locationName .c_str()); // Site name with country + + tracepdeex(0, fout, "%-20s %-20s\n", + rec.receiverType .c_str(), // Receiver type + rec.antennaType .c_str()); // Antenna type + } + + if (firstWrite) filePosMap[filename][E_FilePos::COORD] = fout.tellp(); + fout.seekp( filePosMap[filename][E_FilePos::COORD]); // Overwrite + + + VectorEcef recPosEcef; + bool kfFound = true; + for (int i = 0; i < 3; i++) + { + kfFound &= kfState.getKFValue({KF::REC_POS, {}, rec.id, i}, recPosEcef(i)); + } + + if (kfFound == false) + { + recPosEcef = rec.aprioriPos; + } + + VectorEcef eccEcef = body2ecef(rec.attStatus, rec.snx.ecc_ptr->ecc); + VectorPos recPos = ecef2pos(recPosEcef + eccEcef); + + if (recPos[1] < 0) + recPos[1] += 2 * PI; + + double geoidOffset = egm96_compute_altitude_offset(recPos.latDeg(), recPos.lonDeg()); + + tracepdeex(0, fout, "%12.6lf%12.6lf%12.3lf%12.3lf%12.3lf\n", + recPos.latDeg(), + recPos.lonDeg(), + recPos.hgt(), // ARP height above ellipsoid + recPos.hgt() - geoidOffset, // ARP height above geoid + rec.snx.ecc_ptr->ecc.u()); // ARP height above benchmark + + if (firstWrite) + tracepdeex(0, fout, "%-20s ", time.gregString().c_str()); // Time of first sample + + if (firstWrite) filePosMap[filename][E_FilePos::CURR_TIME] = fout.tellp(); + fout.seekp( filePosMap[filename][E_FilePos::CURR_TIME]); + tracepdeex(0, fout, "%-20s\n", time.gregString().c_str()); // Time of processing + + if (firstWrite) + { + tracepdeex(0, fout, "%-20s %-20s %-20s %-20s\n", + acsConfig.cost_centre, // Processing centre + acsConfig.cost_method, // Processing method + acsConfig.cost_orbit_type, // Orbit type + acsConfig.cost_met_source); // Source of met. data + + tracepdeex(0, fout, "%5d%5d", + acsConfig.cost_time_interval / 60, // Nominal time increment between data samples (min) + acsConfig.cost_time_interval / 60); // Batch updating interval (min) + } + + if (firstWrite) filePosMap[filename][E_FilePos::TOTAL_TIME] = fout.tellp(); + fout.seekp( filePosMap[filename][E_FilePos::TOTAL_TIME]); + tracepdeex(0, fout, "%5d\n", duration / 60); // Total length of batch time series + + if (firstWrite) filePosMap[filename][E_FilePos::PCDH] = fout.tellp(); + fout.seekp( filePosMap[filename][E_FilePos::PCDH]); + + bool isRealTime = (acsConfig.obs_rtcm_inputs.size() > 0); + + union + { + unsigned int all = 0; + struct + { + unsigned isRealTime : 1; ///< Data processed in near-real time [false: (re-)processed off-line] + unsigned climate : 1; ///< Data processed to climate quality [false: NRT quality] + unsigned otl : 1; ///< Ocean tide loading correction applied + unsigned atc : 1; ///< Atmospheric loading correction applied + unsigned localMetData : 1; ///< Local surface met. sensor data available + unsigned centredTime : 1; ///< Timestamps are at the centre of period [false: end of period] + unsigned gpsUsed : 1; ///< GPS satellite(s) used + unsigned gloUsed : 1; ///< GLONASS satellite(s) used + unsigned galUsed : 1; ///< Galileo satellite(s) used + unsigned reserved : 22; ///< Reserved + unsigned invalid : 1; ///< PCDH is missing or invalid + }; + } pcdh; ///< Product Confidence Data - Header + pcdh.isRealTime = isRealTime; + pcdh.climate = false; + pcdh.otl = acsConfig.model.tides.otl; + pcdh.atc = false; + pcdh.localMetData = false; + pcdh.centredTime = false; + pcdh.gpsUsed = acsConfig.process_sys[E_Sys::GPS]; + pcdh.gloUsed = acsConfig.process_sys[E_Sys::GLO]; + pcdh.galUsed = acsConfig.process_sys[E_Sys::GAL]; + pcdh.invalid = false; + tracepdeex(0, fout, "%08x\n", (uint32_t)pcdh.all); // Product confidence data - header + + auto& numSamplesPos = filePosMap[filename][E_FilePos::NUM_SAMPLES]; + + if (firstWrite) + numSamplesPos = fout.tellp(); + + fout.seekp(numSamplesPos); + + numSamplesMap[filename]++; + + tracepdeex(0, fout, "%4d\n", numSamplesMap[filename]); // Number of data samples + + + // Body + if (firstWrite == false) + fout.seekp(filePosMap[filename][E_FilePos::FOOTER]); + + + int obsCount = 0; + for (auto& obs : only(rec.obsList)) + { + if ( acsConfig.process_sys[obs.Sat.sys] == false + ||obs.exclude) + { + continue; + } + obsCount++; + } + + union + { + unsigned int all = 0; + struct + { + unsigned numSats : 5; ///< Num GNSS sasts in solution [31 = missing] + unsigned obsMetData : 1; ///< Observed met. data used [false: NWP met data] + unsigned ztdPoorQuality : 1; ///< ZTD data quality is considered poor + unsigned reserved : 24; ///< Reserved + unsigned invalid : 1; ///< PCDD is missing or invalid + }; + } pcdd; ///< Product Confidence Data - Data + + pcdd.numSats = std::min(obsCount, 31); + pcdd.obsMetData = false; + pcdd.ztdPoorQuality = false; + pcdd.invalid = false; + + double tropStates[3] = {}; + double tropVars [3] = {}; + bool tropFound [3] = {}; + + for (auto& [key, index] : kfState.kfIndexMap) + { + if ( key.type != KF::TROP + &&key.type != KF::TROP_GRAD) + { + continue; + } + + if ( acsConfig.pppOpts.common_atmosphere == false + &&key.str != rec.id) + { + continue; + } + + double state = kfState.x(index); + double var = kfState.P(index,index); + + int num; + if (key.type == KF::TROP) num = 0; + else num = key.num + 1; + + tropFound [num] = true; + tropStates [num] += state; + tropVars [num] += var; + } + + double ztd = -9.9 / 1000; + double zwd = -9.9 / 1000; + double ztdStd = -9.9 / 1000; + double nsGrad = -9.99 / 1000; + double ewGrad = -9.99 / 1000; + double nsGradStd = -9.99 / 1000; + double ewGradStd = -9.99 / 1000; + + if (tropFound[0]) + { + ztd = tropStates [0]; + ztdStd = sqrt( tropVars [0]); + double azel[2] = {0,1}; // tropacs requires el>0 + double zhd = tropacs(recPos, azel); + zwd = ztd - zhd; + } + + double gradM = gradMapFn(30 * D2R); + + if (tropFound[1]) { nsGrad = gradM * tropStates[1]; nsGradStd = sqrt(tropVars[1]); } + if (tropFound[2]) { ewGrad = gradM * tropStates[2]; ewGradStd = sqrt(tropVars[2]); } + + GEpoch epoch = time; + tracepdeex(0, fout, " %02d %02d %02d %08x%7.1lf%7.1lf%7.1lf%7.1lf%7.1lf%7.1lf%7.1lf%7.2lf%7.2lf%7.2lf%7.2lf%8.3lf\n", + (int)epoch.hour, // Timestamp (hr) + (int)epoch.min, // Timestamp (min) + (int)epoch.sec, // Timestamp (sec) + (uint32_t)pcdd.all, // Product confidence data - data + ztd * 1000, // ZTD (mm) + ztdStd * 1000, // ZTD std-dev (mm) + zwd * 1000, // ZWD (mm) + -9.9, // IWV (kg.m^-2) + -9.9, // Pressure (hPa) + -9.9, // Temperature used for IWV (K) + -9.9, // Relative humidity used for IWV (%) + nsGrad * 1000, // N/S delay gradient (mm) + ewGrad * 1000, // E/W delay gradient (mm) + nsGradStd * 1000, // N/S delay gradient std-dev (mm) + ewGradStd * 1000, // E/W delay gradient std-dev (mm) + -99.999); // Vertically integrated TEC (TECU) + + tracepdeex(0, fout, "%4d\n", obsCount); // Number of slant samples to follow + + for (auto& obs : only(rec.obsList)) + { + if ( acsConfig.process_sys[obs.Sat.sys] == false + ||obs.exclude + ||obs.tropSlant == 0) + { + continue; + } + + SatStat& satStat = *obs.satStat_ptr; + + tracepdeex(0, fout, "%-4s%7.1lf%7.1lf%7.1lf%7.1lf\n", + obs.Sat.id().c_str(), // Sat ID + obs.tropSlant * 1000, // Total slant delay (mm) + sqrt(obs.tropSlantVar) * 1000, // Total slant delay std-dev (mm) + satStat.azel[0] * R2D, // Slant azi angle (CW from true North) + satStat.azel[1] * R2D); // Slant ele angle (from local horizon) + } + + filePosMap[filename][E_FilePos::FOOTER] = fout.tellp(); + + tracepdeex(0, fout, "----------------------------------------------------------------------------------------------------\n"); +} diff --git a/src/cpp/common/cost.hpp b/src/cpp/common/cost.hpp new file mode 100644 index 000000000..2ac1a749c --- /dev/null +++ b/src/cpp/common/cost.hpp @@ -0,0 +1,15 @@ + +#include +#include "gTime.hpp" + +struct KFState; +struct Station; + +using std::string; + +void outputCost( + string filename, + Station& rec, + GTime time, + KFState& kfState); + diff --git a/src/cpp/common/debug.cpp b/src/cpp/common/debug.cpp index 2ed55556b..d203fdb32 100644 --- a/src/cpp/common/debug.cpp +++ b/src/cpp/common/debug.cpp @@ -1,25 +1,27 @@ #pragma GCC optimize ("O0") + + #include #include #include "eigenIncluder.hpp" -#include "common.hpp" +// #include "common.hpp" #include "minimumConstraints.hpp" #include "rtsSmoothing.hpp" #include "observations.hpp" #include "algebraTrace.hpp" -#include "streamTrace.hpp" #include "linearCombo.hpp" #include "navigation.hpp" #include "acsConfig.hpp" #include "station.hpp" #include "algebra.hpp" -#include "common.hpp" +// #include "common.hpp" #include "debug.hpp" #include "sinex.hpp" +#include "trace.hpp" #include "enums.h" std::random_device randoDev; @@ -32,7 +34,7 @@ void minimumTest( GTime gtime; gtime++; trace << std::endl; - map pointMap; + map pointMap; Vector3d p; pointMap["STN0"] = {+1, 0, 0}; @@ -49,8 +51,9 @@ void minimumTest( // pointMap["STN6"] *= 0.999; - + acsConfig.output_residuals = true; KFState kfStateStations; + kfStateStations.output_residuals = true; map stationMap; @@ -60,8 +63,8 @@ void minimumTest( KFMeasEntryList stationEntries; for (auto& [id, a] : pointMap) { - a *= 5000000 * sqrt(2); - a += Vector3d(0.0000001,0.0000001,0.0000001); + a *= 5000000;// * sqrt(2); +// a += Vector3d(0.0000001,0.0000001,0.0000001); auto& rec = stationMap[id]; rec.id = id; @@ -87,6 +90,7 @@ void minimumTest( 0, +cos(angx), +sin(angx), 0, -sin(angx), +cos(angx); + rec.minconApriori = a; Vector3d p = a; p = rotz * p; p = rotx * p; @@ -95,9 +99,6 @@ void minimumTest( // trace << "\t" << p(0) << "\t" << p(1) << "\t" << p(2) << std::endl; rec.aprioriPos = a; - double ep[6]; - time2epoch(gtime, ep); - epoch2yds(ep, rec.aprioriTime); for (int i = 0; i < 3; i++) { @@ -111,8 +112,8 @@ void minimumTest( meas.addDsgnEntry(kfKey, 1); - double val = p(i) - a(i); - val += stationEntries.size()/1000.0; + double val = p(i); +// val += stationEntries.size()/1000.0; meas.setValue(val); // if (stationEntries.size() < 3) @@ -130,7 +131,7 @@ void minimumTest( dummyMeas.setNoise(100); // dummyMeas.addDsgnEntry({KF::IONOSPHERIC, {}, "1", 3}, 1); // dummyMeas.addDsgnEntry({KF::REC_POS, {}, "2", 2}, 1); - stationEntries.push_back(dummyMeas); +// stationEntries.push_back(dummyMeas); //add process noise to existing states as per their initialisations. @@ -189,14 +190,11 @@ void minimumTest( std::cout << std::endl << "Distance: " << ((point1-point2).norm() - 10000000); } } -// kfStateStations.outputStates(trace); + kfStateStations.outputStates(trace); } #if 0 -#endif - #include "sinex.hpp" -#include "streamTrace.hpp" #if 0 void outputMeas( Trace& trace, ///< Trace to output to @@ -288,12 +286,848 @@ void testOutlierDetection() #endif -#include "rinexNavWrite.hpp" #include "acsConfig.hpp" +#include "mongoWrite.hpp" + +void rtsBump() +{ + KFState kfState; + kfState.rts_basename = "therfe"; + kfState.rts_lag = -1; + + InitialState sinInit; + sinInit.P = 10000; + sinInit.Q = 1; + + InitialState ambInit; + ambInit.P = 10000; + + GTime time; + time += 60; + + for (int i = 0; i < 1000; i++) + { + double amb = 0; + if (i < 10) amb = 10; + else amb = 0; + + double sine = sin(i/100.0); + + double cose = cos(i/100.0); + + KFMeasEntryList kfMeasEntryList; + + KFKey sinKey; + KFKey ambKey; + + sinKey.type = KF::TROP; + ambKey.type = KF::AMBIGUITY; + + { + KFMeasEntry measEntry(&kfState, {0,{},"two"}); + + measEntry.addDsgnEntry(sinKey, 1, sinInit); + measEntry.addDsgnEntry(ambKey, 1, ambInit); + + measEntry.setValue(amb + sine); + measEntry.setNoise(1); + + kfMeasEntryList.push_back(measEntry); + } + if (i > 100) + { + KFMeasEntry measEntry(&kfState, {0,{},"100"}); + + measEntry.addDsgnEntry(sinKey, 1, sinInit); + + measEntry.setValue(sine); + measEntry.setNoise(400); + + kfMeasEntryList.push_back(measEntry); + } + +// if (i > 100) + { + KFMeasEntry measEntry(&kfState, {0,{},"sin"}); + sinKey.num = 1; + measEntry.addDsgnEntry(sinKey, 1, sinInit); + + measEntry.setValue(sine); + measEntry.setNoise(400); + + kfMeasEntryList.push_back(measEntry); + } + + kfState.output_residuals = true; + + kfState.stateTransition(std::cout, time); + + kfState.outputStates(std::cout); + + KFMeas combinedMeas = kfState.combineKFMeasList(kfMeasEntryList, time); + + kfState.filterKalman(std::cout, combinedMeas); + + kfState.outputStates(std::cout); + + if (acsConfig.output_mongo_states) + { + mongoStates(kfState); + } + + time++; + } + + RTS_Process(kfState); +} + +void dualFilters() +{ + vector positions; + + KFState kfState; + kfState.rts_basename = "therfe"; + kfState.rts_lag = -1; + + InitialState posInit; + posInit.P = 100000000; + + InitialState velInit; + velInit.P = 100000000; + velInit.Q = 0.1; + GTime time; + time += 60; + + for (int i = 0; i < 20; i++) + { + double position = 0; + if (i < 10) position = i * 1.0 + 5; + else position = i * 0.3 + 6; + + positions.push_back(position); + + KFMeasEntryList kfMeasEntryList; + + for (int j = 0; j < 3; j++) + { + KFKey posKey; + KFKey velKey; + + posKey.type = KF::REC_POS; + velKey.type = KF::REC_POS_RATE; + + posKey.num = j; + velKey.num = j; + + KFMeasEntry measEntry(&kfState); + + measEntry.addDsgnEntry(posKey, 1, posInit); + + kfState.setKFTransRate(posKey, velKey, 1, velInit); + + if (j == 1 && i >= 10) continue; + if (j == 2 && i < 10) continue; + + measEntry.setValue(position); + measEntry.setNoise(4); + + kfMeasEntryList.push_back(measEntry); + } + + kfState.output_residuals = true; + + kfState.stateTransition(std::cout, time); + + kfState.outputStates(std::cout); + + KFMeas combinedMeas = kfState.combineKFMeasList(kfMeasEntryList, time); + + kfState.filterKalman(std::cout, combinedMeas); + + kfState.outputStates(std::cout); + + if (acsConfig.output_mongo_states) + { + mongoStates(kfState); + } + + time++; + } + + RTS_Process(kfState); +} + + + +#include "streamSerial.hpp" +#include "streamFile.hpp" +#include "streamRtcm.hpp" +#include "streamObs.hpp" +#include "streamUbx.hpp" + +#endif + +#include "mongoWrite.hpp" + + +//#include "orbitProp.hpp" +//extern map orbitPropagatorMap; + +/** Compare the orbital states created by pseudo-linear state transitions with the original values. + * The pseudo-linear state transition in the filter (STM + adjustment) is mathematically equivalent to setting a state value directly, + * but numerical precision in a computer does not allow 100% correspondence - this checks its mostly working +// */ +//void checkOrbits( +// Trace& trace, +// KFState& kfState) +//{ +// +// +// //get current inertial states from the kfState +// for (auto& [kfKey, index] : kfState.kfIndexMap) +// { +// if ( kfKey.type != KF::ORBIT +// ||kfKey.num != 0) +// { +// continue; +// } +// +// auto id = kfKey.str; +// +// auto& orbitPropagator = orbitPropagatorMap[id]; +// +// KFState subState = getOrbitFromState(trace, id, kfState); +// +// Vector6d inertialState; +// inertialState << orbitPropagator.states.pos, orbitPropagator.states.vel; +// +// Vector6d deltaState = inertialState +// - subState.x.head(6); +// +// trace << "\norbitPropagator.base.inertialState" << inertialState .transpose().format(HeavyFmt); +// trace << "\nsubState.x.head(6) " << subState.x.head(6) .transpose().format(HeavyFmt); +// trace << "\ndeltaState " << deltaState .transpose().format(HeavyFmt); +// +// MatrixXd transition = orbitPropagator.states.posVelSTM; +// +// //Convert the absolute transition matrix to an identity matrix (already populated elsewhere) and stm-per-time matrix +// transition -= MatrixXd::Identity(transition.rows(), transition.cols()); +// +// MatrixXd thingy = transition * subState.P * transition.transpose(); +// +// // std::cout << "\ntransition\n" << transition << "\n"; +// // std::cout << "\nthingy\n" << thingy << "\n"; +// // if (0) +// for (auto& [key1, index1] : subState.kfIndexMap) +// for (auto& [key2, index2] : subState.kfIndexMap) +// { +// int index1a = kfState.kfIndexMap[key1]; +// int index2a = kfState.kfIndexMap[key2]; +// +// kfState.P(index1a, index2a) += thingy(index1, index2); +// // kfState.addKFState(key, init); +// } +// } + + +// MatrixXd transition = orbitPropagator.states.posVelSTM; +// +// //Convert the absolute transition matrix to an identity matrix (already populated elsewhere) and stm-per-time matrix +// transition -= MatrixXd::Identity(transition.rows(), transition.cols()); +// transition /= 900; +// +// MatrixXd thingy = transition * subState.P * transition.transpose(); +// +// std::cout << "\ntransition\n" << transition << "\n"; +// std::cout << "\nthingy\n" << thingy << "\n"; +// for (auto& [key1, index1] : subState.kfIndexMap) +// for (auto& [key2, index2] : subState.kfIndexMap) +// { +// int index1a = kfState.kfIndexMap[key1]; +// int index2a = kfState.kfIndexMap[key2]; +// +// kfState.P(index1a, index2a) += thingy(index1, index2); +// // kfState.addKFState(key, init); +// } +// +//} + +// //apply required state based accelerations to the matrices before the state transitions +// if (0) +// for (auto& [accKey, subIndex] : subState.kfIndexMap) +// { +// Vector3d acceleration; +// +// switch (accKey.type) +// { +// default: +// { +// //nothing to be done except for state types specified below +// continue; +// } +// case KF::SRP_SCALE: { acceleration = outputsMap["accSrp"]; break; } //this should be whatever was used in the propagator above, for this srp component only +// } +// +// std::cout << std::endl << "add acceleration: " << acceleration.transpose() << std::endl; +// //add state transition elements for each component +// for (int i = 0; i < 3; i++) +// { +// KFKey posKey = kfKey; +// posKey.num = i; +// +// KFKey velKey = posKey; +// velKey.type = KF::ORBIT; +// velKey.num = i + 3; +// +// kfState .setAccelerator(posKey, velKey, accKey, acceleration(i)); +// subState.setAccelerator(posKey, velKey, accKey, acceleration(i)); +// } +// } + + +void timecheck() +{ + PTime now = timeGet(); + GTime gNow = now; + UtcTime uNow = gNow; + + std::cout << "now: " << now. bigTime << std::endl; + std::cout << "gNow: " << gNow. bigTime << std::endl; + std::cout << "uNow: " << uNow. bigTime << std::endl; +} + +void debugTime() +{ + auto utcNow = boost::posix_time::second_clock::universal_time(); + + PTime pTime = timeGet(); + auto bTime = boost::posix_time::from_time_t((time_t)pTime.bigTime); + GTime gTime = pTime; + + std::cout << std::setprecision(1) << std::fixed; + std::cout << std::endl; + std::cout << "universal_time(): " << utcNow << std::endl; + std::cout << "timeGet(): " << pTime.bigTime << " " << bTime << std::endl; + std::cout << "PTime to GTime: " << gTime.bigTime << " " << gTime.to_string(1) << std::endl; + std::cout << "GTime(timeGet()): " << GTime(timeGet()).to_string(1) << std::endl; + + pTime = gTime; + UtcTime utcTime = gTime; + GEpoch gEpoch = gTime; + UYds uYds = gTime; + + GWeek gWeek = gTime; + GTow gTow = gTime; + + BWeek bWeek = gTime; + BTow bTow = gTime; + + RTod rTod = gTime; + + std::cout << std::endl; + std::cout << "GTime to anything:" << std::endl; + std::cout << "GTime to PTime: " << pTime.bigTime << std::endl; + std::cout << "GTime to UtcTime: " << utcTime.bigTime << std::endl; + std::cout << "GTime to GEpoch: " << (int)gEpoch.year << "-" << (int)gEpoch.month << "-" << (int)gEpoch.day << " " << (int)gEpoch.hour << ":" << (int)gEpoch.min << ":" << gEpoch.sec << std::endl; + std::cout << "GTime to UYds: " << uYds.year << " " << uYds.doy << " " << uYds.sod << std::endl; + std::cout << "GTime to GWeek: " << gWeek.val << std::endl; + std::cout << "GTime to GTow: " << gTow. val << std::endl; + std::cout << "GTime to BWeek: " << bWeek.val << std::endl; + std::cout << "GTime to BTow: " << bTow. val << std::endl; + std::cout << "GTime to RTod: " << rTod. val << std::endl; + + + GTime gTimeU = utcTime; + GTime gTimeE = gEpoch; + GTime gTimeY = uYds; + + std::cout << std::endl; + std::cout << "anything to GTime:" << std::endl; + std::cout << "UtcTime to GTime: " << gTimeU.bigTime << " " << gTimeU.to_string(1) << std::endl; + std::cout << "GEpoch to GTime: " << gTimeE.bigTime << " " << gTimeE.to_string(1) << std::endl; + std::cout << "UYds to GTime: " << gTimeY.bigTime << " " << gTimeY.to_string(1) << std::endl; + + GTime gTimeG = GTime(gWeek, gTow); + GTime gTimeB = GTime(bWeek, bTow); + + std::cout << "GTime(GWeek, GTow): " << gTimeG.bigTime << " " << gTimeG.to_string(1) << std::endl; + std::cout << "GTime(BWeek, BTow): " << gTimeB.bigTime << " " << gTimeB.to_string(1) << std::endl; + + GTime nearTime= timeGet(); + gTimeG = GTime(gTow, nearTime); + gTimeB = GTime(bTow, nearTime); + GTime gTimeR = GTime(rTod, nearTime); + + std::cout << "GTime(GTow, GTime): " << gTimeG.bigTime << " " << gTimeG.to_string(1) << std::endl; + std::cout << "GTime(BTow, GTime): " << gTimeB.bigTime << " " << gTimeB.to_string(1) << std::endl; + std::cout << "GTime(RTod, GTime): " << gTimeR.bigTime << " " << gTimeR.to_string(1) << std::endl; + + + GTow nearGTow= 1; + nearTime= GTime(gWeek, nearGTow); + gTow = 604800 - 1.1; + gTimeG = GTime(gTow, nearTime); + + std::cout << std::endl; + std::cout << "Week/Day roll-over:" << std::endl; + std::cout << "nearGTow: " << nearGTow.val << "\t\tnearTime: " << nearTime.to_string(1) << std::endl; + std::cout << "gTow: " << gTow. val << "\tGTime(gTow, nearTime): " << gTimeG. to_string(1) << std::endl; + + nearGTow= 604800 - 1; + nearTime= GTime(gWeek, nearGTow); + gTow = 1.1; + gTimeG = GTime(gTow, nearTime); + + std::cout << "nearGTow: " << nearGTow.val << "\tnearTime: " << nearTime.to_string(1) << std::endl; + std::cout << "gTow: " << gTow. val << "\t\tGTime(gTow, nearTime): " << gTimeG. to_string(1) << std::endl; + + BTow nearBTow= 1; + nearTime= GTime(bWeek, nearBTow); + bTow = 604800 - 1.1; + gTimeB = GTime(bTow, nearTime); + + std::cout << "nearBTow: " << nearBTow.val << "\t\tnearTime: " << nearTime.to_string(1) << std::endl; + std::cout << "bTow: " << bTow. val << "\tGTime(bTow, nearTime): " << gTimeB. to_string(1) << std::endl; + + nearBTow= 604800 - 1; + nearTime= GTime(bWeek, nearBTow); + bTow = 1.1; + gTimeB = GTime(bTow, nearTime); + + std::cout << "nearBTow: " << nearBTow.val << "\tnearTime: " << nearTime.to_string(1) << std::endl; + std::cout << "bTow: " << bTow. val << "\t\tGTime(bTow, nearTime): " << gTimeB. to_string(1) << std::endl; + + UYds nearYds = uYds; + nearYds.sod = 86400 - 10800 + 1; + nearTime= nearYds; + RTod nearTod = nearTime; + rTod = 86400 - 1.1; + gTimeR = GTime(rTod, nearTime); + + std::cout << "nearSod: " << nearYds. sod << "\t\tnearTime: " << nearTime.to_string(1) << "\tnearTod: " << nearTod. val << std::endl; + std::cout << "rTod: " << rTod. val << "\tGTime(rTod, nearTime): " << gTimeR. to_string(1) << std::endl; + + nearYds.sod = 86400 - 10800 - 1; + nearTime= nearYds; + nearTod = nearTime; + rTod = 1.1; + gTimeR = GTime(rTod, nearTime); + + std::cout << "nearSod: " << nearYds. sod << "\t\tnearTime: " << nearTime.to_string(1) << "\tnearTod: " << nearTod. val << std::endl; + std::cout << "rTod: " << rTod. val << "\tGTime(rTod, nearTime): " << gTimeR. to_string(1) << std::endl; +} + +#include "coordinates.hpp" +#include "iers2010.hpp" + +const GTime j2000TT = GEpoch{2000, E_Month::JAN, 1, 11, 58, 55.816 + GPS_SUB_UTC_2000}; // defined in utc 11:58:55.816 +void rotationTest() +{ + GTime time = GEpoch{2019, E_Month::FEB, 6, 0, 0, 0}; + + Vector3d nowPosI = Vector3d::Zero(); + nowPosI(0) = 20000000; + Vector3d lastPosE = nowPosI; + + MjDateUt1 lastmjDate; + +// change to inherit long double, then require to_double() for conversions, deny otherwise. + + //do a day's worth of 20 second increment tests + for (; time < GEpoch{2019, E_Month::FEB, 9, 0, 0, 0}; time += 10) + { + Matrix3d i2tMatrix = Matrix3d::Identity(); + + //convert to terrestrial + ERPValues erpv = geterp(nav.erp, time); + eci2ecef(time, erpv, i2tMatrix); + + MjDateUt1 mjDate (time, erpv.ut1Utc); + + Vector3d rSatEcef = i2tMatrix * nowPosI; + Vector3d deltaP = rSatEcef - lastPosE; + + long double deltamjdtt = mjDate.val - lastmjDate.val; + + printf("\n%s - {%15.6f} [%20.32e %30.23e %30.23e] %30.23e", + time.to_string().c_str(), + rSatEcef.dot(deltaP), + (double)mjDate.val, + (double)deltamjdtt, + (double)(mjDate.val), + rSatEcef.dot(lastPosE) + ); + + lastPosE = rSatEcef; + +// std::cout << rSatEcef.dot(lastPosE); + lastmjDate = mjDate; + } +} + +void longDoubleTest() +{ + long double a; + std::cout << std::endl << "This system uses " << sizeof(a) * 8 << " bits for long doubles. (Hopefully that number is 128...)" << std::endl; +} + +#include "ssr.hpp" + +void debugSSR(GTime time, E_Sys sys) +{ + int iodPos; + int iodEph; + int iodClk; + GTime ephValidStart; + GTime ephValidStop; + GTime clkValidStart; + GTime clkValidStop; + Vector3d dPos[2]; + double dClk[2] = {}; + GTime ephTime = time; + + for (auto& Sat : getSysSats(sys)) + { + GObs obs; + obs.Sat = Sat; + obs.satNav_ptr = &nav.satNavMap[Sat]; + + dPos[0] = Vector3d::Zero(); + dPos[1] = Vector3d::Zero(); + + bool posDeltaPass = ssrPosDelta(time, ephTime, obs, obs.satNav_ptr->transmittedSSR, dPos[0], iodPos, iodEph, ephValidStart, ephValidStop); + bool clkDeltaPass = ssrClkDelta(time, ephTime, obs, obs.satNav_ptr->transmittedSSR, dClk[0], iodClk, clkValidStart, clkValidStop); + posDeltaPass = ssrPosDelta(time, ephTime, obs, obs.satNav_ptr->receivedSSR, dPos[1], iodPos, iodEph, ephValidStart, ephValidStop); + clkDeltaPass = ssrClkDelta(time, ephTime, obs, obs.satNav_ptr->receivedSSR, dClk[1], iodClk, clkValidStart, clkValidStop); + + if (posDeltaPass && clkDeltaPass) + { + std::cout << "Debugging ssr: " << time.to_string(1) << "\t" << Sat.id() << std::setprecision(4) << std::fixed + << "\t" << std::setw(7) << (dPos[0] - dPos[1]).transpose() << "\t" << std::setw(7) << dPos[0].transpose() << "\t" << std::setw(7) << dPos[1].transpose() + << "\t" << std::setw(8) << (dClk[0] - dClk[1]) << "\t" << std::setw(8) << dClk[0] << "\t" << std::setw(8) << dClk[1] << std::endl; + } + } +} + +void reflector() +{ + Vector3d face[3]; + for (int i = 0; i < 3; i++) + { + face[i] = Vector3d::Zero(); + face[i](i) = 1; + } + + double absorbtion [3] = {}; + double specularity [3] = {}; + + absorbtion [0] = 1; + specularity [1] = 1; +// specularity [2] = 0; + + for (int x : {0, 1}) + for (int y : {0, 1}) + for (int z : {0, 1}) + { + Vector3d source; + source(0) = x; + source(1) = y; + source(2) = z; + + source.normalize(); + + Vector3d totalMomentum = Vector3d::Zero(); + + double totalFrontalarea = 0; + + for (int i = 0; i < 3; i++) + { + Vector3d correctFace = face[i]; + + if (correctFace.dot(source) < 0) + { + correctFace *= -1; + } + + double frontalArea = 1 * source.dot(face[i]); + totalFrontalarea += frontalArea; + + Vector3d incoming = frontalArea * source; + Vector3d reflected = -frontalArea * (source - 2 * (source.dot(correctFace)) * correctFace) * specularity[i]; + Vector3d emissive = frontalArea * correctFace * (1-specularity[i]) * 0.7; + + Vector3d outgoing = (1 - absorbtion[i]) * (reflected + emissive); + + Vector3d momentum = (incoming + outgoing); + + +// std::cout << incoming.transpose() << std::endl; +// std::cout << reflected.transpose() << std::endl; +// std::cout << emissive.transpose() << std::endl; + totalMomentum += momentum; + } + totalMomentum /= totalFrontalarea; + printf("%10.4f %10.4f %10.4f -> %10.4f %10.4f %10.4f \n", source(0), source(1), source(2), totalMomentum(0), totalMomentum(1), totalMomentum(2)); + } +} + +void light() +{ + double v = 0; + + double c = 1; + + double t1 = -4; + double t2 = -t1; + + double tof = t2-t1/2; + + for (int rec = 1; rec < 10; rec++) + { + std::cout << "\n\nrec = " << rec; + for (int i = 0; i < 10; i++) + { + double t = t2-tof; + + double x = v * t; + + double r = fabs(rec - x); + + tof = r / c; + + std::cout << "\nt = " << t << " x = " << x << " r = " << r << " tof = " << tof; + } + } +} + +// void Spawn() +// { +// int pid = fork(); +// +// std::cout << pid << std::endl; +// if (pid) +// { +// return; +// std::cout << "returning\n"; +// } +// while (pid < 10000) +// std::cout << pid++ << std::endl; +// +// } + +#include "streamParser.hpp" +#include "streamFile.hpp" +#include "rinex.hpp" +#include "coordinates.hpp" +#include "erp.hpp" + +#include "geomagField.hpp" + +void debugIGRF() +{ + std::cout << "\nDebugging IGRF:" << std::endl; + + // // test 1 - file reading + // std::cout << " n m g h" << std::endl; + // for (auto& [year, igrfMF] : igrfMFMap) + // { + // std::cout << igrfMF.year << ":" << std::endl; + // for (int i = 0; i <= igrfMF.maxDegree; i++) + // for (int j = 0; j <= i; j++) + // { + // std::cout << std::setprecision(2) << std::fixed; + // std::cout << " " << std::setw(2) << i + // << " " << std::setw(2) << j + // << " " << std::setw(9) << igrfMF.gnm(i, j) + // << " " << std::setw(9) << igrfMF.hnm(i, j) + // << std::endl; + // } + // } + + // { + // std::cout << igrfSV.year << "-" << igrfSV.yearEnd << ":" << std::endl; + // for (int i = 0; i <= igrfSV.maxDegree; i++) + // for (int j = 0; j <= i; j++) + // { + // std::cout << std::setprecision(2) << std::fixed; + // std::cout << " " << std::setw(2) << i + // << " " << std::setw(2) << j + // << " " << std::setw(9) << igrfSV.gnm(i, j) + // << " " << std::setw(9) << igrfSV.hnm(i, j) + // << std::endl; + // } + // } + + // // test 2 - get coefficients + // { + // std::cout << " "; + // for (int i = 0; i <= 13; i++) + // for (int j = 0; j <= i; j++) + // { + // std::cout << " g " << std::setw(2) << i << "," << std::setw(2) << j + // << " h " << std::setw(2) << i << "," << std::setw(2) << j; + // } + // std::cout << std::endl; + // } + + // for (int year = 1981; year <= 2026; year++) + // { + // GEpoch ep = {year, 1, 1, 0, 0, 0.0}; + // GTime time = ep; + + // GeomagMainField igrfMF; + // bool pass = getSHCoef(time, igrfMF); + + // if (!pass) + // return; + + // std::cout << time.to_string() << ":"; + // for (int i = 0; i <= igrfMF.maxDegree; i++) + // for (int j = 0; j <= i; j++) + // { + // std::cout << std::setprecision(2) << std::fixed; + // std::cout << " " << std::setw(9) << igrfMF.gnm(i, j) + // << " " << std::setw(9) << igrfMF.hnm(i, j); + // } + // std::cout << std::endl; + // } + + // test 3.1 - time series + { + Vector3d r = {-4.05205271694605e+06, 4.21283598092691e+06, -2.54510460797403e+06}; // Cartesian - ALIC + VectorPos pos = ecef2pos(r); + pos[0] = asin(r.z()/r.norm()); + pos[1] = atan2(r.y(), r.x()); + pos[2] = r.norm(); + + std::cout << std::setprecision(5) << std::fixed; + std::cout << "\n\tGeocentric pos: " << pos[0]*R2D << " " << pos[1]*R2D << " " << pos[2]/1000 << std::endl; + + for (int year = 1981; year <= 2023; year++) + { + GEpoch ep = {year, 1, 1, 0, 0, 0.0}; + GTime time = ep; + + Vector3d intensity = getGeomagIntensity(time, pos); + + std::cout << std::setprecision(5) << std::fixed; + std::cout << "\tyear: " << ep.year; + std::cout << std::setprecision(1) << std::fixed; + std::cout << "\tX: " << std::setw(8) << intensity.x() + << "\tY: " << std::setw(8) << intensity.y() + << "\tZ: " << std::setw(8) << intensity.z() + << std::endl; + } + } + + // test 3.2 - grid (including singularity) + { + GEpoch ep = {2019, 7, 18, 0, 0, 0.0}; + GTime time = ep; + double year = decimalYear(time); + + std::cout << std::setprecision(5) << std::fixed; + std::cout << "\n\tyear: " << year << std::endl; + + for (int lat = -90; lat <= 90; lat += 10) + for (int lon = -180; lon <= 180; lon += 20) + { + VectorPos pos = Vector3d(lat*D2R, lon*D2R, 6371000); + + Vector3d intensity = getGeomagIntensity(time, pos); + + std::cout << std::setprecision(1) << std::fixed; + std::cout << "\tGeocentric pos: " << std::setw(5) << pos[0]*R2D << " " << std::setw(6) << pos[1]*R2D << " " << std::setw(4) << pos[2]/1000; + std::cout << std::setprecision(1) << std::fixed; + std::cout << "\tX: " << std::setw(8) << intensity.x() + << "\tY: " << std::setw(8) << intensity.y() + << "\tZ: " << std::setw(8) << intensity.z() + << std::endl; + } + } +} + +#include "attitude.hpp" +#include "planets.hpp" + +void debugAttitude() +{ + // // GPS + // SatSys Sat(E_Sys::GPS, 1); + // GEpoch ep = {2019, 07, 18, 0, 0, 0}; + // int nEpoch = 288; + // double interval = 300; + + // // GRACE C + // SatSys Sat(E_Sys::LEO, 65); + // // GEpoch ep = {2019, 02, 13, 0, 0, 0}; + // GEpoch ep = {2022, 01, 01, 0, 0, 0}; + // int nEpoch = 8640; + // double interval = 10; + + // // GRACE D + // SatSys Sat(E_Sys::LEO, 65); + // GEpoch ep = {2022, 01, 01, 0, 0, 0}; + // int nEpoch = 8640; + // double interval = 10; + + // // COSMIC2 - 1 + // SatSys Sat(E_Sys::LEO, 80); + // GEpoch ep = {2022, 12, 31, 23, 39, 43}; + // int nEpoch = 2261; + // double interval = 1; + + // SPIRE + SatSys Sat(E_Sys::LEO, 99); + GEpoch ep = {2023, 01, 01, 9, 59, 46}; + int nEpoch = 5853; + double interval = 1; + + GObs obs; + obs.Sat = Sat; + obs.time = ep; + + Station rec; + rec.id = Sat.id(); + + auto& satOpts = acsConfig.getSatOpts(Sat); + auto& recOpts = acsConfig.getRecOpts(rec.id); + + AttStatus attStatus = {}; + VectorEcef rSun; + VectorEcef eSun; + + printf("\n"); + for (int i=0; i using std::isnan; + +#include +#define EIGEN_DENSEBASE_PLUGIN "EigenDenseBaseAddons.h" + + #include #include #include @@ -15,6 +19,7 @@ using std::isnan; #include #include #include + using Eigen::SimplicialLLT; using Eigen::SimplicialLDLT; using Eigen::COLAMDOrdering; @@ -26,8 +31,9 @@ using Eigen::MatrixXd; using Eigen::Matrix2d; using Eigen::Matrix3d; using Eigen::VectorXd; -using Vector6d = Eigen::Vector; -using Matrix6d = Eigen::Matrix; +using Array6d = Eigen::Array; +using Vector6d = Eigen::Vector; +using Matrix6d = Eigen::Matrix; using Eigen::Vector3d; using Eigen::Vector2d; using Eigen::MatrixXi; @@ -39,9 +45,133 @@ using Eigen::Quaterniond; using Eigen::Triplet; using Eigen::ArrayXd; using Eigen::placeholders::all; + typedef Eigen::Array ArrayXb; template using Vector = Matrix; -#endif + +struct Vector3dInit : Vector3d +{ + Vector3dInit() + { + Vector3d::setZero(); + } + + Vector3dInit& operator=(const Vector3d in) + { + Vector3d::operator=(in); + + return *this; + } +}; + +struct VectorEnu : Vector3d +{ + VectorEnu() + { + Vector3d::setZero(); + } + + VectorEnu(const Vector3d& in) + { + Vector3d::operator=(in); + } + + VectorEnu& operator=(const Vector3d in) + { + Vector3d::operator=(in); + + return *this; + } + + double& e() { return x(); } + double& n() { return y(); } + double& u() { return z(); } + + double& r() { return x(); } + double& f() { return y(); } +}; + +struct VectorEcef : Vector3d +{ + VectorEcef() + { + Vector3d::setZero(); + } + + VectorEcef(const Vector3d& in) + { + Vector3d::operator=(in); + } + + VectorEcef& operator=(const Vector3d& in) + { + Vector3d::operator=(in); + + return *this; + } + + VectorEcef operator*(const double rhs) { return Vector3d(((Vector3d)*this) * ( rhs)); } + VectorEcef operator-(const VectorEcef& rhs) { return Vector3d(((Vector3d)*this) - ((Vector3d) rhs)); } + VectorEcef operator+(const VectorEcef& rhs) { return Vector3d(((Vector3d)*this) + ((Vector3d) rhs)); } +}; + +struct VectorEci : Vector3d +{ + VectorEci() + { + Vector3d::setZero(); + } + + VectorEci(const Vector3d& in) + { + Vector3d::operator=(in); + } + + VectorEci& operator=(const Vector3d& in) + { + Vector3d::operator=(in); + + return *this; + } + + VectorEci operator*(const double rhs) { return Vector3d(((Vector3d)*this) * ( rhs)); } + VectorEci operator-(const VectorEci& rhs) { return Vector3d(((Vector3d)*this) - ((Vector3d) rhs)); } + VectorEci operator+(const VectorEci& rhs) { return Vector3d(((Vector3d)*this) + ((Vector3d) rhs)); } +}; + +struct VectorPos : Vector3d +{ + VectorPos() + { + Vector3d::setZero(); + } + + VectorPos(const Vector3d& in) + { + Vector3d::operator=(in); + } + + VectorPos& operator=(const Vector3d& in) + { + Vector3d::operator=(in); + + return *this; + } + + double& lat() { return x(); } + double& lon() { return y(); } + double& hgt() { return z(); } + + const double& lat() const { return x(); } + const double& lon() const { return y(); } + const double& hgt() const { return z(); } + + double latDeg() const; + double lonDeg() const; +}; + +const Eigen::IOFormat HeavyFmt(Eigen::FullPrecision, 0, ", ", ",\n", "[", "]", "[", "]"); + diff --git a/src/cpp/common/enums.h b/src/cpp/common/enums.h index f22854493..e8f56327b 100644 --- a/src/cpp/common/enums.h +++ b/src/cpp/common/enums.h @@ -1,45 +1,39 @@ -#ifndef __ENUMS_H__ -#define __ENUMS_H__ +#pragma once #define BETTER_ENUMS_DEFAULT_CONSTRUCTOR(Enum) \ public: \ Enum() = default; +#define BETTER_ENUMS_MACRO_FILE "enum_macros.h" //BETTER_ENUM Extended #include "enum.h" //BETTER_ENUM typedef enum { FTYPE_NONE, - F1 = 1, L1 = F1, - F2 = 2, L2 = F2, - F5 = 5, L5 = F5, + /* Base carrier frequencies */ + F1 = 1, // 1575.42 MHz: GPS L1, GAL E1, BDS B1, QZS L1, SBS L1, + F2 = 2, // 1227.60 MHz: GPS L2, QZS L2, + F5 = 5, // 1176.45 MHz: GPS L5, GAL E5A, BDS B2A, QZS L5, SBS L5 + F6 = 6, // 1278.75 MHz: GAL E6, QZS L6, + F7 = 7, // 1207.14 MHz: GAL E5B, BDS B2B + F8 = 8, // 1191.795 MHz: GAL E5, BDS B2, + G1 = 11, // ~1602 MHz: GLO G1, + G2 = 12, // ~1246 MHz: GLO G2, + G3 = 13, // 1202.025 MHz: GLO G3, + G4 = 14, // 1600.995 MHz GLO G1A + G6 = 16, // 1248.08 MHz: GLO G2A, + B1 = 21, // 1561.098 MHz: BDS B2-1, + B3 = 23, // 1268.52 MHz: BDS B3 + I9 = 39, // 2492.028 MHz: IRN S9 NUM_FTYPES, - F6 = 6, - F8 = 8, - F3 = 3, - F4 = 4, - F7 = 7, - - FTYPE_IF12 = 12, - FTYPE_IF15 = 15, - FTYPE_IF25 = 25, - - G1 = 101, - G2, - E1 = F1, - E2, - E5A = F5, - E5B = F7, - E5AB = F8, - E6 = F6, - LEX = F6, - B1, - B2, - B3 + /* Combined signals */ + FTYPE_IF12 = 102, + FTYPE_IF15 = 105, + FTYPE_IF25 = 205 } E_FType; typedef enum @@ -52,21 +46,35 @@ typedef enum typedef enum { SVH_OK, - SVH_UNHEALTHY = -1 + SVH_UNHEALTHY = -1 //implicitly used in rtcm } E_Svh; +BETTER_ENUM(E_Solution, short int, + NONE, + SINGLE, + SINGLE_X, + PPP +) + +BETTER_ENUM(E_Radio, short int, + TRANSMITTER, + RECEIVER +) + + BETTER_ENUM(E_Sys, short int, NONE, GPS, GAL, GLO, - SUPPORTED, - SBS, QZS, + SBS, BDS, LEO, + SUPPORTED, IRN, + IMS, COMB) @@ -76,29 +84,35 @@ BETTER_ENUM(E_DCBPair, short int, P1_C1, P2_C2) -BETTER_ENUM(E_BiasGroup, short int, - GPS, - GLO, - GAL, - BDS, - NUM) - BETTER_ENUM(E_OffsetType, short int, UNSPECIFIED, APC, COM) +BETTER_ENUM(E_TrigType, short int, + CONSTANT, + COS, + SIN) + + BETTER_ENUM(KF, short int, NONE, ONE, REC_POS, REC_POS_RATE, + STRAIN_RATE, + + POS, + VEL, + ACC, + + HEADING, SAT_POS, SAT_POS_RATE, - SAT_MOMENTUM, + REF_SYS_BIAS, @@ -111,13 +125,11 @@ BETTER_ENUM(KF, short int, SAT_CLOCK_RATE_GM, TROP, - TROP_GM, + TROP_GRAD, ORBIT_PTS, SRP, - ORBIT, - IONOSPHERIC, IONO_STEC, @@ -126,17 +138,45 @@ BETTER_ENUM(KF, short int, EOP, EOP_RATE, + EOP_ADJUST, + EOP_RATE_ADJUST, CALC, + SLR_REC_RANGE_BIAS, + SLR_REC_TIME_BIAS, + XFORM_XLATE, XFORM_RTATE, XFORM_SCALE, AMBIGUITY, + CODE_BIAS, PHASE_BIAS, - CODE_BIAS + + Z_AMB, + WL_MEAS, + WL_PIV, + + CODE_MEAS, + PHAS_MEAS, + + REFERENCE, + + ORBIT, FIRST_ORBIT_STATE = ORBIT, + EMP_DYB_0, + EMP_DYB_1C, + EMP_DYB_1S, + EMP_DYB_2C, + EMP_DYB_2S, + EMP_DYB_3C, + EMP_DYB_3S, + EMP_DYB_4C, + EMP_DYB_4S, LAST_ORBIT_STATE = EMP_DYB_4S, + + RANGE + ) @@ -146,10 +186,13 @@ BETTER_ENUM(KEPLER, short int, LZ, EU, EV, - M, - NUM + M ) +BETTER_ENUM(E_Relativity, short int, + OFF, + ON) + BETTER_ENUM(E_ChiSqMode, int, NONE, INNOVATION, @@ -174,20 +217,31 @@ BETTER_ENUM(E_IonoModel, int, MEAS_OUT, BSPLINE, SPHERICAL_CAPS, - SPHERICAL_HARMONICS) + SPHERICAL_HARMONICS, + LOCAL) BETTER_ENUM(E_IonoMode, int, - OFF, /* ionosphere option: correction off */ - BROADCAST, /* ionosphere option: broadcast model */ - SBAS, /* ionosphere option: SBAS model */ - IONO_FREE_LINEAR_COMBO, /* ionosphere option: L1/L2 or L1/L5 iono-free LC */ - ESTIMATE, /* ionosphere option: estimation */ - TOTAL_ELECTRON_CONTENT, /* ionosphere option: IONEX TEC model */ - QZS, /* ionosphere option: QZSS broadcast model */ - LEX, /* ionosphere option: QZSS LEX ionospehre */ - STEC) /* ionosphere option: SLANT TEC model */ - -BETTER_ENUM(E_LinearCombo, int, + OFF, ///< ionosphere option: correction off + BROADCAST, ///< ionosphere option: broadcast model + SBAS, ///< ionosphere option: SBAS model + IONO_FREE_LINEAR_COMBO, ///< ionosphere option: L1/L2 or L1/L5 iono-free LC + ESTIMATE, ///< ionosphere option: estimation + TOTAL_ELECTRON_CONTENT, ///< ionosphere option: IONEX TEC model + QZS, ///< ionosphere option: QZSS broadcast model + LEX, ///< ionosphere option: QZSS LEX ionospehre + STEC) ///< ionosphere option: SLANT TEC model + +BETTER_ENUM(E_IonoMapFn, int, + SLM, ///< single layer model mapping function + MSLM, ///< modified single layer model mapping function + MLM, ///< multiple layer model mapping function + KLOBUCHAR) ///< Klobuchar mapping function + +BETTER_ENUM(E_IonoFrame, int, + EARTH_FIXED, ///< Earth-fixed reference frame + SUN_FIXED) ///< Sun-fixed reference frame + +BETTER_ENUM(E_LinearCombo, int, //todo aaron, remove this and use code priorities only ANY, L1L2_ONLY, L1L5_ONLY) @@ -208,142 +262,149 @@ BETTER_ENUM(E_Period, int, SQRT_SECOND = SECOND, SQRT_MINUTE = MINUTE, SQRT_HOUR = HOUR, SQRT_DAY = DAY, SQRT_WEEK = WEEK, SQRT_YEAR = YEAR, SQRT_SECONDS = SECOND, SQRT_MINUTES = MINUTE, SQRT_HOURS = HOUR, SQRT_DAYS = DAY, SQRT_WEEKS = WEEK, SQRT_YEARS = YEAR) +BETTER_ENUM(E_TimeSys, int, + NONE, ///< NONE for unknown + GPST, ///< GPS Time + GLONASST, ///< GLONASS Time + GST, ///< Galileo System Time + BDT, ///< BeiDou Time + QZSST, ///< QZSS Time + TAI, ///< International Atomic Time + UTC, ///< Universal Coordinated Time + UT1, ///< Universal Time corrected for polar motion + TT) ///< Terrestrial Time + BETTER_ENUM(E_PosFrame, int, NONE, XYZ, NED, RTN) +BETTER_ENUM(E_ObxFrame, short int, + OTHER, + ECEF, + ECI, + BCRS) + BETTER_ENUM(E_FilterMode, int, LSQ, KALMAN) BETTER_ENUM(E_Inverter, int, + NONE, + INV, LLT, LDLT, - INV) + COLPIVHQR, + BDCSVD, + JACOBISVD, + FULLPIVLU, FIRST_UNSUPPORTED = FULLPIVLU, + FULLPIVHQR) BETTER_ENUM(E_ObsDesc, int, - C, // Code / Pseudorange - L, // Phase - D, // Doppler - S, // Raw signal strength (carrier to noise ratio) - X // Receiver channel numbers + C, // Code / Pseudorange + L, // Phase + D, // Doppler + S, // Raw signal strength (carrier to noise ratio) + X // Receiver channel numbers ) BETTER_ENUM(E_ObsCode, int, - NONE = 0 , /* none or unknown */ - L1C = 1 , /* L1C/A,G1C/A,E1C (GPS,GLO,GAL,QZS,SBS) */ - L1P = 2 , /* L1P,G1P (GPS,GLO) */ - L1W = 3 , /* L1 Z-track (GPS) */ - L1Y = 4 , /* L1Y (GPS) */ - L1M = 5 , /* L1M (GPS) */ - L1N = 6 , /* L1codeless (GPS) */ - L1S = 7 , /* L1C(D) (GPS,QZS) */ - L1L = 8 , /* L1C(P) (GPS,QZS) */ - L1E = 9 , /* L1C/B (QZS) */ - L1A = 10, /* E1A (GAL) */ - L1B = 11, /* E1B (GAL) */ - L1X = 12, /* E1B+C,L1C(D+P) (GAL,QZS) */ - L1Z = 13, /* E1A+B+C,L1-SAIF (GAL,QZS) */ - L2C = 14, /* L2C/A,G1C/A (GPS,GLO) */ - L2D = 15, /* L2 L1C/A-(P2-P1) (GPS) */ - L2S = 16, /* L2C(M) (GPS,QZS) */ - L2L = 17, /* L2C(L) (GPS,QZS) */ - L2X = 18, /* L2C(M+L),B1I+Q (GPS,QZS,CMP) */ - L2P = 19, /* L2P,G2P (GPS,GLO) */ - L2W = 20, /* L2 Z-track (GPS) */ - L2Y = 21, /* L2Y (GPS) */ - L2M = 22, /* L2M (GPS) */ - L2N = 23, /* L2codeless (GPS) */ - L5I = 24, /* L5/E5aI (GPS,GAL,QZS,SBS) */ - L5Q = 25, /* L5/E5aQ (GPS,GAL,QZS,SBS) */ - L5X = 26, /* L5/E5aI+Q (GPS,GAL,QZS,SBS) */ - L7I = 27, /* E5bI,B2I (GAL,CMP) */ - L7Q = 28, /* E5bQ,B2Q (GAL,CMP) */ - L7X = 29, /* E5bI+Q,B2I+Q (GAL,CMP) */ - L6A = 30, /* E6A (GAL) */ - L6B = 31, /* E6B (GAL) */ - L6C = 32, /* E6C (GAL) */ - L6X = 33, /* E6B+C,LEXS+L,B3I+Q (GAL,QZS,CMP) */ - L6Z = 34, /* E6A+B+C (GAL) */ - L6S = 35, /* LEXS (QZS) */ - L6L = 36, /* LEXL (QZS) */ - L8I = 37, /* E5(a+b)I (GAL) */ - L8Q = 38, /* E5(a+b)Q (GAL) */ - L8X = 39, /* E5(a+b)I+Q (GAL) */ - L2I = 40, /* B1I (CMP) */ - L2Q = 41, /* B1Q (CMP) */ - L6I = 42, /* B3I (CMP) */ - L6Q = 43, /* B3Q (CMP) */ - L3I = 44, /* G3I (GLO) */ - L3Q = 45, /* G3Q (GLO) */ - L3X = 46, /* G3I+Q (GLO) */ - L1I = 47, /* B1I (BDS) */ - L1Q = 48, /* B1Q (BDS) */ - MAXCODE = 48, - NUM_CODES + NONE = 0 , ///< none or unknown + L1C = 1 , ///< L1C/A,G1C/A,E1C (GPS,GLO,GAL,QZS,SBS) + L1P = 2 , ///< L1P,G1P (GPS,GLO) + L1W = 3 , ///< L1 Z-track (GPS) + L1Y = 4 , ///< L1Y (GPS) + L1M = 5 , ///< L1M (GPS) + L1N = 6 , ///< L1codeless (GPS) + L1S = 7 , ///< L1C(D) (GPS,QZS) + L1L = 8 , ///< L1C(P) (GPS,QZS) + L1E = 9 , ///< L1C/B (QZS) + L1A = 10, ///< E1A (GAL) + L1B = 11, ///< E1B (GAL) + L1X = 12, ///< E1B+C,L1C(D+P) (GAL,QZS) + L1Z = 13, ///< E1A+B+C,L1-SAIF (GAL,QZS) + L2C = 14, ///< L2C/A,G1C/A (GPS,GLO) + L2D = 15, ///< L2 L1C/A-(P2-P1) (GPS) + L2S = 16, ///< L2C(M) (GPS,QZS) + L2L = 17, ///< L2C(L) (GPS,QZS) + L2X = 18, ///< L2C(M+L),B1-2I+Q (GPS,QZS,BDS) + L2P = 19, ///< L2P,G2P (GPS,GLO) + L2W = 20, ///< L2 Z-track (GPS) + L2Y = 21, ///< L2Y (GPS) + L2M = 22, ///< L2M (GPS) + L2N = 23, ///< L2codeless (GPS) + L5I = 24, ///< L5/E5aI (GPS,GAL,QZS,SBS) + L5Q = 25, ///< L5/E5aQ (GPS,GAL,QZS,SBS) + L5X = 26, ///< L5/E5aI+Q (GPS,GAL,QZS,SBS) + L7I = 27, ///< E5bI,B2aI (GAL,BDS) + L7Q = 28, ///< E5bQ,B2aQ (GAL,BDS) + L7X = 29, ///< E5bI+Q,B2aI+Q (GAL,BDS) + L6A = 30, ///< E6A (GAL) + L6B = 31, ///< E6B (GAL) + L6C = 32, ///< E6C (GAL) + L6X = 33, ///< E6B+C,LEXS+L,B3I+Q (GAL,QZS,BDS) + L6Z = 34, ///< E6A+B+C (GAL) + L6S = 35, ///< L6S (QZS) + L6L = 36, ///< L6L (QZS) + L8I = 37, ///< E5(a+b)I (GAL) + L8Q = 38, ///< E5(a+b)Q (GAL) + L8X = 39, ///< E5(a+b)I+Q (GAL) + L2I = 40, ///< B1-2I (BDS) + L2Q = 41, ///< B1-2Q (BDS) + L6I = 42, ///< B3I (BDS) + L6Q = 43, ///< B3Q (BDS) + L3I = 44, ///< G3I (GLO) + L3Q = 45, ///< G3Q (GLO) + L3X = 46, ///< G3I+Q (GLO) + L1I = 47, ///< B1I (BDS) + L1Q = 48, ///< B1Q (BDS) + L4A = 49, ///< L1OCd (GLO) + L4B = 50, ///< L1OCp (GLO) + L4X = 51, ///< L1OCd+L1OCp (GLO) + L6E = 52, ///< L6E (QZS) + L1D = 53, ///< B1D (BDS) + L5D = 54, ///< B2aD (BDS) + L5P = 55, ///< B2aP (BDS) + L9A = 57, ///< S9 A SPS (IRN) + L9B = 58, ///< S9 B RS(D) (IRN) + L9C = 59, ///< S9 C RS(P) (IRN) + L9X = 60, ///< S9 B+C (IRN) + L5A = 61, ///< L5 A SPS (IRN) + L5B = 62, ///< L5 B RS(D) (IRN) + L5C = 63, ///< L5 C RS(P) (IRN) + L5Z = 64, ///< L5 B+C (IRN) + L6D = 65, ///< L6 Data (BDS) + L6P = 66, ///< L6 Pilot (BDS) + L7D = 67, ///< L7 Data (BDS) + L7P = 68, ///< L7 Pilot (BDS) + L7Z = 69, ///< L7 Data+Pilot (BDS) + L8D = 70, ///< L8 Data (BDS) + L8P = 71, ///< L8 Pilot (BDS) + L8Z = 72 ///< L8 Data+Pilot (BDS) ) - -BETTER_ENUM(E_Estimate, int, - STAX, - STAY, - STAZ, - VELX, - VELY, - VELZ, - XGC, - YGC, - ZGC, - RS_RAR, - RS_DER, - RS_RA, - RS_DE, - RS_PL, - LOD, - UT, - XPOR, - YPOR, - XPO, - YPO, - NUT_LN, - NUT_OB, - NUTRLN, - NUTROB, - NUT_X, - NUT_Y, - NUTR_X, - NUTR_Y, - SAT__X, - SAT__Y, - SAT__Z, - SAT_VX, - SAT_VY, - SAT_VZ, - SAT_RP, - SAT_GX, - SAT_GZ, - SATYBI, - TROTOT, - TRODRY, - TROWET, - TGNTOT, - TGNDRY, - TGNWET, - TGETOT, - TGEDRY, - TGEWET, - RBIAS, - TBIAS, - SBIAS, - ZBIAS, - AXI_OF, - SATA_X, - SATA_Y, - SATA_Z, - CN, - SN) +BETTER_ENUM(E_ObsCode2, int, + NONE, + P1, + P2, + C1, + C2, + C3, + C4, + C5, + C6, + C7, + C8, + L1, + L2, + L3, + L4, + L5, + L6, + L7, + L8 +) BETTER_ENUM(E_ARmode, short int, OFF, @@ -365,33 +426,31 @@ BETTER_ENUM(E_AmbTyp, short int, UCL3) BETTER_ENUM(E_NavRecType, short int, - NONE, /* NONE for unknown */ - EPH, /* Ephemerides data including orbit, clock, biases, accuracy and status parameters */ - STO, /* System Time and UTC proxy offset parameters */ - EOP, /* Earth Orientation Parameters */ - ION) /* Global/Regional ionospheric model parameters */ + NONE, ///< NONE for unknown */ + EPH, ///< Ephemerides data including orbit, clock, biases, accuracy and status parameters */ + STO, ///< System Time and UTC proxy offset parameters */ + EOP, ///< Earth Orientation Parameters */ + ION) ///< Global/Regional ionospheric model parameters */ BETTER_ENUM(E_NavMsgType, short int, - NONE, /* NONE for unknown */ - LNAV, /* GPS/QZSS/NavIC Legacy Navigation Messages */ - FDMA, /* GLONASS Legacy FDMA Navigation Message */ - FNAV, /* Galileo Free Navigation Message */ - INAV, /* Galileo Integrity Navigation Message */ - IFNV, /* Galileo INAV or FNAV Navigation Message */ - D1, /* BeiDou-2/3 MEO/IGSO Navigation Message */ - D2, /* BeiDou-2/3 GEO Navigation Message */ - D1D2, /* BeiDou-2/3 MEO/IGSO and GEO Navigation Message */ - SBAS, /* SBAS Navigation Message */ - CNAV, /* GPS/QZSS CNAV Navigation Message */ - CNV1, /* BeiDou-3 CNAV-1 Navigation Message */ - CNV2, /* GPS/QZSS CNAV-2 Navigation Message - BeiDou-3 CNAV-2 Navigation Message */ - CNV3, /* BeiDou-3 CNAV-3 Navigation Message */ - CNVX) /* GPS/QZSS CNAV or CNAV-2 Navigation Message - BeiDou-3 CNAV-1, CNAV-2 or CNAV-3 Navigation Message */ + NONE, ///< NONE for unknown + LNAV, ///< GPS/QZSS/NavIC Legacy Navigation Messages + FDMA, ///< GLONASS Legacy FDMA Navigation Message + FNAV, ///< Galileo Free Navigation Message + INAV, ///< Galileo Integrity Navigation Message + IFNV, ///< Galileo INAV or FNAV Navigation Message + D1, ///< BeiDou-2/3 MEO/IGSO Navigation Message + D2, ///< BeiDou-2/3 GEO Navigation Message + D1D2, ///< BeiDou-2/3 MEO/IGSO and GEO Navigation Message + SBAS, ///< SBAS Navigation Message + CNAV, ///< GPS/QZSS CNAV Navigation Message + CNV1, ///< BeiDou-3 CNAV-1 Navigation Message + CNV2, ///< GPS/QZSS CNAV-2 Navigation Message BeiDou-3 CNAV-2 Navigation Message + CNV3, ///< BeiDou-3 CNAV-3 Navigation Message + CNVX) ///< GPS/QZSS CNAV or CNAV-2 Navigation Message BeiDou-3 CNAV-1, CNAV-2 or CNAV-3 Navigation Message BETTER_ENUM(E_SatType, short int, - NONE, /* NONE or unknown */ + NONE, GEO, IGSO, MEO) @@ -456,10 +515,14 @@ BETTER_ENUM(RtcmMessageType, uint16_t, GPS_EPHEMERIS = 1019, + GLO_EPHEMERIS = 1020, + //GPS_NETWORK_RTK_RESIDUAL = 1030, //RECEIVER_AND_ANTENNA_DESC = 1033, - //BDS_EPHEMERIS = 1042, + BDS_EPHEMERIS = 1042, + + QZS_EPHEMERIS = 1044, GAL_FNAV_EPHEMERIS = 1045, GAL_INAV_EPHEMERIS = 1046, @@ -469,7 +532,17 @@ BETTER_ENUM(RtcmMessageType, uint16_t, GPS_SSR_CODE_BIAS = 1059, GPS_SSR_COMB_CORR = 1060, GPS_SSR_URA = 1061, - + GPS_SSR_HR_CLK_CORR = 1062, + GPS_SSR_PHASE_BIAS = 1265, + + GLO_SSR_ORB_CORR = 1063, + GLO_SSR_CLK_CORR = 1064, + GLO_SSR_CODE_BIAS = 1065, + GLO_SSR_COMB_CORR = 1066, + GLO_SSR_URA = 1067, + GLO_SSR_HR_CLK_CORR = 1068, + GLO_SSR_PHASE_BIAS = 1266, + MSM4_GPS = 1074, MSM5_GPS = 1075, MSM6_GPS = 1076, @@ -499,28 +572,134 @@ BETTER_ENUM(RtcmMessageType, uint16_t, GAL_SSR_ORB_CORR = 1240, GAL_SSR_CLK_CORR = 1241, - GAL_SSR_COMB_CORR = 1243, GAL_SSR_CODE_BIAS = 1242, + GAL_SSR_COMB_CORR = 1243, + GAL_SSR_URA = 1244, + GAL_SSR_HR_CLK_CORR = 1245, + GAL_SSR_PHASE_BIAS = 1267, - GPS_SSR_PHASE_BIAS = 1265, + QZS_SSR_ORB_CORR = 1246, + QZS_SSR_CLK_CORR = 1247, + QZS_SSR_CODE_BIAS = 1248, + QZS_SSR_COMB_CORR = 1249, + QZS_SSR_URA = 1250, + QZS_SSR_HR_CLK_CORR = 1251, + QZS_SSR_PHASE_BIAS = 1268, - GAL_SSR_PHASE_BIAS = 1267, + SBS_SSR_ORB_CORR = 1252, + SBS_SSR_CLK_CORR = 1253, + SBS_SSR_CODE_BIAS = 1254, + SBS_SSR_COMB_CORR = 1255, + SBS_SSR_URA = 1256, + SBS_SSR_HR_CLK_CORR = 1257, + SBS_SSR_PHASE_BIAS = 1269, + + BDS_SSR_ORB_CORR = 1258, + BDS_SSR_CLK_CORR = 1259, + BDS_SSR_CODE_BIAS = 1260, + BDS_SSR_COMB_CORR = 1261, + BDS_SSR_URA = 1262, + BDS_SSR_HR_CLK_CORR = 1263, + BDS_SSR_PHASE_BIAS = 1270, + COMPACT_SSR = 4073, + IGS_SSR = 4076, CUSTOM = 4082 ) -BETTER_ENUM(E_Ephemeris, int, +BETTER_ENUM(CompactSSRSubtype, unsigned short, + CMP_SSR_NONE = 0, + CMP_SSR_MSK = 1, + CMP_SSR_ORB = 2, + CMP_SSR_CLK = 3, + CMP_SSR_COD = 4, + CMP_SSR_PHS = 5, + CMP_SSR_BIA = 6, + CMP_SSR_URA = 7, + CMP_SSR_TEC = 8, + CMP_SSR_GRD = 9, + CMP_SSR_SRV = 10, + CMP_SSR_CMB = 11, + CMP_SSR_ATM = 12) + +BETTER_ENUM(IgsSSRSubtype, unsigned short, + IGS_SSR_GPS_NONE = 0, + IGS_SSR_GPS_ORB = 21, + IGS_SSR_GPS_CLK = 22, + IGS_SSR_GPS_CMB = 23, + IGS_SSR_GPS_HRC = 24, + IGS_SSR_GPS_COD = 25, + IGS_SSR_GPS_PHS = 26, + IGS_SSR_GPS_URA = 27, + + IGS_SSR_GLO_ORB = 41, + IGS_SSR_GLO_CLK = 42, + IGS_SSR_GLO_CMB = 43, + IGS_SSR_GLO_HRC = 44, + IGS_SSR_GLO_COD = 45, + IGS_SSR_GLO_PHS = 46, + IGS_SSR_GLO_URA = 47, + + IGS_SSR_GAL_ORB = 61, + IGS_SSR_GAL_CLK = 62, + IGS_SSR_GAL_CMB = 63, + IGS_SSR_GAL_HRC = 64, + IGS_SSR_GAL_COD = 65, + IGS_SSR_GAL_PHS = 66, + IGS_SSR_GAL_URA = 67, + + IGS_SSR_QZS_ORB = 81, + IGS_SSR_QZS_CLK = 82, + IGS_SSR_QZS_CMB = 83, + IGS_SSR_QZS_HRC = 84, + IGS_SSR_QZS_COD = 85, + IGS_SSR_QZS_PHS = 86, + IGS_SSR_QZS_URA = 87, + + IGS_SSR_BDS_ORB = 101, + IGS_SSR_BDS_CLK = 102, + IGS_SSR_BDS_CMB = 103, + IGS_SSR_BDS_HRC = 104, + IGS_SSR_BDS_COD = 105, + IGS_SSR_BDS_PHS = 106, + IGS_SSR_BDS_URA = 107, + + IGS_SSR_SBS_ORB = 121, + IGS_SSR_SBS_CLK = 122, + IGS_SSR_SBS_CMB = 123, + IGS_SSR_SBS_HRC = 124, + IGS_SSR_SBS_COD = 125, + IGS_SSR_SBS_PHS = 126, + IGS_SSR_SBS_URA = 127, + + IGS_SSR_IONVTEC = 201 +) + +BETTER_ENUM(E_Source, short int, NONE, PRECISE, SSR, KALMAN, - BROADCAST) - + BROADCAST, + NOMINAL, + MODEL, + REMOTE) BETTER_ENUM(E_RTCMSubmessage, short int, TIMESTAMP = 1 ) +BETTER_ENUM(E_CrdEpochEvent, int, + REC_RX = 0, // ground receive time (at SRP) (two-way) + SAT_BN = 1, // spacecraft bounce time (two-way) + REC_TX = 2, // ground transmit time (at SRP) (two-way) + SAT_RX = 3, // spacecraft receive time (one-way) + SAT_TX = 4, // spacecraft transmit time (one-way) + REC_TX_SAT_RX = 5, // ground transmit time (at SRP) and spacecraft receive time (one-way) + SAT_TX_REC_RX = 6, // spacecraft transmit time and ground receive time (at SRP) (one-way) + NONE = 7 +) + BETTER_ENUM(E_ObsWaitCode, short int, OK, EARLY_DATA, @@ -544,18 +723,6 @@ BETTER_ENUM(E_TidesMdl, short int, ELASTIC, ANELASTIC) -BETTER_ENUM(E_SnxDataMissing, short int, - NONE_MISSING, - SITE_ID, - RECEIVER, - ANTENNA, - ECCENTRICITY, - GPS_PHASE_CENTRE, - ESTIMATE) - -BETTER_ENUM(E_Integrator, short int, - RKF78) - BETTER_ENUM(E_ThirdBody, short int, MERCURY = 1, VENUS = 2, @@ -578,5 +745,92 @@ BETTER_ENUM(E_SigWarning, short int, USR_DISC = 5) // User defined +BETTER_ENUM(E_SlrRangeType, short int, // from crd_v2.01.pdf p7 + TX_ONLY = 0, // no ranges (i.e., transmit time only) + ONE_WAY = 1, // one-way ranging + TWO_WAY = 2, // two-way ranging + RX_ONLY = 3, // receive times only + MIXED = 3) // mixed (for real-time data recording, and combination of one- and two-way ranging, e.g., T2L2) + +BETTER_ENUM(E_UBXClass, short int, + NAV = 0x01, + RXM = 0x02, + INF = 0x04, + ACK = 0x05, + CFG = 0x06, + MON = 0x0A, + AID = 0x0B, + TIM = 0x0D) + +BETTER_ENUM(E_RXMId, short int, + SFRBX = 0x13, + MEASX = 0x14, + RAWX = 0x15) + +BETTER_ENUM(E_Month, short int, + NONE, + JAN, + FEB, + MAR, + ARP, + MAY, + JUN, + JUL, + AUG, + SEP, + OCT, + NOV, + DEC) + +BETTER_ENUM(E_FilePos, short int, + COORD, + CURR_TIME, + TOTAL_TIME, + PCDH, + NUM_SAMPLES, + FOOTER) + +BETTER_ENUM(E_Component, short int, + NONE, + X, + LLH, + P, + DX, + PREFIT, + POSTFIT, + VARIANCE, + OBSERVED, + HEADING, + RANGE, + SAT_CLOCK, + REC_CLOCK, + SAGNAC, + RELATIVITY1, + RELATIVITY2, + REC_ANTENNA_DELTA, + REC_PCO, + SAT_PCO, + REC_PCV, + SAT_PCV, + TIDES_SOLID, + TIDES_POLE, + TIDES_OTL, + IONOSPHERIC_COMPONENT, + IONOSPHERIC_COMPONENT1, + IONOSPHERIC_COMPONENT2, + IONOSPHERIC_MODEL, + PHASE_WIND_UP, + PHASE_AMBIGUITY, + REC_RANGE_BIAS, + REC_TIME_BIAS, + REC_PHASE_BIAS, + SAT_PHASE_BIAS, + REC_CODE_BIAS, + SAT_CODE_BIAS, + TROPOSPHERE, + EOP, + NET_RESIDUAL, + ORBIT_PT, + SAT_REFLECTOR_DELTA) + -#endif diff --git a/src/cpp/common/ephBroadcast.cpp b/src/cpp/common/ephBroadcast.cpp new file mode 100644 index 000000000..7f4a6a9c3 --- /dev/null +++ b/src/cpp/common/ephBroadcast.cpp @@ -0,0 +1,643 @@ + +#include "eigenIncluder.hpp" +#include "observations.hpp" +#include "navigation.hpp" +#include "acsConfig.hpp" +#include "trace.hpp" +#include "gTime.hpp" + + +#define STD_BRDCCLK 30.0 ///< error of broadcast clock (m) + +#define NMAX 10 + +#define J2_GLO 1.0826257E-3 ///< 2nd zonal harmonic of geopot ref [2] + +#define SIN_5 -0.0871557427476582 ///< sin(-5.0 deg) +#define COS_5 +0.9961946980917456 ///< cos(-5.0 deg) + +#define ERREPH_GLO 5.0 ///< error of glonass ephemeris (m) +#define TSTEP 60.0 ///< integration step glonass ephemeris (s) +#define RTOL_KEPLER 1E-14 ///< relative tolerance for Kepler equation + +#define MAX_ITER_KEPLER 30 ///< max number of iteration of Kelpler + +#define OMGE_GLO 7.292115E-5 ///< earth angular velocity (rad/s) ref [2] +#define OMGE_CMP 7.292115E-5 ///< earth angular velocity (rad/s) ref [9] +#define OMGE_GAL 7.2921151467E-5 ///< earth angular velocity (rad/s) ref [7] + +/** variance by ura ephemeris (ref [1] 20.3.3.3.1.1) +*/ +double var_uraeph( + int ura) +{ + const double ura_value[] = + { + 2.4, 3.4, 4.85, 6.85, 9.65, 13.65, 24.0, 48.0, 96.0, 192.0, 384.0, 768.0, 1536.0, 3072.0, 6144.0 + }; + + return ura < 0 || 15 < ura ? SQR(6144.0) : SQR(ura_value[ura]); +} + +/** select EOP/ION messages +*/ +template +EPHTYPE* selSysEphFromMap( + Trace& trace, + GTime time, + E_Sys sys, + E_NavMsgType type, + map>>>& ephMap) +{ +// trace(4,__FUNCTION__ " : time=%s sat=%2d iode=%d\n",time.to_string(3).c_str(),Sat,iode); + + auto& satEphMap = ephMap[sys][type]; + + auto it = satEphMap.lower_bound(time); + if (it == satEphMap.end()) + { + tracepdeex(5, trace, "\nno broadcast ephemeris (EOP/ION): %s sys=%s", time.to_string(0).c_str(), sys._to_string()); + if (satEphMap.empty() == false) + { + tracepdeex(5, trace, " last is %s", satEphMap.begin()->first.to_string(0).c_str()); + } + return nullptr; + } + + auto& [ephTime, eph] = *it; + + return &eph; +} + +/** select ephememeris +*/ +template +EPHTYPE* selSatEphFromMap( + Trace& trace, + GTime time, + SatSys Sat, + E_NavMsgType type, + int& iode, + map>>>& ephMap) +{ +// trace(4,__FUNCTION__ " : time=%s sat=%2d iode=%d\n",time.to_string(3).c_str(),Sat,iode); + + double tmax; + switch (Sat.sys) + { + case E_Sys::GAL: tmax = MAXDTOE_GAL; break; + case E_Sys::QZS: tmax = MAXDTOE_QZS; break; + case E_Sys::BDS: tmax = MAXDTOE_CMP; break; + case E_Sys::GLO: tmax = MAXDTOE_GLO; break; + case E_Sys::SBS: tmax = MAXDTOE_SBS; break; + default: tmax = MAXDTOE; break; + } + + auto& satEphMap = ephMap[Sat][type]; + + if (iode >= 0) + { + for (auto& [dummy, eph] : satEphMap) + { + if ( iode != eph.iode + ||fabs((eph.toe - time).to_double()) > tmax) + { + continue; + } + + return &eph; + } + + tracepdeex(5, trace, "\nno broadcast ephemeris: %s sat=%s with iode=%3d", time.to_string(0).c_str(), Sat.id().c_str(), iode); + + return nullptr; + } + + auto it = satEphMap.lower_bound(time + tmax); + if (it == satEphMap.end()) + { + tracepdeex(5, trace, "\nno broadcast ephemeris: %s sat=%s within MAXDTOE+ ", time.to_string(0).c_str(), Sat.id().c_str()); + if (satEphMap.empty() == false) + { + tracepdeex(5, trace, " last is %s", satEphMap.begin()->first.to_string(0).c_str()); + } + + return nullptr; + } + + auto& [ephTime, eph] = *it; + + if (fabs((eph.toe - time).to_double()) > tmax) + { + tracepdeex(5, trace, "\nno broadcast ephemeris: %s sat=%s within MAXDTOE-", time.to_string(0).c_str(), Sat.id().c_str()); + + return nullptr; + } + + iode = eph.iode; + + return &eph; +} + + +template<> Eph* seleph (Trace& trace, GTime time, SatSys Sat, E_NavMsgType type, int iode, Navigation& nav){ return selSatEphFromMap(trace, time, Sat, type, iode, nav.ephMap); } +template<> Geph* seleph(Trace& trace, GTime time, SatSys Sat, E_NavMsgType type, int iode, Navigation& nav){ return selSatEphFromMap(trace, time, Sat, type, iode, nav.gephMap); } +template<> Seph* seleph(Trace& trace, GTime time, SatSys Sat, E_NavMsgType type, int iode, Navigation& nav){ return selSatEphFromMap(trace, time, Sat, type, iode, nav.sephMap); } +template<> ION* seleph (Trace& trace, GTime time, E_Sys sys, E_NavMsgType type, Navigation& nav){ return selSysEphFromMap(trace, time, sys, type, nav.ionMap); } +template<> EOP* seleph (Trace& trace, GTime time, E_Sys sys, E_NavMsgType type, Navigation& nav){ return selSysEphFromMap(trace, time, sys, type, nav.eopMap); } + + + + + +/** glonass orbit differential equations + */ +void deq( + const double* x, + double* xdot, + Vector3d& acc) +{ + double r2 = dot(x, x, 3); + double r3 = r2 * sqrt(r2); + double omg2 = SQR(OMGE_GLO); + + if (r2 <= 0) + { + xdot[0] = 0; + xdot[1] = 0; + xdot[2] = 0; + xdot[3] = 0; + xdot[4] = 0; + xdot[5] = 0; + + return; + } + + /* ref [2] A.3.1.2 with bug fix for xdot[4],xdot[5] */ + double a = 1.5 * J2_GLO * MU_GLO * SQR(RE_GLO) / r2 / r3; /* 3/2*J2*mu*Ae^2/r^5 */ + double b = 5.0 * SQR(x[2]) / r2; /* 5*z^2/r^2 */ + double c = -MU_GLO / r3 - a * (1 - b); /* -mu/r^3-a(1-b) */ + + xdot[0] = x[3]; + xdot[1] = x[4]; + xdot[2] = x[5]; + + xdot[3] = (c + omg2) * x[0] + 2 * OMGE_GLO * x[4] + acc[0]; + xdot[4] = (c + omg2) * x[1] - 2 * OMGE_GLO * x[3] + acc[1]; + xdot[5] = (c - 2 * a) * x[2] + acc[2]; +} + +/* glonass position and velocity by numerical integration --------------------*/ +void glorbit( + double t, + double* x, + Vector3d& acc) +{ + double k1[6]; + double k2[6]; + double k3[6]; + double k4[6]; + double w [6]; + + deq(x, k1, acc); for (int i = 0; i < 6; i++) w[i] = x[i] + k1[i] * t / 2; + deq(w, k2, acc); for (int i = 0; i < 6; i++) w[i] = x[i] + k2[i] * t / 2; + deq(w, k3, acc); for (int i = 0; i < 6; i++) w[i] = x[i] + k3[i] * t; + deq(w, k4, acc); + + for (int i = 0; i < 6; i++) + x[i] += (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]) * t / 6; +} + + + + + + + + + +/** broadcast ephemeris to satellite clock bias +* compute satellite clock bias with broadcast ephemeris (gps, galileo, qzss) +* satellite clock does not include relativity correction and tdg +*/ +double eph2Clk(GTime time, Eph& eph, int recurse = 0) +{ + double t = (time - eph.toe).to_double(); t -= recurse ? eph2Clk(time - t, eph, recurse - 1) : 0; + + return + eph.f0 + + eph.f1 * t + + eph.f2 * t * t; +} + +/** glonass ephemeris to satellite clock bias + * satellite clock includes relativity correction + */ +double eph2Clk(GTime time, Geph& geph, int recurse = 0) +{ + double t = (time - geph.toe).to_double(); t -= recurse ? eph2Clk(time - t, geph, recurse - 1) : 0; + + return - geph.taun + + geph.gammaN * t; +} + +/** sbas ephemeris to satellite clock bias +*/ +double eph2Clk(GTime time, Seph& seph, int recurse = 0) +{ + double t = (time - seph.toe).to_double(); t -= recurse ? eph2Clk(time - t, seph, recurse - 1) : 0; + + return + seph.af0 + + seph.af1 * t; +} + + + + + +/** broadcast ephemeris to satellite position and clock bias +* compute satellite position and clock bias with broadcast ephemeris (gps, galileo, qzss) +* satellite clock includes relativity correction without code bias (tgd or bgd) +*/ +void eph2Pos( + GTime time, ///< time (gpst) + Eph& eph, ///< broadcast ephemeris + Vector3d& rSat, ///< satellite position (ecef) {x,y,z} (m) + double* var_ptr = nullptr) ///< satellite position and clock variance (m^2) +{ +// trace(4, __FUNCTION__ " : time=%s sat=%2d\n",time.to_string(3).c_str(),eph->Sat); + + if (eph.A <= 0) + { + rSat = Vector3d::Zero(); + + if (var_ptr) + *var_ptr = 0; + + return; + } + + double tk = (time - eph.toe).to_double(); + int prn = eph.Sat.prn; + int sys = eph.Sat.sys; + + double mu; + double omge; + switch (sys) + { + case E_Sys::GAL: mu = MU_GAL; omge = OMGE_GAL; break; + case E_Sys::BDS: mu = MU_CMP; omge = OMGE_CMP; break; + default: mu = MU_GPS; omge = OMGE; break; + } + + double M = eph.M0 + (sqrt(mu / (eph.A * eph.A * eph.A)) + eph.deln) * tk; + + double E = M; + double Ek = 0; + int n; + for (n = 0; fabs(E - Ek) > RTOL_KEPLER && n < MAX_ITER_KEPLER; n++) + { + Ek = E; + E -= (E - eph.e * sin(E) - M) / (1 - eph.e * cos(E)); + } + + if (n >= MAX_ITER_KEPLER) + { +// trace(2,"kepler iteration overflow sat=%2d\n",eph->Sat); + return; + } + + double sinE = sin(E); + double cosE = cos(E); + +// trace(4,"kepler: sat=%2d e=%8.5f n=%2d del=%10.3e\n",eph->Sat,eph->e,n,E-Ek); + + double u = atan2(sqrt(1 - eph.e * eph.e) * sinE, cosE - eph.e) + eph.omg; + double r = eph.A * (1 - eph.e * cosE); + double i = eph.i0 + + eph.idot * tk; + + double sin2u = sin(2 * u); + double cos2u = cos(2 * u); + + u += eph.cus * sin2u + eph.cuc * cos2u; //argument of latitude + r += eph.crs * sin2u + eph.crc * cos2u; //radius + i += eph.cis * sin2u + eph.cic * cos2u; //inclination + + double x = r * cos(u); + double y = r * sin(u); + double cosi = cos(i); + + /* beidou geo satellite (ref [9]), prn range may change in the future */ + if ( ( sys == +E_Sys::BDS) + &&( prn <= 5 + ||prn >= 59)) + { + double O = eph.OMG0 + + eph.OMGd * tk + - omge * eph.toes; + + double sinO = sin(O); + double cosO = cos(O); + + double xg = x * cosO - y * cosi * sinO; + double yg = x * sinO + y * cosi * cosO; + double zg = y * sin(i); + + double sino = sin(omge * tk); + double coso = cos(omge * tk); + + rSat[0] = +xg * coso + yg * sino * COS_5 + zg * sino * SIN_5; + rSat[1] = -xg * sino + yg * coso * COS_5 + zg * coso * SIN_5; + rSat[2] = -yg * SIN_5 + zg * COS_5; + } + else + { + double O = eph.OMG0 + + (eph.OMGd - omge) * tk + - omge * eph.toes; + + double sinO = sin(O); + double cosO = cos(O); + + rSat[0] = x * cosO - y * cosi * sinO; + rSat[1] = x * sinO + y * cosi * cosO; + rSat[2] = y * sin(i); + } + + /* position and clock error variance */ + if (var_ptr) + *var_ptr = var_uraeph(eph.sva); +} + + +/** glonass ephemeris to satellite position and clock bias. +* compute satellite position and clock bias with glonass ephemeris +*/ +void eph2Pos( + GTime time, ///< time (gpst) + Geph& geph, ///< glonass ephemeris + Vector3d& rSat, ///< satellite position {x,y,z} (ecef) (m) + double* var = nullptr) ///< satellite position and clock variance (m^2) +{ +// trace(4, __FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),geph->Sat); + + double t = (time - geph.toe).to_double(); + + double x[6]; + for (int i = 0; i < 3; i++) + { + x[i ] = geph.pos[i]; + x[i + 3] = geph.vel[i]; + } + + for (double tt = t < 0 ? -TSTEP : TSTEP; fabs(t) > 1E-9; t -= tt) + { + if (fabs(t) < TSTEP) + tt = t; + + glorbit(tt, x, geph.acc); + } + + for (int i = 0; i < 3; i++) + rSat[i] = x[i]; + + if (var) + *var = SQR(ERREPH_GLO); +} + +/** sbas ephemeris to satellite position and clock bias +* compute satellite position and clock bias with sbas ephemeris +*/ +void eph2Pos( + GTime time, ///< time (gpst) + Seph& seph, ///< sbas ephemeris + Vector3d& rSat, ///< satellite position {x,y,z} (ecef) (m) + double* var = nullptr) ///< satellite position and clock variance (m^2) +{ +// trace(4, __FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),seph->Sat); + + double t = (time - seph.t0).to_double(); + + for (int i = 0; i < 3; i++) + { + rSat[i] = seph.pos[i] + + seph.vel[i] * t + + seph.acc[i] * t * t / 2; + } + + if (var) + *var = var_uraeph(seph.sva); +} + + + + + + +/* satellite clock by broadcast ephemeris + */ +template +bool satClkBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatSys Sat, + double& satClk, + double& satClkVel, + double& ephVar, + bool& ephClkValid, + int& obsIode, + Navigation& nav) +{ + double satClk1; + double tt = 1E-3; + + ephVar = SQR(STD_BRDCCLK); + +// trace(4, "%s: time=%s sat=%2d iode=%d\n",__FUNCTION__,time.to_string(3).c_str(),obs.Sat,iode); + + int sys = Sat.sys; + + ephClkValid = false; + + auto type = acsConfig.used_nav_types[Sat.sys]; + + auto eph_ptr = seleph(trace, teph, Sat, type, obsIode, nav); + + if (eph_ptr == nullptr) + { + tracepdeex(2,trace, "Could not find Broadcast Ephemeris for sat: %s, %s\n", Sat.id().c_str(), teph.to_string(2)); + return false; + } + + auto& eph = *eph_ptr; + + satClk = eph2Clk(time, eph); + satClk1 = eph2Clk(time + tt, eph); + + if (eph.svh == E_Svh::SVH_OK) + { + ephClkValid = true; + } + + obsIode = eph.iode; + + /* satellite velocity and clock drift by differential approx */ + satClkVel = (satClk1 - satClk) / tt; + + return true; +} + + + +/* satellite position by broadcast ephemeris + */ +template +bool satPosBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatSys Sat, + Vector3d& rSat, + Vector3d& satVel, + double& ephVar, + bool& ephPosValid, + int& obsIode, + Navigation& nav) +{ + Vector3d rSat_1; + double tt = 1E-3; + +// trace(4, "%s: time=%s sat=%2d iode=%d\n",__FUNCTION__,time.to_string(3).c_str(),obs.Sat,iode); + + int sys = Sat.sys; + + auto type = acsConfig.used_nav_types[Sat.sys]; + + auto eph_ptr = seleph(trace, teph, Sat, type, obsIode, nav); + + if (eph_ptr == nullptr) + { + tracepdeex(2,trace, "Could not find Broadcast Ephemeris for sat: %s, %s\n", Sat.id().c_str(), teph.to_string(2)); + return false; + } + + auto& eph = *eph_ptr; + + eph2Pos(time, eph, rSat, &ephVar); + eph2Pos(time + tt, eph, rSat_1); + + if (eph.svh == E_Svh::SVH_OK) + { + ephPosValid = true; + } + + obsIode = eph.iode; + + /* satellite velocity and clock drift by differential approx */ + satVel = (rSat_1 - rSat) / tt; + + return true; +} + +/* satellite clock by broadcast ephemeris + */ +bool satClkBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatSys Sat, + double& satClk, + double& satClkVel, + double& ephVar, + bool& ephClkValid, + int& obsIode, + Navigation& nav) +{ + int sys = Sat.sys; + + ephClkValid = false; + + if ( sys == +E_Sys::GPS + || sys == +E_Sys::GAL + || sys == +E_Sys::QZS + || sys == +E_Sys::BDS) { return satClkBroadcast (trace, time, teph, Sat, satClk, satClkVel, ephVar, ephClkValid, obsIode, nav); } + else if ( sys == +E_Sys::GLO) { return satClkBroadcast (trace, time, teph, Sat, satClk, satClkVel, ephVar, ephClkValid, obsIode, nav); } + else if ( sys == +E_Sys::SBS) { return satClkBroadcast (trace, time, teph, Sat, satClk, satClkVel, ephVar, ephClkValid, obsIode, nav); } + else { return false; } +} + + +/* satellite position by broadcast ephemeris + */ +bool satPosBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatSys Sat, + Vector3d& rSat, + Vector3d& satVel, + double& ephVar, + bool& ephPosValid, + int& obsIode, + Navigation& nav) +{ + int sys = Sat.sys; + + ephPosValid = false; + + if ( sys == +E_Sys::GPS + || sys == +E_Sys::GAL + || sys == +E_Sys::QZS + || sys == +E_Sys::BDS) { return satPosBroadcast (trace, time, teph, Sat, rSat, satVel, ephVar, ephPosValid, obsIode, nav); } + else if ( sys == +E_Sys::GLO) { return satPosBroadcast (trace, time, teph, Sat, rSat, satVel, ephVar, ephPosValid, obsIode, nav); } + else if ( sys == +E_Sys::SBS) { return satPosBroadcast (trace, time, teph, Sat, rSat, satVel, ephVar, ephPosValid, obsIode, nav); } + else { return false; } + +} + +bool satClkBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + Navigation& nav, + int iode) +{ + satPos.iodeClk = iode; + + return satClkBroadcast( + trace, + time, + teph, + satPos.Sat, + satPos.satClk, + satPos.satClkVel, + satPos.satClkVar, + satPos.ephClkValid, + satPos.iodeClk, + nav); +} + +bool satPosBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + Navigation& nav, + int iode) +{ + satPos.iodePos = iode; + + return satPosBroadcast( + trace, + time, + teph, + satPos.Sat, + satPos.rSat, + satPos.satVel, + satPos.posVar, + satPos.ephPosValid, + satPos.iodePos, + nav); +} diff --git a/src/cpp/common/ephKalman.cpp b/src/cpp/common/ephKalman.cpp new file mode 100644 index 000000000..f667f4518 --- /dev/null +++ b/src/cpp/common/ephKalman.cpp @@ -0,0 +1,100 @@ + + + +#include "eigenIncluder.hpp" +#include "observations.hpp" +#include "navigation.hpp" +#include "algebra.hpp" +#include "trace.hpp" +#include "gTime.hpp" + + +bool satClkKalman( + Trace& trace, + GTime time, + SatPos& satPos, + const KFState* kfState_ptr) +{ + if (kfState_ptr == nullptr) + { + return false; + } + + auto& kfState = *kfState_ptr; + + double clk = 0; + double vel = 0; + + //get orbit things from the state + KFKey kfKey; + kfKey.type = KF::SAT_CLOCK; + kfKey.Sat = satPos.Sat; + + bool found = true; + found &= kfState.getKFValue(kfKey, clk); + + if (found == false) + { + return false; + } + + kfKey.type = KF::SAT_CLOCK_RATE; + + found &= kfState.getKFValue(kfKey, vel); + + double dt = (time - kfState.time).to_double(); + + clk /= CLIGHT; + vel /= CLIGHT; + + satPos.satClk = clk + + vel * dt; + + satPos.satClkVel = vel; + + return true; +} + +bool satPosKalman( + Trace& trace, + GTime time, + SatPos& satPos, + const KFState* kfState_ptr) +{ + if (kfState_ptr == nullptr) + { + return false; + } + + auto& kfState = *kfState_ptr; + + bool found = true; + + auto& rSat0 = satPos.rSatEci0; + auto& vSat0 = satPos.vSatEci0; + + //get orbit things from the state + for (int i = 0; i < 3; i++) + { + KFKey kfKey; + kfKey.type = KF::ORBIT; + kfKey.Sat = satPos.Sat; + + kfKey.num = i; + found &= kfState.getKFValue(kfKey, rSat0(i)); + + kfKey.num = i + 3; + found &= kfState.getKFValue(kfKey, vSat0(i)); + + if (found == false) + { + return false; + } + } + + double dt = (time - kfState.time).to_double(); + + satPos.rSatEciDt = propagateEllipse(trace, kfState.time, dt, rSat0, vSat0, satPos.rSat); + + return true; +} diff --git a/src/cpp/common/ephPrecise.cpp b/src/cpp/common/ephPrecise.cpp new file mode 100644 index 000000000..ef54ac550 --- /dev/null +++ b/src/cpp/common/ephPrecise.cpp @@ -0,0 +1,659 @@ + +// #pragma GCC optimize ("O0") + +#include +#include +#include +#include +#include + +using std::string; +using std::array; +using std::map; + +#include + + +#include "eigenIncluder.hpp" +#include "coordinates.hpp" +#include "corrections.hpp" +#include "navigation.hpp" +#include "ephPrecise.hpp" +#include "biasSINEX.hpp" +#include "constants.hpp" +#include "mongoRead.hpp" +#include "ephemeris.hpp" +#include "station.hpp" +#include "algebra.hpp" +#include "planets.hpp" +#include "common.hpp" +#include "gTime.hpp" +#include "trace.hpp" +#include "enums.h" + +#define NMAX 10 /* order of polynomial interpolation */ +#define MAXDTE 900.0 /* max time difference to ephem time (s) */ +#define EXTERR_CLK 1E-3 /* extrapolation error for clock (m/s) */ +#define EXTERR_EPH 5E-7 /* extrapolation error for ephem (m/s^2) */ + +/** read dcb parameters file + */ +int readdcb( + string file) +{ + std::ifstream inputStream(file); + if (!inputStream) + { +// trace(2,"dcb parameters file open error: %s\n",file); + return 0; + } + + BiasEntry entry; +// trace(3,"readdcbf: file=%s\n",file); + + entry.tini.bigTime = 3; + entry.measType = CODE; + entry.source = "dcb"; + + string line; + while (std::getline(inputStream, line)) + { + char* buff = &line[0]; + + E_DCBPair type = E_DCBPair::NONE; + if (strstr(buff,"DIFFERENTIAL (P1-P2) CODE BIASES")) type = E_DCBPair::P1_P2; + else if (strstr(buff,"DIFFERENTIAL (P1-C1) CODE BIASES")) type = E_DCBPair::P1_C1; + else if (strstr(buff,"DIFFERENTIAL (P2-C2) CODE BIASES")) type = E_DCBPair::P2_C2; + + char str1[32] = ""; + char str2[32] = ""; + + if ( !type + ||sscanf(buff,"%31s %31s", str1, str2) < 1) + continue; + + double cbias = str2num(buff,26,9); + double rms = str2num(buff,38,9); + + entry.bias = cbias * 1E-9 * CLIGHT; /* ns -> m */ //todo aaron, this looks like it had issues to begin with + entry.var = SQR(rms * 1E-9 * CLIGHT); + + SatSys Sat(str1); + + if (Sat.sys == +E_Sys::GPS) + { + if (type == +E_DCBPair::P1_P2) { entry.cod1 = E_ObsCode::L1W; entry.cod2 = E_ObsCode::L2W; } + else if (type == +E_DCBPair::P1_C1) { entry.cod1 = E_ObsCode::L1W; entry.cod2 = E_ObsCode::L1C; } + else if (type == +E_DCBPair::P2_C2) { entry.cod1 = E_ObsCode::L2W; entry.cod2 = E_ObsCode::L2D; } + } + else if (Sat.sys == +E_Sys::GLO) + { + if (type == +E_DCBPair::P1_P2) { entry.cod1 = E_ObsCode::L1P; entry.cod2 = E_ObsCode::L2P; } + else if (type == +E_DCBPair::P1_C1) { entry.cod1 = E_ObsCode::L1P; entry.cod2 = E_ObsCode::L1C; } + else if (type == +E_DCBPair::P2_C2) { entry.cod1 = E_ObsCode::L2P; entry.cod2 = E_ObsCode::L2C; } + } + + string id; + if ( !strcmp(str1,"G") + ||!strcmp(str1,"R")) + { + /* receiver dcb */ + entry.Sat = Sat; + entry.name = str2; + id = str2; + } + else if (Sat) + { + /* satellite dcb */ + entry.Sat = Sat; + entry.name = ""; + id = str1; + } + + if ( Sat.sys == +E_Sys::GLO + &&Sat.prn == 0) + { + // this seems to be a receiver + // for ambiguous GLO receiver bias id (i.e. PRN not specified), duplicate bias entry for each satellite + for (int prn = 1; prn <= NSATGLO; prn++) + { + Sat.prn = prn; + id = entry.name + ":" + Sat.id(); + // entry.Sat = Sat; + pushBiasSinex(id, entry); + } + } + else if ( Sat.sys == +E_Sys::GLO + &&Sat.prn != 0) + { + // this can be a receiver or satellite + id = id + ":" + Sat.id(); + pushBiasSinex(id, entry); + } + else + { + // this can be a receiver or satellite + id = id + ":" + Sat.sysChar(); + pushBiasSinex(id, entry); + } + } + + return 1; +} + +/** polynomial interpolation by Neville's algorithm + */ +double interpolate(const double *x, double *y, int n) +{ + for (int j=1; j < n; j++) + for (int i=0; i < n - j; i++) + { + y[i] = (x[i+j] * y[i] - x[i] * y[i+1]) / (x[i+j] - x[i]); + } + + return y[0]; +} + +/** polynomial interpolation by Neville's algorithm + */ +Vector3d interpolate( + vector& x, + vector& y) +{ + for (int j = 1; j < x.size(); j++) + for (int i = 0; i < x.size() - j; i++) + { + y[i] = (x[i+j] * y[i] - x[i] * y[i+1]) / (x[i+j] - x[i]); + } + + return y[0]; +} + +/** satellite position by precise ephemeris + */ +bool pephpos( + Trace& trace, + GTime time, + SatSys Sat, + Navigation& nav, + Vector3d& rSat, + double* vare) +{ +// trace(4,"%s : time=%s sat=%s\n",__FUNCTION__, time.to_string(3).c_str(),Sat.id().c_str()); + + rSat = Vector3d::Zero(); + + if (nav.pephMap.empty()) + { + BOOST_LOG_TRIVIAL(warning) << "Warning: Looking for precise positions, but no precise ephemerides found"; + + return false; + } + + auto it = nav.pephMap.find(Sat.id()); + if (it == nav.pephMap.end()) + { + BOOST_LOG_TRIVIAL(warning) << "Warning: Looking for precise position, but no precise ephemerides found for " << Sat.id(); + + return false; + } + + auto& [id, pephMap] = *it; + + auto firstTime = pephMap.begin() ->first; + auto lastTime = pephMap.rbegin() ->first; + + if ( (pephMap.size() < NMAX + 1) + ||(time < firstTime - MAXDTE) + ||(time > lastTime + MAXDTE)) + { + tracepdeex(3, std::cout, "\nNo precise ephemeris for %s at %s, ephemerides cover %s to %s", + Sat.id() .c_str(), + time .to_string(0) .c_str(), + firstTime.to_string(0) .c_str(), + lastTime .to_string(0) .c_str()); + return false; + } + +// //search for the ephemeris in the map + + auto peph_it = pephMap.lower_bound(time); + if (peph_it == pephMap.end()) + { + peph_it--; + } + + auto middle0 = peph_it; + + //go forward a few steps to make sure we're far from the end of the map. + for (int i = 0; i < NMAX/2; i++) + { + peph_it++; + if (peph_it == pephMap.end()) + { + break; + } + } + + //go backward a few steps to make sure we're far from the beginning of the map + for (int i = 0; i <= NMAX; i++) + { + peph_it--; + if (peph_it == pephMap.begin()) + { + break; + } + } + + auto begin = peph_it; + + vector t(NMAX+1); + vector p(NMAX+1); + double c[2]; + double s[3]; + + //get interpolation parameters and check all ephemerides have values. + peph_it = begin; + for (int i = 0; i <= NMAX; i++, peph_it++) + { + Peph& peph = peph_it->second; + if (peph.pos.isZero()) + { +// trace(3,"prec ephem outage %s sat=%s\n",time.to_string().c_str(), Sat.id().c_str()); + return false; + } + + auto& pos = peph.pos; + + t[i] = (peph.time - time).to_double(); + p[i] = pos; + } + + rSat = interpolate(t, p); + + if (vare) + { + double std = middle0->second.posStd.norm(); + + /* extrapolation error for orbit */ + if (t[0 ] > 0) std += EXTERR_EPH * SQR(t[0 ]) / 2; //todo aaron, needs straigtening as below? + else if (t[NMAX] < 0) std += EXTERR_EPH * SQR(t[NMAX]) / 2; + + *vare = SQR(std); + } + + return true; +} + +bool mongopos( + GTime time, + SatSys Sat, + Vector3d& rSat) +{ +// trace(4,"%s : time=%s sat=%s\n",__FUNCTION__, time.to_string(3).c_str(),Sat.id().c_str()); + + rSat = Vector3d::Zero(); + + auto mongoMap = mongoReadOrbits(time, Sat); + + if (mongoMap.empty()) + { + tracepdeex(3, std::cout, "\nLooking for mongo position, but no mongom ephemerides found for %s", Sat.id().c_str()); + return false; + } + + auto& timeMap = mongoMap[Sat]; + + auto firstTime = timeMap.begin() ->first; + auto lastTime = timeMap.rbegin() ->first; + + if ( (timeMap.size() < NMAX + 1) + ||(time < firstTime - MAXDTE) + ||(time > lastTime + MAXDTE)) + { + tracepdeex(3, std::cout, "\nNo mongo ephemeris for %s at %s, ephemerides cover %s to %s", + Sat.id() .c_str(), + time .to_string(0) .c_str(), + firstTime.to_string(0) .c_str(), + lastTime .to_string(0) .c_str()); + return false; + } + +// //search for the ephemeris in the map + + auto peph_it = timeMap.lower_bound(time); + if (peph_it == timeMap.end()) + { + peph_it--; + } + + auto middle0 = peph_it; + + //go forward a few steps to make sure we're far from the end of the map. + for (int i = 0; i < NMAX/2; i++) + { + peph_it++; + if (peph_it == timeMap.end()) + { + break; + } + } + + //go backward a few steps to make sure we're far from the beginning of the map + for (int i = 0; i <= NMAX; i++) + { + peph_it--; + if (peph_it == timeMap.begin()) + { + break; + } + } + + auto begin = peph_it; + + vector t(NMAX+1); + vector p(NMAX+1); + double c[2]; + double s[3]; + + for (auto T : t) + { + std::cout << std::endl << T; + } + + //get interpolation parameters and check all ephemerides have values. + peph_it = begin; + for (int i = 0; i <= NMAX; i++, peph_it++) + { + auto& [ephTime, state] = *peph_it; + + if (state.isZero()) + { +// trace(3,"prec ephem outage %s sat=%s\n",time.to_string().c_str(), Sat.id().c_str()); + return false; + } + + t[i] = (ephTime - time).to_double(); + p[i] = state.head(3); + } + + rSat = interpolate(t, p); + + return true; +} + +template +bool pclkMapClk( + Trace& trace, + GTime time, + string id, + Navigation& nav, + double& clk, + double* varc, + TYPE& pclkMaps) +{ + auto it = pclkMaps.find(id); + if (it == pclkMaps.end()) + { + return false; + } + + auto& [key, pclkMap] = *it; + + if ( (pclkMap.size() < 2) + ||(time < pclkMap.begin() ->first - MAXDTE) + ||(time > pclkMap.rbegin() ->first + MAXDTE)) + { + BOOST_LOG_TRIVIAL(debug) << "no prec clock " << time.to_string() << " for " << id; + + return false; + } + + auto pclk_it = pclkMap.lower_bound(time); + if (pclk_it == pclkMap.end()) + { + pclk_it--; + } + + auto middle0_it = pclk_it; + + auto middle1_it = middle0_it; + if (middle0_it != pclkMap.begin()) + { + middle0_it--; + } + + auto& [time0, middle0] = *middle0_it; + auto& [time1, middle1] = *middle1_it; + + //linear interpolation + double t[2]; + double c[2]; + t[0] = (time - time0).to_double(); + t[1] = (time - time1).to_double(); + c[0] = middle0.clk; + c[1] = middle1.clk; + + bool use0 = true; + bool use1 = true; + + if (c[0] == INVALID_CLOCK_VALUE) { use0 = false; } + if (c[1] == INVALID_CLOCK_VALUE) { use1 = false; } + if (t[0] <= 0) { use1 = false; } + if (t[1] >= 0) { use0 = false; } + + if ( use0 == false + && use1 == false) + { + BOOST_LOG_TRIVIAL(debug) << "Precise clock outage " << time.to_string() << " for " << id; + + clk = 0; + + return false; + } + + double std = 0; + + if (use0 && use1) { clk = (c[1] * t[0] - c[0] * t[1]) / (t[0] - t[1]); double inv0 = 1 / middle0.clkStd * CLIGHT + EXTERR_CLK * fabs(t[0]); + double inv1 = 1 / middle1.clkStd * CLIGHT + EXTERR_CLK * fabs(t[1]); + std = 1 / (inv0 + inv1); } + else if (use0) { clk = c[0]; std = middle0.clkStd * CLIGHT + EXTERR_CLK * fabs(t[0]); } + else if (use1) { clk = c[1]; std = middle1.clkStd * CLIGHT + EXTERR_CLK * fabs(t[1]); } + + if (varc) + *varc = SQR(std); + + return true; +} + +/** clock by precise clock + */ +bool pephclk( + Trace& trace, + GTime time, + string id, + Navigation& nav, + double& clk, + double* varc) +{ +// BOOST_LOG_TRIVIAL(debug) << "pephclk : time=" << time.to_string(3) << " id=" << id; + + bool pass; + pass = pclkMapClk(trace, time, id, nav, clk, varc, nav.pclkMap); if (pass) return true; + pass = pclkMapClk(trace, time, id, nav, clk, varc, nav.pephMap); if (pass) return true; + + return false; +} + +/** satellite antenna phase center offset in ecef + */ +VectorEcef satAntOff( + Trace& trace, ///< Trace file to output to + GTime time, ///< Solution time + AttStatus& attStatus, ///< attitude status + SatSys& Sat, ///< Satellite ID + map& lamMap) ///< Lambda (wavelengths) map +{ + tracepdeex(4, trace, "\n%-10s: time=%s sat=%s", __FUNCTION__, time.to_string(3).c_str(), Sat.id().c_str()); + + VectorEcef dAnt; + + E_FType j; + E_FType k; + E_Sys sys = Sat.sys; + switch (sys) + { + case E_Sys::GPS: j = F1; k = F2; break; //todo aaron, change to use same format as new_preprocessor + case E_Sys::GLO: j = G1; k = G2; break; + case E_Sys::GAL: j = F1; k = F5; break; + case E_Sys::BDS: j = B1; k = B3; break; + case E_Sys::QZS: j = F1; k = F2; break; + case E_Sys::SBS: j = F1; k = F5; break; + default: return dAnt; + } + + if ( lamMap[j] == 0 + ||lamMap[k] == 0) + { + return dAnt; + } + + double gamma = SQR(lamMap[k]) / SQR(lamMap[j]); + double C1 = gamma / (gamma - 1); + double C2 = -1 / (gamma - 1); + + /* iono-free LC */ + Vector3d pcoJ = antPco(Sat.id(), Sat.sys, j, time, E_Radio::TRANSMITTER); + Vector3d pcoK = antPco(Sat.id(), Sat.sys, k, time, E_Radio::TRANSMITTER); + + VectorEcef dant1 = body2ecef(attStatus, pcoJ); + VectorEcef dant2 = body2ecef(attStatus, pcoK); + + dAnt = C1 * dant1 + + C2 * dant2; + + return dAnt; +} + +VectorEcef satAntOff( + Trace& trace, ///< Trace file to output to + GTime time, ///< Solution time + AttStatus& attStatus, ///< attitude status + SatSys& Sat, ///< Satellite ID + E_FType ft) ///< Frequency +{ + tracepdeex(4, trace, "\n%s: time=%s\n", __FUNCTION__, time.to_string(3).c_str()); + + /* iono-free LC */ + Vector3d pco = antPco(Sat.id(), Sat.sys, ft, time, E_Radio::TRANSMITTER); + + VectorEcef dAnt = body2ecef(attStatus, pco); + + tracepdeex(3, trace, "\n%s %s pco (enu) = %14.4f %14.4f %14.4f", time.to_string().c_str(), Sat.id().c_str(), pco[1], pco[0], pco[2]); + tracepdeex(3, trace, "\n%s %s pcoEcef = %14.4f %14.4f %14.4f", time.to_string().c_str(), Sat.id().c_str(), dAnt[0], dAnt[1], dAnt[2]); + + return dAnt; +} + +bool satClkPrecise( + Trace& trace, + GTime time, + SatSys& Sat, + double& clk, + double& clkVel, + double& clkVar, + Navigation& nav) +{ + clk = 0; + clkVel = 0; + + tracepdeex(4, trace, "\n%-10s: time=%s sat=%s", __FUNCTION__, time.to_string(3).c_str(), Sat.id().c_str()); + + double tt = 1E-3; + + double clk2 = 0; + + bool pass = pephclk(trace, time, Sat, nav, clk, &clkVar) + && pephclk(trace, time + tt, Sat, nav, clk2); + + if ( pass == false + || clk == INVALID_CLOCK_VALUE) + { + tracepdeex(4, trace, " - pephclk failed"); + clk = 0; + + return false; + } + + clkVel = (clk2 - clk) / tt; + + return true; +} + + +/** Satellite position/clock by precise ephemeris/clock + */ +bool satPosPrecise( + Trace& trace, + GTime time, + SatSys& Sat, + Vector3d& rSat, + Vector3d& satVel, + double& ephVar, + Navigation& nav) +{ + rSat = Vector3d::Zero(); + satVel = Vector3d::Zero(); + + tracepdeex(4, trace, "\n%-10s: time=%s sat=%s", __FUNCTION__, time.to_string(3).c_str(), Sat.id().c_str()); + + double tt = 1E-3; + + Vector3d rSat2 = Vector3d::Zero(); + + bool pass = pephpos(trace, time, Sat, nav, rSat, &ephVar) + && pephpos(trace, time + tt, Sat, nav, rSat2); + + if (pass == false) + { + tracepdeex(4, trace, " - pephpos failed"); + + return false; + } + + satVel = (rSat2 - rSat) / tt; + + return true; +} + +bool satPosPrecise( + Trace& trace, + GTime time, + SatPos& satPos, + Navigation& nav) +{ + return satPosPrecise( + trace, + time, + satPos.Sat, + satPos.rSat, + satPos.satVel, + satPos.posVar, + nav); +} + +bool satClkPrecise( + Trace& trace, + GTime time, + SatPos& satPos, + Navigation& nav) +{ + return satClkPrecise( + trace, + time, + satPos.Sat, + satPos.satClk, + satPos.satClkVel, + satPos.satClkVar, + nav); +} diff --git a/src/cpp/common/preceph.hpp b/src/cpp/common/ephPrecise.hpp similarity index 54% rename from src/cpp/common/preceph.hpp rename to src/cpp/common/ephPrecise.hpp index 346b5170c..7fb3387e7 100644 --- a/src/cpp/common/preceph.hpp +++ b/src/cpp/common/ephPrecise.hpp @@ -1,34 +1,23 @@ -#ifndef PRECEPH_HPP__ -#define PRECEPH_HPP__ +#pragma once #include #include -#include using std::string; -using std::list; -#include "streamTrace.hpp" -#include "antenna.hpp" #include "satSys.hpp" #include "gTime.hpp" +#include "trace.hpp" //forward declarations struct Navigation; -struct Obs; +struct SatPos; +struct GObs; struct Peph; int readdcb(string file); -bool peph2pos( - Trace& trace, - GTime time, - SatSys& Sat, - Obs& obs, - Navigation& nav, - bool applyRelativity = true); - void readSp3ToNav( string& file, Navigation* nav, @@ -36,19 +25,39 @@ void readSp3ToNav( bool readsp3( std::istream& fileStream, - list& pephList, + vector& pephList, int opt, - bool& isUTC, + E_TimeSys& tsys, double* bfact); -double interppol(const double *x, double *y, int n); +double interpolate(const double *x, double *y, int n); void orb2sp3(Navigation& nav); -int pephclk( + +bool pephPos( + Trace& trace, + GTime time, + SatPos& satPos, + Navigation& nav); + +bool pephClk( + Trace& trace, + GTime time, + SatPos& satPos, + Navigation& nav); + +bool pephclk( + Trace& trace, GTime time, string id, Navigation& nav, double& dtSat, double* varc = nullptr); -#endif +bool pephpos( + Trace& trace, + GTime time, + SatSys Sat, + Navigation& nav, + Vector3d& rSat, + double* vare = nullptr); diff --git a/src/cpp/common/ephRemote.cpp b/src/cpp/common/ephRemote.cpp new file mode 100644 index 000000000..5d48fea79 --- /dev/null +++ b/src/cpp/common/ephRemote.cpp @@ -0,0 +1,73 @@ + +#include "eigenIncluder.hpp" +#include "observations.hpp" +#include "mongoRead.hpp" +#include "algebra.hpp" +#include "trace.hpp" +#include "gTime.hpp" + +bool satClkRemote( + Trace& trace, + GTime time, + SatPos& satPos) +{ + return false; +// bool found = true; +// +// GTime t0; +// t0.bigTime = (long int) (time.bigTime + 0.5); // time tags in mongo will be rounded up to whole sec +// +// double +// Vector6d inertialState = mongoReadOrbit(t0, satPos.Sat); +// +// if (inertialState.isZero()) +// { +// return false; +// } +// +// +// auto& rSat0 = satPos.rSatEci0; +// auto& vSat0 = satPos.vSatEci0; +// +// rSat0 = inertialState.head(3); +// vSat0 = inertialState.tail(3); +// +// double dt = (time - t0).to_double(); +// +// satPos.rSatEciDt = propagateEllipse(trace, t0, dt, rSat0, vSat0, satPos.rSat); + + + return true; +} + +bool satPosRemote( + Trace& trace, + GTime time, + SatPos& satPos) +{ + bool found = true; + + GTime t0; + t0.bigTime = (long int) (time.bigTime + 0.5); // time tags in mongo will be rounded up to whole sec + + auto inertialStatesMap = mongoReadOrbits(t0, satPos.Sat); + + if (inertialStatesMap.empty()) + { + return false; + } + + auto& inertialState = inertialStatesMap[satPos.Sat][t0]; + + auto& rSat0 = satPos.rSatEci0; + auto& vSat0 = satPos.vSatEci0; + + rSat0 = inertialState.head(3); + vSat0 = inertialState.tail(3); + + double dt = (time - t0).to_double(); + + satPos.rSatEciDt = propagateEllipse(trace, t0, dt, rSat0, vSat0, satPos.rSat); + + return true; +} diff --git a/src/cpp/common/ephSBAS.cpp b/src/cpp/common/ephSBAS.cpp new file mode 100644 index 000000000..d443e9b2b --- /dev/null +++ b/src/cpp/common/ephSBAS.cpp @@ -0,0 +1,42 @@ + +#if (0) +/* satellite position and clock with sbas correction -------------------------*/ +// int satpos_sbas(gtime_t time, gtime_t teph, SatSys Sat, const nav_t* nav, +// double* rs, double* dtSat, double* var, int* svh) +// { +// const sbssatp_t* sbs; +// int i; +// +// trace(4, __FUNCTION__ ": time=%s sat=%2d\n", time.to_string(3).c_str(), Sat); +// +// /* search sbas satellite correciton */ +// for (i = 0; i < nav->sbssat.nsat; i++) +// { +// sbs = nav->sbssat.sat + i; +// +// if (sbs->Sat == Sat) +// break; +// } +// +// if (i >= nav->sbssat.nsat) +// { +// trace(2, "no sbas correction for orbit: %s sat=%2d\n", time.to_string(0).c_str(), Sat); +// ephpos(time, teph, Sat, nav, -1, rs, dts, var, svh); +// *svh = -1; +// +// return 0; +// } +// +// /* satellite postion and clock by broadcast ephemeris */ +// if (!ephpos(time, teph, Sat, nav, sbs->lcorr.iode, rs, dts, var, svh)) +// return 0; +// +// /* sbas satellite correction (long term and fast) */ +// if (sbssatcorr(time, Sat, nav, rs, dts, var)) +// return 1; +// +// *svh = -1; +// +// return 0; +// } +#endif diff --git a/src/cpp/common/ephSSR.cpp b/src/cpp/common/ephSSR.cpp new file mode 100644 index 000000000..a5fc5ed3f --- /dev/null +++ b/src/cpp/common/ephSSR.cpp @@ -0,0 +1,344 @@ + +#include "eigenIncluder.hpp" +#include "navigation.hpp" +#include "acsConfig.hpp" +#include "ephemeris.hpp" +#include "gTime.hpp" +#include "ssr.hpp" + + +#define DEFURASSR 0.03 ///< default accurary of ssr corr (m) +#define MAXECORSSR 15 ///< max orbit correction of ssr (m) +#define MAXCCORSSR (1E-6*CLIGHT) ///< max clock correction of ssr (m) + +/** variance by ura ssr (ref [4]) +*/ +double var_urassr( + int ura) +{ + if (ura <= 0) return SQR(DEFURASSR); + if (ura >= 63) return SQR(5.4665); + + double std = (pow(3, (ura >> 3) & 7) * (1.0 + (ura & 7) / 4.0) - 1.0) * 1E-3; + return SQR(std); +} + +Matrix3d rac2ecef( + Vector3d& rSat, // Sat position (ECEF) + Vector3d& satVel) // Sat velocity (ECEF) +{ + Matrix3d ecef2racMat = ecef2rac(rSat, satVel); + + return ecef2racMat.transpose(); +} + +template +void cullSSRMap( + GTime time, + TYPE& map) +{ + for (auto it = map.begin(); it != map.end(); ) + { + auto& [ssrtime, ssr] = *it; + + if (ssr.t0 < time - ssr.udi * acsConfig.validity_interval_factor) + { + it = map.erase(it); + } + else + { + ++it; + } + } +} + +void cullOldSSRs( + GTime time) +{ + for (auto& [Sat, satNav] : nav.satNavMap) + { + cullSSRMap(time, satNav.receivedSSR.ssrCodeBias_map); + cullSSRMap(time, satNav.receivedSSR.ssrPhasBias_map); + cullSSRMap(time, satNav.receivedSSR.ssrClk_map); + cullSSRMap(time, satNav.receivedSSR.ssrEph_map); + cullSSRMap(time, satNav.receivedSSR.ssrHRClk_map); + cullSSRMap(time, satNav.receivedSSR.ssrUra_map); + } +} + + +bool ssrPosDelta( + GTime time, + GTime ephTime, + SatPos& satPos, + const SSRMaps& ssrMaps, + Vector3d& dPos, + int& iodPos, + int& iodEph, + GTime& validStart, + GTime& validStop) +{ + if (ssrMaps.ssrEph_map.empty()) + { + satPos.failureSsrPosEmpty = true; + + return false; + } + + //get 'price is right' closest ssr components to ephemeris time. + auto ephIt = ssrMaps.ssrEph_map.lower_bound(ephTime); + if (ephIt == ssrMaps.ssrEph_map.end()) + { + satPos.failureSsrPosTime = true; + + return false; + } + + auto& [t_e, ssrEph] = *ephIt; + + iodPos = ssrEph.iod; + iodEph = ssrEph.iode; + + double tEph = (time - ssrEph.t0).to_double(); + + validStart = ssrEph.t0 - ssrEph.udi / 2; + validStop = ssrEph.t0 + ssrEph.udi / 2; + + /* ssr orbit and clock correction (ref [4]) */ + if (fabs(tEph) > ssrEph.udi * acsConfig.validity_interval_factor) + { + satPos.failureSsrPosUdi = true; + + tracepdeex(2, std::cout, "age of ssr error: %s t=%.0f > %.0f\n",time.to_string(0).c_str(), tEph, ssrEph.udi * acsConfig.validity_interval_factor); + return false; + } + + dPos = ssrEph.deph + + ssrEph.ddeph * tEph; + + if (dPos.norm() > MAXECORSSR) + { + satPos.failureSsrPosMag = true; + + tracepdeex(2, std::cout,"SSR pos correction too large : %s %s deph=%.1fm\n", time.to_string(0).c_str(), satPos.Sat.id().c_str(), dPos.norm()); + return false; + } + + return true; +} + +bool ssrClkDelta( + GTime time, + GTime ephTime, + SatPos& satPos, + const SSRMaps& ssrMaps, + double& dclk, + int& iodClk, + GTime& validStart, + GTime& validStop) +{ + if (ssrMaps.ssrClk_map.empty()) + { + satPos.failureSsrClkEmpty = true; + tracepdeex(4,std::cout, "No SSR corrections for sat=%s\n", satPos.Sat.id().c_str()); + return false; + } + + //get 'price is right' closest ssr components to ephemeris time + auto clkIt = ssrMaps.ssrClk_map.lower_bound(ephTime); + if (clkIt == ssrMaps.ssrClk_map.end()) + { + satPos.failureSsrClkTime = true; + tracepdeex(4,std::cout, "No SSR corrections before %s sat=%s\n", ephTime.to_string(0).c_str(), satPos.Sat.id().c_str()); + return false; + } + + auto& [t_c, ssrClk] = *clkIt; + + iodClk = ssrClk.iod; + + double tClk = (time - ssrClk.t0).to_double(); + + validStart = ssrClk.t0 - ssrClk.udi / 2; + validStop = ssrClk.t0 + ssrClk.udi / 2; + + /* ssr orbit and clock correction (ref [4]) */ + if (fabs(tClk) > ssrClk.udi * acsConfig.validity_interval_factor) + { + satPos.failureSsrClkUdi = true; + + tracepdeex(4,std::cout, "age of ssr error: %s sat=%s\n", time.to_string(0).c_str(), satPos.Sat.id().c_str()); + return false; + } + + dclk = ssrClk.dclk[0] + + ssrClk.dclk[1] * tClk + + ssrClk.dclk[2] * tClk * tClk; + + /* ssr highrate clock correction (ref [4]) */ + auto hrcIt = ssrMaps.ssrHRClk_map.lower_bound(ephTime); + if (hrcIt != ssrMaps.ssrHRClk_map.end()) + { + auto& [t_h, ssrHrc] = *hrcIt; + + double tHrc = (time - ssrHrc.t0).to_double(); + + if ( ssrClk.iod == ssrHrc.iod + && fabs(tHrc) < ssrClk.udi * acsConfig.validity_interval_factor) + { + dclk += ssrHrc.hrclk; + } + } + + if (fabs(dclk) > MAXCCORSSR) + { + satPos.failureSsrClkMag = true; + + tracepdeex(2, std::cout,"SSR clk correction too large : %s %s dclk=%.1f\n", time.to_string(0).c_str(), satPos.Sat.id().c_str(), dclk); + return 0; + } + + return true; +} + +/** satellite position and clock with ssr correction +*/ +bool satPosSSR( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + Navigation& nav) +{ + SSRMaps& ssrMaps = satPos.satNav_ptr->receivedSSR; + SatSys& Sat = satPos.Sat; + Vector3d& rSat = satPos.rSat; + Vector3d& satVel = satPos.satVel; + double& satClk = satPos.satClk; + double& satClkVel = satPos.satClkVel; + bool& ephPosValid = satPos.ephPosValid; + bool& ephClkValid = satPos.ephClkValid; + int& obsIodeClk = satPos.iodeClk; + int& obsIodePos = satPos.iodePos; + double& posVar = satPos.posVar; + double& clkVar = satPos.satClkVar; + +// tracepdeex(4,trace, __FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),satPos.Sat); + ephPosValid = false; + ephClkValid = false; + + int iodPos; + int iodEph; + int iodClk; + GTime ephValidStart; + GTime ephValidStop; + GTime clkValidStart; + GTime clkValidStop; + Vector3d dPos; + double dClk; + GTime ephTime = time; + + bool once = true; + + while (true) + { + bool posDeltaPass = ssrPosDelta(time, ephTime, satPos, ssrMaps, dPos, iodPos, iodEph, ephValidStart, ephValidStop); + bool clkDeltaPass = ssrClkDelta(time, ephTime, satPos, ssrMaps, dClk, iodClk, clkValidStart, clkValidStop); + + if ( posDeltaPass == false + || clkDeltaPass == false) + { + satPos.failureSSRFail = true; + + BOOST_LOG_TRIVIAL(warning) << "Warning: SSR Corrections not found for " << satPos.Sat.id(); + return false; + } + + if ( ephValidStart >= clkValidStop + ||clkValidStart >= ephValidStop) + { + BOOST_LOG_TRIVIAL(warning) << "Warning: Timing inconsistent for " << satPos.Sat.id() << " : " << ephValidStart.to_string(0) << "-" << ephValidStop.to_string(0) << " " << clkValidStart.to_string(0) << "-" << clkValidStop.to_string(0); + + if (ephValidStart >= clkValidStop) ephTime = clkValidStop - 0.5; + if (clkValidStart >= ephValidStop) ephTime = ephValidStop - 0.5; + continue; + } + + if (iodClk != iodPos) + { + satPos.failureIodeConsistency = true; + + BOOST_LOG_TRIVIAL(warning) << "Warning: IOD inconsistent for " << satPos.Sat.id() << iodClk << " " << iodPos; + return false; + } + + bool pass = true; + pass &= satPosBroadcast(trace, time, teph, Sat, rSat, satVel, posVar, ephPosValid, iodEph, nav); + pass &= satClkBroadcast(trace, time, teph, Sat, satClk, satClkVel, clkVar, ephClkValid, iodEph, nav); + + if (pass == false) + { + if (once) + { + once = false; + + if (clkValidStart < ephValidStart) ephTime = clkValidStart - 0.5; + else ephTime = ephValidStart - 0.5; + + BOOST_LOG_TRIVIAL(warning) << "Warning: IODE BRDC not found for " << satPos.Sat.id() << " - adjusting ephTime"; + + continue; + } + satPos.failureBroadcastEph = true; + + BOOST_LOG_TRIVIAL(warning) << "warning: IODE BRDC not found for " << satPos.Sat.id(); + + return false; + } + + break; + } + + tracepdeex(4, trace, "\nBRDCEPH %s %s %13.3f %13.3f %13.3f %11.3f ", time.to_string(6).c_str(), Sat.id().c_str(), rSat[0], rSat[1], rSat[2], 1e9*satClk); + + Matrix3d rac2ecefMat = rac2ecef(rSat, satVel); + + Vector3d dPosECEF = rac2ecefMat * dPos; + + rSat -= dPosECEF; + + /* t_corr = t_sv - (dtSat(brdc) + dClk(ssr) / CLIGHT) (ref [10] eq.3.12-7) */ + satClk += dClk / CLIGHT; + + /* variance by ssr ura */ + double ura = -1; + + auto uraIt = ssrMaps.ssrUra_map.lower_bound(time); + if (uraIt != ssrMaps.ssrUra_map.end()) + { + auto& [t_u, ssrUra] = *uraIt; + + ura = ssrUra.ura; + } + + clkVar = var_urassr(ura); + + tracepdeex(4, trace, "\nSSR_EPH %s %s %13.3f %13.3f %13.3f %11.3f ", time.to_string(6).c_str(), Sat.id().c_str(), rSat[0], rSat[1], rSat[2], 1e9*satClk); + + tracepdeex(5, trace, "%s: %s sat=%s deph=%6.3f %6.3f %6.3f dclk=%6.3f var=%6.3f iode=%d clktimes:%s %s ephtimes%s %s\n", + __FUNCTION__, + time.to_string(2).c_str(), + Sat.id().c_str(), + dPos[0], + dPos[1], + dPos[2], + dClk, + clkVar, + iodEph, + clkValidStart .to_string(0).c_str(), + clkValidStop .to_string(0).c_str(), + ephValidStart .to_string(0).c_str(), + ephValidStop .to_string(0).c_str()); + + return true; +} diff --git a/src/cpp/common/ephemeris.cpp b/src/cpp/common/ephemeris.cpp index 3be2e2703..6362250b5 100644 --- a/src/cpp/common/ephemeris.cpp +++ b/src/cpp/common/ephemeris.cpp @@ -1,400 +1,39 @@ // #pragma GCC optimize ("O0") - -#include "enums.h" -#include "common.hpp" -#include "satSys.hpp" -#include "algebra.hpp" -#include "preceph.hpp" +#include "eigenIncluder.hpp" +#include "corrections.hpp" +#include "coordinates.hpp" +#include "navigation.hpp" +#include "ephPrecise.hpp" +#include "mongoRead.hpp" #include "constants.hpp" #include "acsConfig.hpp" #include "ephemeris.hpp" #include "testUtils.hpp" -#include "navigation.hpp" -#include "corrections.hpp" -#include "streamTrace.hpp" -#include "eigenIncluder.hpp" - - -#define NMAX 10 - -/* constants and macros ------------------------------------------------------*/ - -#define J2_GLO 1.0826257E-3 ///< 2nd zonal harmonic of geopot ref [2] - -#define OMGE_GLO 7.292115E-5 ///< earth angular velocity (rad/s) ref [2] -#define OMGE_CMP 7.292115E-5 ///< earth angular velocity (rad/s) ref [9] -#define OMGE_GAL 7.2921151467E-5 ///< earth angular velocity (rad/s) ref [7] - -#define SIN_5 -0.0871557427476582 ///< sin(-5.0 deg) -#define COS_5 0.9961946980917456 ///< cos(-5.0 deg) - -#define ERREPH_GLO 5.0 ///< error of glonass ephemeris (m) -#define TSTEP 60.0 ///< integration step glonass ephemeris (s) -#define RTOL_KEPLER 1E-14 ///< relative tolerance for Kepler equation - -#define DEFURASSR 0.03 ///< default accurary of ssr corr (m) -#define MAXECORSSR 10.0 ///< max orbit correction of ssr (m) -#define MAXCCORSSR (1E-6*CLIGHT) ///< max clock correction of ssr (m) -#define STD_BRDCCLK 30.0 ///< error of broadcast clock (m) - -#define MAX_ITER_KEPLER 30 ///< max number of iteration of Kelpler - -/** variance by ura ephemeris (ref [1] 20.3.3.3.1.1) - */ -double var_uraeph( - int ura) -{ - const double ura_value[] = - { - 2.4, 3.4, 4.85, 6.85, 9.65, 13.65, 24.0, 48.0, 96.0, 192.0, 384.0, 768.0, 1536.0, 3072.0, 6144.0 - }; - - return ura < 0 || 15 < ura ? SQR(6144.0) : SQR(ura_value[ura]); -} - -/** variance by ura ssr (ref [4]) - */ -double var_urassr( - int ura) -{ - if (ura <= 0) return SQR(DEFURASSR); - if (ura >= 63) return SQR(5.4665); - - double std = (pow(3, (ura >> 3) & 7) * (1.0 + (ura & 7) / 4.0) - 1.0) * 1E-3; - return SQR(std); -} - -/** broadcast ephemeris to satellite clock bias -* compute satellite clock bias with broadcast ephemeris (gps, galileo, qzss) -* notes : see ref [1],[7],[8] -* satellite clock does not include relativity correction and tdg -*/ -double eph2clk( - GTime time, ///< time by satellite clock (gpst) - Eph& eph) ///< broadcast ephemeris -{ -// trace(4,__FUNCTION__ " : time=%s sat=%2d\n",time.to_string(3).c_str(),eph->Sat); - double t = time - eph.toc; - - for (int i = 0; i < 2; i++) - { - t -= eph.f0 - + eph.f1 * t - + eph.f2 * t * t; - } - - double ans = eph.f0 - + eph.f1 * t - + eph.f2 * t * t; - return ans; -} +#include "algebra.hpp" +#include "orbits.hpp" +#include "satSys.hpp" +#include "common.hpp" +#include "trace.hpp" +#include "enums.h" +#include "ssr.hpp" -/** broadcast ephemeris to satellite position and clock bias -* compute satellite position and clock bias with broadcast ephemeris (gps, galileo, qzss) -* -* notes : see ref [1],[7],[8] -* satellite clock includes relativity correction without code bias -* (tgd or bgd) +/** URA SSR by variance */ -void eph2pos( - GTime time, ///< time (gpst) - Eph& eph, ///< broadcast ephemeris - Vector3d& rSat, ///< satellite position (ecef) {x,y,z} (m) - double& dtSat, ///< satellite clock bias (s) - double* var_ptr = nullptr, ///< satellite position and clock variance (m^2) - bool applyRelativity = true) ///< apply relativity to clock -{ -// trace(4, __FUNCTION__ " : time=%s sat=%2d\n",time.to_string(3).c_str(),eph->Sat); - - if (eph.A <= 0) - { - rSat = Vector3d::Zero(); - dtSat = 0; - - if (var_ptr) - *var_ptr = 0; - - return; - } - - double tk = time - eph.toe; - int prn = eph.Sat.prn; - int sys = eph.Sat.sys; - - double mu; - double omge; - switch (sys) - { - case E_Sys::GAL: mu = MU_GAL; omge = OMGE_GAL; break; - case E_Sys::BDS: mu = MU_CMP; omge = OMGE_CMP; break; - default: mu = MU_GPS; omge = OMGE; break; - } - - double M = eph.M0 + (sqrt(mu / (eph.A * eph.A * eph.A)) + eph.deln) * tk; - - double E = M; - double Ek = 0; - int n; - for (n = 0; fabs(E - Ek) > RTOL_KEPLER && n < MAX_ITER_KEPLER; n++) - { - Ek = E; - E -= (E - eph.e * sin(E) - M) / (1 - eph.e * cos(E)); - } - - if (n >= MAX_ITER_KEPLER) - { -// trace(2,"kepler iteration overflow sat=%2d\n",eph->Sat); - return; - } - - double sinE = sin(E); - double cosE = cos(E); - -// trace(4,"kepler: sat=%2d e=%8.5f n=%2d del=%10.3e\n",eph->Sat,eph->e,n,E-Ek); - - double u = atan2(sqrt(1 - eph.e * eph.e) * sinE, cosE - eph.e) + eph.omg; - double r = eph.A * (1 - eph.e * cosE); - double i = eph.i0 - + eph.idot * tk; - - double sin2u = sin(2 * u); - double cos2u = cos(2 * u); - - u += eph.cus * sin2u + eph.cuc * cos2u; //argument of latitude - r += eph.crs * sin2u + eph.crc * cos2u; //radius - i += eph.cis * sin2u + eph.cic * cos2u; //inclination - - double x = r * cos(u); - double y = r * sin(u); - double cosi = cos(i); - - /* beidou geo satellite (ref [9]), prn range may change in the future */ - if ( ( sys == +E_Sys::BDS) - &&( prn <= 5 - ||prn >= 59)) - { - double O = eph.OMG0 - + eph.OMGd * tk - - omge * eph.toes; - - double sinO = sin(O); - double cosO = cos(O); - - double xg = x * cosO - y * cosi * sinO; - double yg = x * sinO + y * cosi * cosO; - double zg = y * sin(i); - - double sino = sin(omge * tk); - double coso = cos(omge * tk); - - rSat[0] = +xg * coso + yg * sino * COS_5 + zg * sino * SIN_5; - rSat[1] = -xg * sino + yg * coso * COS_5 + zg * coso * SIN_5; - rSat[2] = -yg * SIN_5 + zg * COS_5; - } - else - { - double O = eph.OMG0 - + (eph.OMGd - omge) * tk - - omge * eph.toes; - - double sinO = sin(O); - double cosO = cos(O); - - rSat[0] = x * cosO - y * cosi * sinO; - rSat[1] = x * sinO + y * cosi * cosO; - rSat[2] = y * sin(i); - } - - tk = time - eph.toc; - dtSat = eph.f0 - + eph.f1 * tk - + eph.f2 * tk * tk; - - /* relativity correction */ - if (applyRelativity) - { - dtSat -= 2 * sqrt(mu * eph.A) * eph.e * sinE / SQR(CLIGHT); //is equivalent to - 2 * obs.rSat.dot(obs.satVel) / CLIGHT; - } - - /* position and clock error variance */ - if (var_ptr) - *var_ptr = var_uraeph(eph.sva); -} - -/* glonass orbit differential equations --------------------------------------*/ -void deq( - const double* x, - double* xdot, - Vector3d& acc) -{ - double r2 = dot(x, x, 3); - double r3 = r2 * sqrt(r2); - double omg2 = SQR(OMGE_GLO); - - if (r2 <= 0) - { - xdot[0] = 0; - xdot[1] = 0; - xdot[2] = 0; - xdot[3] = 0; - xdot[4] = 0; - xdot[5] = 0; - - return; - } - - /* ref [2] A.3.1.2 with bug fix for xdot[4],xdot[5] */ - double a = 1.5 * J2_GLO * MU_GLO * SQR(RE_GLO) / r2 / r3; /* 3/2*J2*mu*Ae^2/r^5 */ - double b = 5.0 * SQR(x[2]) / r2; /* 5*z^2/r^2 */ - double c = -MU_GLO / r3 - a * (1 - b); /* -mu/r^3-a(1-b) */ - - xdot[0] = x[3]; - xdot[1] = x[4]; - xdot[2] = x[5]; - - xdot[3] = (c + omg2) * x[0] + 2 * OMGE_GLO * x[4] + acc[0]; - xdot[4] = (c + omg2) * x[1] - 2 * OMGE_GLO * x[3] + acc[1]; - xdot[5] = (c - 2 * a) * x[2] + acc[2]; -} - -/* glonass position and velocity by numerical integration --------------------*/ -void glorbit( - double t, - double* x, - Vector3d& acc) -{ - double k1[6]; - double k2[6]; - double k3[6]; - double k4[6]; - double w [6]; - - deq(x, k1, acc); for (int i = 0; i < 6; i++) w[i] = x[i] + k1[i] * t / 2; - deq(w, k2, acc); for (int i = 0; i < 6; i++) w[i] = x[i] + k2[i] * t / 2; - deq(w, k3, acc); for (int i = 0; i < 6; i++) w[i] = x[i] + k3[i] * t; - deq(w, k4, acc); - - for (int i = 0; i < 6; i++) - x[i] += (k1[i] + 2 * k2[i] + 2 * k3[i] + k4[i]) * t / 6; -} - -/* glonass ephemeris to satellite clock bias ----------------------------------- -* compute satellite clock bias with glonass ephemeris -* args : gtime_t time I time by satellite clock (gpst) -* Geph *geph I glonass ephemeris -* return : satellite clock bias (s) -* notes : see ref [2] -*-----------------------------------------------------------------------------*/ -double geph2clk( - GTime time, - Geph& geph) -{ -// trace(4,__FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),geph->Sat); - - double t = time - geph.toe; - - for (int i = 0; i < 2; i++) - { - t -= geph.taun - + geph.gamn * t; - } - - return geph.taun - + geph.gamn * t; -} - -/** glonass ephemeris to satellite position and clock bias. -* compute satellite position and clock bias with glonass ephemeris -* -*/ -void geph2pos( - GTime time, ///< time (gpst) - Geph& geph, ///< glonass ephemeris - Vector3d& rSat, ///< satellite position {x,y,z} (ecef) (m) - double& dts, ///< satellite clock bias (s) - double* var = nullptr) ///< satellite position and clock variance (m^2) -{ -// trace(4, __FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),geph->Sat); - - double t = time - geph.toe; - - dts = geph.taun - + geph.gamn * t; - - double x[6]; - for (int i = 0; i < 3; i++) - { - x[i ] = geph.pos[i]; - x[i + 3] = geph.vel[i]; - } - - for (double tt = t < 0 ? -TSTEP : TSTEP; fabs(t) > 1E-9; t -= tt) - { - if (fabs(t) < TSTEP) - tt = t; - - glorbit(tt, x, geph.acc); - } - - for (int i = 0; i < 3; i++) - rSat[i] = x[i]; - - if (var) - *var = SQR(ERREPH_GLO); -} - -/* sbas ephemeris to satellite clock bias -------------------------------------- -* compute satellite clock bias with sbas ephemeris -* args : gtime_t time I time by satellite clock (gpst) -* Seph *seph I sbas ephemeris -* return : satellite clock bias (s) -* notes : see ref [3] -*-----------------------------------------------------------------------------*/ -double seph2clk( - GTime time, - Seph& seph) +double ephVarToUra( + double ephVar) { -// trace(4,__FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),seph->Sat); + // to be implemented - double t = time - seph.t0; - - for (int i = 0; i < 2; i++) - { - t -= seph.af0 - + seph.af1 * t; - } - - return seph.af0 - + seph.af1 * t; + return ephVar; } -/** sbas ephemeris to satellite position and clock bias ------------------------- -* compute satellite position and clock bias with sbas ephemeris -*/ -void seph2pos( - GTime time, ///< time (gpst) - Seph& seph, ///< sbas ephemeris - Vector3d& rSat, ///< satellite position {x,y,z} (ecef) (m) - double& dtSat, ///< satellite clock bias (s) - double* var = nullptr) ///< satellite position and clock variance (m^2) +double relativity1( + Vector3d& rSat, + Vector3d& satVel) { -// trace(4, __FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),seph->Sat); - - double t = time - seph.t0; - - for (int i = 0; i < 3; i++) - { - rSat[i] = seph.pos[i] - + seph.vel[i] * t - + seph.acc[i] * t * t / 2; - } - - dtSat = seph.af0 - + seph.af1 * t; - - if (var) - *var = var_uraeph(seph.sva); + return 2 * rSat.dot(satVel) / CLIGHT / CLIGHT; } template @@ -416,13 +55,14 @@ void cullEphMap( default: tmax = MAXDTOE + 1; break; } - for (auto it = satEphMap.begin(); it != satEphMap.end(); ) + for (auto& [navtyp, navMap] : satEphMap) + for (auto it = navMap.begin(); it != navMap.end(); ) { auto& [ephtime, eph] = *it; - + if (ephtime < time - tmax) { - it = satEphMap.erase(it); + it = navMap.erase(it); } else { @@ -432,929 +72,275 @@ void cullEphMap( } } -template -void cullSSRMap( - GTime time, - TYPE& map) -{ - for (auto it = map.begin(); it != map.end(); ) - { - auto& [ssrtime, ssr] = *it; - - if (ssr.t0 < time - ssr.udi * acsConfig.validity_interval_factor) - { - it = map.erase(it); - } - else - { - ++it; - } - } -} - -void cullOldSSRs( - GTime time) -{ - for (auto& [satid, satNav] : nav.satNavMap) - { - cullSSRMap(time, satNav.receivedSSR.ssrCodeBias_map); - cullSSRMap(time, satNav.receivedSSR.ssrPhasBias_map); - cullSSRMap(time, satNav.receivedSSR.ssrClk_map); - cullSSRMap(time, satNav.receivedSSR.ssrEph_map); - cullSSRMap(time, satNav.receivedSSR.ssrHRClk_map); - cullSSRMap(time, satNav.receivedSSR.ssrUra_map); - } -} - void cullOldEphs( GTime time) { - cullEphMap (time, nav.ephMap); - cullEphMap (time, nav.gephMap); - cullEphMap (time, nav.sephMap); - for (auto& [a,b] : nav.cephMap) - { - cullEphMap (time, b); - } + cullEphMap(time, nav.ephMap); + cullEphMap(time, nav.gephMap); + cullEphMap(time, nav.sephMap); + cullEphMap(time, nav.cephMap); } -/** select ephememeris - */ -template -EPHTYPE* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - map>>& ephMap) +bool satclk( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + vector ephTypes, + Navigation& nav, + const KFState* kfState_ptr) { -// trace(4,__FUNCTION__ " : time=%s sat=%2d iode=%d\n",time.to_string(3).c_str(),Sat,iode); - - double tmax; - switch (Sat.sys) - { - case E_Sys::QZS: tmax = MAXDTOE_QZS + 1; break; - case E_Sys::GAL: tmax = MAXDTOE_GAL + 1; break; - case E_Sys::BDS: tmax = MAXDTOE_CMP + 1; break; - case E_Sys::GLO: tmax = MAXDTOE_GLO + 1; break; - case E_Sys::SBS: tmax = MAXDTOE_SBS + 1; break; - default: tmax = MAXDTOE + 1; break; - } - - auto& satEphMap = ephMap[Sat]; + satPos.ephClkValid = false; + + bool returnValue = false; + + for (auto& ephType : ephTypes) + { + tracepdeex(4, trace, "\n%-10s: time=%s sat=%s ephType=%d", __FUNCTION__, time.to_string(3).c_str(), satPos.Sat.id().c_str(), ephType); - if (iode >= 0) - { - for (auto& [dummy, eph] : satEphMap) + switch (ephType) { - if (iode != eph.iode) - { - continue; - } - - return &eph; + case E_Source::BROADCAST: returnValue = satClkBroadcast (trace, time, teph, satPos, nav ); break; +// case E_Source::SSR: returnValue = satClkSSR (trace, time, teph, satPos, nav ); break; + case E_Source::PRECISE: returnValue = satClkPrecise (trace, time, satPos, nav ); break; + case E_Source::KALMAN: returnValue = satClkKalman (trace, time, satPos, kfState_ptr ); break; + case E_Source::REMOTE: returnValue = satClkRemote (trace, time, satPos ); break; + default: continue; } - - tracepdeex(5, trace, "no broadcast ephemeris: %s sat=%s with iode=%3d\n", time.to_string(0).c_str(), Sat.id().c_str(), iode); - return nullptr; - } - - auto it = satEphMap.lower_bound(time + tmax); - if (it == satEphMap.end()) - { - tracepdeex(5, trace, "no broadcast ephemeris: %s sat=%s within MAXDTOE+ ", time.to_string(0).c_str(), Sat.id().c_str()); - if (satEphMap.empty() == false) - { - tracepdeex(5, trace, " last is %s", satEphMap.begin()->first.to_string(0).c_str()); - } - tracepdeex(5, trace, "\n"); - return nullptr; - } - - auto& [ephTime, eph] = *it; - - if (fabs(eph.toe - time) > tmax) - { - tracepdeex(5, trace, "no broadcast ephemeris: %s sat=%s within MAXDTOE-\n", time.to_string(0).c_str(), Sat.id().c_str()); - return nullptr; - } - - return &eph; -} - -/** select CNVX ephememeris - */ -template -EPHTYPE* seleph( - Trace& trace, - GTime time, - SatSys Sat, - E_NavMsgType type, - int iode, - map>>>& ephMap) -{ -// trace(4,__FUNCTION__ " : time=%s sat=%2d iode=%d\n",time.to_string(3).c_str(),Sat,iode); - - if ( Sat.sys != +E_Sys::GPS - &&Sat.sys != +E_Sys::QZS - &&Sat.sys != +E_Sys::BDS) - { - tracepdeex(5, trace, "invalid satellite system for CNVX message type: sys=%s type=%s\n", Sat.sys._to_string(), type._to_string()); - return nullptr; - } - - double tmax; - switch (Sat.sys) - { - case E_Sys::QZS: tmax = MAXDTOE_QZS + 1; break; - case E_Sys::BDS: tmax = MAXDTOE_CMP + 1; break; - default: tmax = MAXDTOE + 1; break; - } - - auto& satEphMap = ephMap[Sat][type]; - - if (iode >= 0) - { - for (auto& [dummy, eph] : satEphMap) + + if (returnValue == false) { - if (iode != eph.iode) - { - continue; - } - - return &eph; + continue; } - - tracepdeex(5, trace, "no broadcast ephemeris (CNVX): %s sat=%s with iode=%3d\n", time.to_string(0).c_str(), Sat.id().c_str(), iode); - return nullptr; - } - - auto it = satEphMap.lower_bound(time + tmax); - if (it == satEphMap.end()) - { - tracepdeex(5, trace, "no broadcast ephemeris (CNVX): %s sat=%s within MAXDTOE+ ", time.to_string(0).c_str(), Sat.id().c_str()); - if (satEphMap.empty() == false) - { - tracepdeex(5, trace, " last is %s", satEphMap.begin()->first.to_string(0).c_str()); - } - tracepdeex(5, trace, "\n"); - return nullptr; - } - - auto& [ephTime, eph] = *it; - - if (fabs(eph.toe - time) > tmax) - { - tracepdeex(5, trace, "no broadcast ephemeris (CNVX): %s sat=%s within MAXDTOE-\n", time.to_string(0).c_str(), Sat.id().c_str()); - return nullptr; + + satPos.clkSource = ephType; + satPos.ephClkValid = true; + + break; } - return &eph; + return returnValue; } -/** select EOP/ION messages - */ -template -EPHTYPE* seleph( - Trace& trace, - GTime time, - E_Sys sys, - E_NavMsgType type, - map>>>& ephMap) -{ -// trace(4,__FUNCTION__ " : time=%s sat=%2d iode=%d\n",time.to_string(3).c_str(),Sat,iode); - - auto& satEphMap = ephMap[sys][type]; - - auto it = satEphMap.lower_bound(time); - if (it == satEphMap.end()) - { - tracepdeex(5, trace, "no broadcast ephemeris (EOP/ION): %s sys=%s", time.to_string(0).c_str(), sys._to_string()); - if (satEphMap.empty() == false) - { - tracepdeex(5, trace, " last is %s", satEphMap.begin()->first.to_string(0).c_str()); - } - tracepdeex(5, trace, "\n"); - return nullptr; - } - - auto& [ephTime, eph] = *it; +/** compute satellite position and clock +* satellite clock does not include code bias correction (tgd or bgd) +*/ +bool satpos( + Trace& trace, ///< Trace to output to + GTime time, ///< time (gpst) + GTime teph, ///< time to select ephemeris (gpst) + SatPos& satPos, ///< Data required for determining and storing satellite positions/clocks + vector ephTypes, ///< Source of ephemeris + E_OffsetType offsetType, ///< Type of antenna offset to apply + Navigation& nav, ///< navigation data + const KFState* kfState_ptr) ///< Optional pointer to a kalman filter to take values from +{ + satPos.ephPosValid = false; + + double antennaScalar = 0; + bool returnValue = false; - return &eph; -} - -template<> -Eph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - Navigation& nav) -{ - return seleph(trace, time, Sat, iode, nav.ephMap); -} - -template<> -Geph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - Navigation& nav) -{ - return seleph(trace, time, Sat, iode, nav.gephMap); -} - -template<> -Seph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - Navigation& nav) -{ - return seleph(trace, time, Sat, -1, nav.sephMap); -} - -template<> -Ceph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - E_NavMsgType type, - int iode, - Navigation& nav) -{ - return seleph(trace, time, Sat, type, iode, nav.cephMap); -} + for (auto& ephType : ephTypes) + { + tracepdeex(4, trace, "\n%-10s: time=%s sat=%s ephType=%d offsetType=%d", __FUNCTION__, time.to_string(3).c_str(), satPos.Sat.id().c_str(), ephType, offsetType); -template<> -ION* seleph( - Trace& trace, - GTime time, - E_Sys sys, - E_NavMsgType type, - Navigation& nav) -{ - return seleph(trace, time, sys, type, nav.ionMap); -} - -template<> -EOP* seleph( - Trace& trace, - GTime time, - E_Sys sys, - E_NavMsgType type, - Navigation& nav) -{ - return seleph(trace, time, sys, type, nav.eopMap); -} - -/* satellite clock with broadcast ephemeris ----------------------------------*/ -int ephclk( - GTime time, - GTime teph, - Obs& obs, - double& dts) -{ - int sys; - -// trace(4,__FUNCTION__ " : time=%s sat=%2d\n",time.to_string(3).c_str(),obs.Sat); - - sys = obs.Sat.sys; - - //todo aaron, need to check ephemeris timeout. with teph - switch (sys) - { - case E_Sys::GPS: - case E_Sys::GAL: - case E_Sys::QZS: - case E_Sys::BDS: { if (!obs.satNav_ptr->eph_ptr) return 0; dts = eph2clk (time, *obs.satNav_ptr->eph_ptr); break; } - case E_Sys::GLO: { if (!obs.satNav_ptr->geph_ptr) return 0; dts = geph2clk(time, *obs.satNav_ptr->geph_ptr); break; } - case E_Sys::SBS: { if (!obs.satNav_ptr->seph_ptr) return 0; dts = seph2clk(time, *obs.satNav_ptr->seph_ptr); break; } - default: + switch (ephType) { - return 0; + case E_Source::BROADCAST: returnValue = satPosBroadcast (trace, time, teph, satPos, nav ); break; + case E_Source::SSR: returnValue = satPosSSR (trace, time, teph, satPos, nav ); break; + case E_Source::PRECISE: returnValue = satPosPrecise (trace, time, satPos, nav ); break; + case E_Source::KALMAN: returnValue = satPosKalman (trace, time, satPos, kfState_ptr ); break; + case E_Source::REMOTE: returnValue = satPosRemote (trace, time, satPos ); break; + default: return false; } - } - - return 1; -} - - - -/* satellite position and clock by broadcast ephemeris -----------------------*/ -bool ephpos( - Trace& trace, - GTime time, - GTime teph, - SatSys Sat, - Vector3d& rSat, - Vector3d& satVel, - double* dtSat, - double& ephVar, - E_Svh& svh, - int& obsIode, - Navigation& nav, - int iode, - bool applyRelativity = true) -{ - Vector3d rSat_1; - double dtSat_1; - double tt = 1E-3; - -// trace(4, "%s: time=%s sat=%2d iode=%d\n",__FUNCTION__,time.to_string(3).c_str(),obs.Sat,iode); - - int sys = Sat.sys; - - svh = SVH_UNHEALTHY; - - if ( sys == +E_Sys::GPS - || sys == +E_Sys::GAL - || sys == +E_Sys::QZS - || sys == +E_Sys::BDS) - { - Eph* eph_ptr = seleph(trace, teph, Sat, iode, nav); - - if (eph_ptr == nullptr) - return false; - auto& eph = *eph_ptr; - - eph2pos(time, eph, rSat, dtSat[0], &ephVar, applyRelativity); - time = time + tt; eph2pos(time, eph, rSat_1, dtSat_1, nullptr, applyRelativity); + if (returnValue == false) + { + continue; + } - svh = eph.svh; - obsIode = eph.iode; - } - else if (sys == +E_Sys::GLO) - { - Geph* geph_ptr = seleph(trace, teph, Sat, iode, nav); - - if (geph_ptr == nullptr) - return false; + satPos.posSource = ephType; + satPos.ephPosValid = true; - auto& geph = *geph_ptr; - - geph2pos(time, geph, rSat, dtSat[0], &ephVar); - time = time + tt; geph2pos(time, geph, rSat_1, dtSat_1); + if (ephType == +E_Source::SSR && acsConfig.ssr_input_antenna_offset == +E_OffsetType::UNSPECIFIED) + BOOST_LOG_TRIVIAL(error) << "Error: ssr_input_antenna_offset has not been set in config.\n"; + + if (ephType == +E_Source::SSR && offsetType == +E_OffsetType::APC && acsConfig.ssr_input_antenna_offset == +E_OffsetType::COM) antennaScalar = +1; + if (ephType == +E_Source::SSR && offsetType == +E_OffsetType::COM && acsConfig.ssr_input_antenna_offset == +E_OffsetType::APC) antennaScalar = -1; + if (ephType == +E_Source::PRECISE && offsetType == +E_OffsetType::APC) antennaScalar = +1; + if (ephType == +E_Source::KALMAN && offsetType == +E_OffsetType::APC) antennaScalar = +1; + if (ephType == +E_Source::REMOTE && offsetType == +E_OffsetType::APC) antennaScalar = +1; + if (ephType == +E_Source::BROADCAST && offsetType == +E_OffsetType::COM) antennaScalar = -1; - svh = geph.svh; - obsIode = geph.iode; + break; } - else if (sys == +E_Sys::SBS) + + // satellite antenna offset correction + if (antennaScalar) { - Seph* seph_ptr = seleph(trace, teph, Sat, -1, nav); - - if (seph_ptr == nullptr) - return 0; + if (satPos.satNav_ptr == nullptr) + { + BOOST_LOG_TRIVIAL(debug) << "Sat nav pointer undefined"; + return returnValue; + } - auto& seph = *seph_ptr; + auto& attStatus = satPos.satNav_ptr->attStatus; - seph2pos(time, seph, rSat, dtSat[0], &ephVar); - time = time + tt; seph2pos(time, seph, rSat_1, dtSat_1); + if ( attStatus.eXBody.isZero() + ||attStatus.eYBody.isZero() + ||attStatus.eZBody.isZero()) + { + BOOST_LOG_TRIVIAL(debug) << "Satellite attitude of " << satPos.Sat.id() << " not available, antenna offset not corrected."; + return returnValue; + } - svh = seph.svh; - } - else - return false; - - /* satellite velocity and clock drift by differential approx */ - satVel = (rSat_1 - rSat) / tt; - dtSat[1] = (dtSat_1 - dtSat[0]) / tt; - - return true; -} - -bool ephpos( - Trace& trace, - GTime time, - GTime teph, - Obs& obs, - Navigation& nav, - int iode, - bool applyRelativity = true) -{ - return ephpos( - trace, - time, - teph, - obs.Sat, - obs.rSat, - obs.satVel, - obs.dtSat, - obs.ephVar, - obs.svh, - obs.iode, - nav, - iode, - applyRelativity); -} - - -Matrix3d ecef2rac( - Vector3d& rSat, // Sat position (ECEF) - Vector3d& satVel) // Sat velocity (ECEF) -{ - // Ref: RTCM c10403.3, equation (3.12-5), p188 (this rotation matrix performs RAC->ECEF, so ECEF->RAC is simply the transpose of this) - Vector3d ea = satVel.normalized(); - Vector3d rv = rSat.cross(satVel); Vector3d ec = rv.normalized(); - Vector3d er = ea.cross(ec); - - Matrix3d Rt; - Rt.row(0) = er; - Rt.row(1) = ea; - Rt.row(2) = ec; + E_FType j; + E_FType k; + E_Sys sys = satPos.Sat.sys; + switch (sys) + { + case E_Sys::GPS: j = F1; k = (acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) ? F5 : F2; break; + case E_Sys::GLO: j = G1; k = G2; break; + case E_Sys::GAL: j = F1; k = F5; break; + case E_Sys::BDS: j = B1; k = B3; break; + case E_Sys::QZS: j = F1; k = F2; break; + case E_Sys::SBS: j = F1; k = F5; break; + default: return false; + } + + if ( satPos.satNav_ptr->lamMap.empty() + ||satPos.satNav_ptr->lamMap[j] == 0 + ||satPos.satNav_ptr->lamMap[k] == 0) + { + updatenav(satPos); // satAntOff() requries lamMap + } - return Rt; -} + Vector3d dAnt = Vector3d::Zero(); + if (acsConfig.common_sat_pco) dAnt = satAntOff(trace, time, attStatus, satPos.Sat, j); + else dAnt = satAntOff(trace, time, attStatus, satPos.Sat, nav.satNavMap[satPos.Sat].lamMap); -Matrix3d rac2ecef( - Vector3d& rSat, // Sat position (ECEF) - Vector3d& satVel) // Sat velocity (ECEF) -{ - Matrix3d ecef2racMat = ecef2rac(rSat, satVel); + satPos.rSat += dAnt * antennaScalar; + } - return ecef2racMat.transpose(); -} - - -double relativity1( - Vector3d& rSat, - Vector3d& satVel) -{ - return 2 * rSat.dot(satVel) / CLIGHT / CLIGHT; + return returnValue; } -bool ssrPosDelta( - GTime time, - const SSRMaps& ssrMaps, - Vector3d& dPos, - int& iodPos, - int& iodEph) +void adjustRelativity( + SatPos& satPos, + E_Relativity applyRelativity) { - //get 'price is right' closest ssr components to ephemeris time. - auto ephIt = ssrMaps.ssrEph_map.lower_bound(time); - if (ephIt == ssrMaps.ssrEph_map.end()) - { - return false; - } + E_Relativity clockHasRelativity; - auto& [t_e, ssrEph] = *ephIt; - - iodPos = ssrEph.iod; - iodEph = ssrEph.iode; - - double tEph = time - ssrEph.t0; - - /* ssr orbit and clock correction (ref [4]) */ - if (fabs(tEph) > ssrEph.udi * acsConfig.validity_interval_factor) - { - tracepdeex(2, std::cout, "age of ssr error: %s t=%.0f > %.0f\n",time.to_string(0).c_str(), tEph, ssrEph.udi * acsConfig.validity_interval_factor); - return false; - } + if (satPos.clkSource == +E_Source::BROADCAST && satPos.Sat.sys == +E_Sys::GLO) clockHasRelativity = E_Relativity::ON; + else clockHasRelativity = E_Relativity::OFF; - if (ssrEph.udi >= 1) - tEph -= ssrEph.udi / 2; - - for (int i = 0; i < 3; i++) - { - dPos[i] = ssrEph.deph [i] - + ssrEph.ddeph[i] * tEph; - } - - if (dPos.norm() > MAXECORSSR) + if (clockHasRelativity == applyRelativity) { - tracepdeex(2, std::cout,"invalid ssr correction: %s deph=%.1f\n", time.to_string(0).c_str(), dPos.norm()); - return false; - } - - return true; -} - -bool ssrClkDelta( - GTime time, - const SSRMaps& ssrMaps, - double& dclk, - int& iodClk) -{ - //get 'price is right' closest ssr components to ephemeris time. - auto clkIt = ssrMaps.ssrClk_map.lower_bound(time); - if (clkIt == ssrMaps.ssrClk_map.end()) - { - return false; + return; } - auto& [t_c, ssrClk] = *clkIt; + double scalar = 0; - iodClk = ssrClk.iod; + if (clockHasRelativity == +E_Relativity::ON && applyRelativity == +E_Relativity::OFF) scalar = -1; + else if (clockHasRelativity == +E_Relativity::OFF && applyRelativity == +E_Relativity::ON) scalar = +1; - double tClk = time - ssrClk.t0; + satPos.satClk -= scalar * relativity1(satPos.rSat, satPos.satVel); +} - /* ssr orbit and clock correction (ref [4]) */ - if (fabs(tClk) > ssrClk.udi * acsConfig.validity_interval_factor) - { -// trace(2,"age of ssr error: %s sat=%2d t=%.0f %.0f\n", time.to_string(0).c_str(), obs.Sat,t1,t2); +/** satellite positions and clocks. +* satellite position and clock are values at signal transmission time. +* satellite clock does not include code bias correction (tgd or bgd). +* any pseudorange and broadcast ephemeris are always needed to get signal transmission time. +*/ +bool satPosClk( + Trace& trace, ///< Trace to output to + GTime teph, ///< time to select ephemeris (gpst) + GObs& obs, ///< observations to complete with satellite positions + Navigation& nav, ///< Navigation data + vector posSources, ///< Source of ephemeris data + vector clkSources, ///< Source of ephemeris data + E_OffsetType offsetType, ///< Point of satellite to output position of + E_Relativity applyRelativity, ///< Option to apply relativistic correction to clock + const KFState* kfState_ptr) ///< Optional pointer to a kalman filter to take values from +{ + tracepdeex(3, trace, "\n%-10s: teph=%s %s", __FUNCTION__, teph.to_string(3).c_str(), obs.Sat.id()); + + if (obs.exclude) + { + obs.failureExclude = true; + return false; } - - if (ssrClk.udi >= 1) - tClk -= ssrClk.udi / 2; - dclk = ssrClk.dclk[0] - + ssrClk.dclk[1] * tClk - + ssrClk.dclk[2] * tClk * tClk; + double pr = 0; - /* ssr highrate clock correction (ref [4]) */ - auto hrcIt = ssrMaps.ssrHRClk_map.lower_bound(time); - if (hrcIt != ssrMaps.ssrHRClk_map.end()) + for (auto& [a, sig] : obs.Sigs) { - auto& [t_h, ssrHrc] = *hrcIt; + if (sig.P == 0) + continue; - double tHrc = time - ssrHrc.t0; + pr = sig.P; - if ( ssrClk.iod == ssrHrc.iod - && fabs(tHrc) < ssrClk.udi * acsConfig.validity_interval_factor) - { - dclk += ssrHrc.hrclk; - } + break; } - - if (fabs(dclk) > MAXCCORSSR) - { -// trace(3,"invalid ssr correction: %s dclk=%.1f\n", time.to_string(0).c_str(), dclk); - return 0; - } - - return true; -} - -/* satellite position and clock with ssr correction --------------------------*/ -bool satpos_ssr( - Trace& trace, - GTime time, - GTime teph, - Navigation& nav, - SSRMaps& ssrMaps, - SatSys& Sat, - Vector3d& rSat, - Vector3d& satVel, - double* dtSat, - E_Svh& svh, - int& obsIode, - double& ephVar, - bool applyRelativity = true) -{ -// tracepdeex(4,trace, __FUNCTION__ ": time=%s sat=%2d\n",time.to_string(3).c_str(),obs.Sat); - svh = SVH_UNHEALTHY; - - int iodPos; - int iodEph; - int iodClk; - Vector3d dPos; - double dClk; - bool posDeltaPass = ssrPosDelta(time, ssrMaps, dPos, iodPos, iodEph); - bool clkDeltaPass = ssrClkDelta(time, ssrMaps, dClk, iodClk); - if ( posDeltaPass == false - || clkDeltaPass == false) - { - return false; - } - - if (iodClk != iodPos) - { - BOOST_LOG_TRIVIAL(error) << "Error: IOD inconsistent." << iodClk << " " << iodPos; -// std::cout << "Bad SSR Delta function" << std::endl; - return false; - } - - /* satellite postion and clock by broadcast ephemeris */ - bool pass = ephpos(trace, time, teph, Sat, rSat, satVel, dtSat, ephVar, svh, obsIode, nav, iodEph); - if (pass == false) - { - svh = SVH_UNHEALTHY; - return false; - } - - /* satellite clock for gps, galileo and qzss */ - int sys = Sat.sys; - - if ( sys == +E_Sys::GPS - || sys == +E_Sys::GAL - || sys == +E_Sys::QZS - || sys == +E_Sys::BDS) + if (pr == 0) { - Eph* eph = seleph(trace, teph, Sat, iodEph, nav); - - if (eph == nullptr) - { - return false; - } - - /* satellite clock by clock parameters */ - double tk = time - eph->toc; + obs.failureNoPseudorange = true; - dtSat[0] = eph->f0 - + eph->f1 * tk - + eph->f2 * tk * tk; - - dtSat[1] = eph->f1 - + eph->f2 * tk * 2; + tracepdeex(2, trace, "\nno pseudorange %s sat=%s", obs.time.to_string(3).c_str(), obs.Sat.id().c_str()); + return false; } - Matrix3d rac2ecefMat = rac2ecef(rSat, satVel); + obs.tof = pr / CLIGHT; - Vector3d dPosECEF = rac2ecefMat * dPos; + // transmission time by satellite clock + GTime time = obs.time; - rSat -= dPosECEF; - - /* t_corr = t_sv - (dtSat(brdc) + dClk(ssr) / CLIGHT) (ref [10] eq.3.12-7) */ - dtSat[0] += dClk / CLIGHT; - - /* variance by ssr ura */ - double ura = -1; + time -= obs.tof; - auto uraIt = ssrMaps.ssrUra_map.lower_bound(time); - if (uraIt != ssrMaps.ssrUra_map.end()) - { - auto& [t_u, ssrUra] = *uraIt; - - ura = ssrUra.ura; - } + bool pass; - ephVar = var_urassr(ura); - - /* relativity correction */ - if (applyRelativity) - { - dtSat[0] -= relativity1(rSat, satVel); - } + pass = satclk(trace, time, teph, obs, clkSources, nav, kfState_ptr); - tracepdeex(5, trace, "%s: %s sat=%2d deph=%6.3f %6.3f %6.3f dclk=%6.3f var=%6.3f\n", - __FUNCTION__, time.to_string(2).c_str(), Sat, dPos[0], dPos[1], dPos[2], dClk, ephVar); - - svh = SVH_OK; - return true; -} - -bool satpos_ssr( - Trace& trace, - GTime time, - GTime teph, - Obs& obs, - Navigation& nav, - bool applyRelativity = true) -{ - return satpos_ssr( - trace, - time, - teph, - nav, - obs.satNav_ptr->receivedSSR, - obs.Sat, - obs.rSat, - obs.satVel, - obs.dtSat, - obs.svh, - obs.iode, - obs.ephVar, - applyRelativity); -} - -bool kalmanPos( - Trace& trace, - GTime time, - SatSys Sat, - Obs& obs, - KFState* kfState_ptr) -{ - if (kfState_ptr == nullptr) + if (pass == false) { + obs.failureNoSatClock = true; + + tracepdeex(2, trace, "\nno satellite clock %s sat=%s", time.to_string(3).c_str(), obs.Sat.id().c_str()); return false; } - - auto& kfState = *kfState_ptr; - - bool pass = true; - - for (short int i = 0; i < 3; i++) - { - pass &= kfState.getKFValue(KFKey{.type = KF::SAT_POS, .Sat = Sat, .num = i}, obs.rSat[i]); - pass &= kfState.getKFValue(KFKey{.type = KF::SAT_POS_RATE, .Sat = Sat, .num = i}, obs.satVel[i]); - } - - return pass; -} - -/* satellite position and clock ------------------------------------------------ -* compute satellite position, velocity and clock -* return : status (1:ok,0:error) -* satellite clock does not include code bias correction (tgd or bgd) -*-----------------------------------------------------------------------------*/ -int satpos( - Trace& trace, ///< Trace to output to - GTime time, ///< time (gpst) - GTime teph, ///< time to select ephemeris (gpst) - Obs& obs, ///< Observation to determine satellite etc, and store answers - E_Ephemeris ephType, ///< Source of ephemeris - E_OffsetType offsetType, ///< Type of antenna offset to apply - Navigation& nav, ///< navigation data - bool applyRelativity, ///< Apply relativity - KFState* kfState_ptr) ///< Optional pointer to a kalman filter to take values from -{ - tracepdeex(4, trace, "%s: time=%s sat=%s ephType=%d offsetType=%d\n", __FUNCTION__, time.to_string(3).c_str(), obs.Sat.id().c_str(), ephType, offsetType); - - obs.svh = SVH_UNHEALTHY; - int returnValue = 0; - switch (ephType) - { - case E_Ephemeris::BROADCAST: returnValue = ephpos (trace, time, teph, obs, nav, ANY_IODE, applyRelativity); break; - case E_Ephemeris::SSR: returnValue = satpos_ssr (trace, time, teph, obs, nav, applyRelativity); break; - case E_Ephemeris::PRECISE: returnValue = peph2pos (trace, time, obs.Sat, obs, nav, applyRelativity); break; - case E_Ephemeris::KALMAN: returnValue = kalmanPos (trace, time, obs.Sat, obs, kfState_ptr); break; - default: return false; - } + tracepdeex(5, trace, "\neph time %s %s pr=%.5f, satClk= %.5f", obs.Sat.id().c_str(), time.to_string(3).c_str(), pr / CLIGHT, obs.satClk); - if (ephType == +E_Ephemeris::SSR && acsConfig.ssr_input_antenna_offset == +E_OffsetType::UNSPECIFIED) - BOOST_LOG_TRIVIAL(error) << "Error: ssr_input_antenna_offset has not been set in config."; + time -= obs.satClk; - double antennaScalar = 0; - - if (ephType == +E_Ephemeris::SSR && offsetType == +E_OffsetType::APC && acsConfig.ssr_input_antenna_offset == +E_OffsetType::COM) antennaScalar = +1; - if (ephType == +E_Ephemeris::SSR && offsetType == +E_OffsetType::COM && acsConfig.ssr_input_antenna_offset == +E_OffsetType::APC) antennaScalar = -1; - if (ephType == +E_Ephemeris::PRECISE && offsetType == +E_OffsetType::APC) antennaScalar = +1; - if (ephType == +E_Ephemeris::KALMAN && offsetType == +E_OffsetType::APC) antennaScalar = +1; - if (ephType == +E_Ephemeris::BROADCAST && offsetType == +E_OffsetType::COM) antennaScalar = -1; + // satellite position and clock at transmission time + pass = satpos(trace, time, teph, obs, posSources, offsetType, nav, kfState_ptr); - /* satellite antenna offset correction */ - if (antennaScalar) + if (pass == false) { - Vector3d dAnt = Vector3d::Zero(); + obs.failureNoSatPos = true; - if (acsConfig.if_antenna_phase_centre) - satAntOff(trace, time, obs.rSat, obs.Sat, nav.satNavMap[obs.Sat].lamMap, dAnt, obs.satStat_ptr); - else - dAnt=satAntOff(trace, time, obs.rSat, obs.Sat, F1, obs.satStat_ptr); + tracepdeex(3, trace, "\n%s failed (no ephemeris?) %s sat=%s", __FUNCTION__, time.to_string(3).c_str(), obs.Sat.id().c_str()); - obs.rSat += dAnt * antennaScalar; + return false; } - return returnValue; -} - -/** satellite positions and clocks. - * satellite position and clock are values at signal transmission time. - * satellite clock does not include code bias correction (tgd or bgd). - * any pseudorange and broadcast ephemeris are always needed to get signal transmission time. - */ -void satposs( - Trace& trace, ///< Trace to output to - GTime teph, ///< time to select ephemeris (gpst) - ObsList& obsList, ///< List of observations to complete with satellite positions - Navigation& nav, ///< Navigation data - E_Ephemeris ephType, ///< Source of ephemeris data - E_OffsetType offsetType, ///< Point of satellite to output position of - bool applyRelativity, ///< Option to apply relativistic correction to clock - bool applyFlightTime) ///< Option to apply offset due to flight time of light signal -{ - TestStack ts(__FUNCTION__); - - tracepdeex(3, trace, "%s: teph=%s n=%d ephType=%d\n", __FUNCTION__, teph.to_string(3).c_str(), obsList.size(), ephType); - - for (auto& obs : obsList) - { - if (obs.exclude) - { - continue; - } - - /* search any pseudorange */ - if (obs.Sigs.empty()) - { - tracepdeex(2, trace, "no pseudorange %s sat=%s\n", obs.time.to_string(3).c_str(), obs.Sat.id().c_str()); - continue; - } - - double pr = 0; - - if (applyFlightTime) - for (auto& [a, sig] : obs.Sigs) - { - pr = sig.P; - break; - } - - /* transmission time by satellite clock */ - GTime time = obs.time - pr / CLIGHT; - - // satellite clock bias by precise/broadcast ephemeris - double dt; - double tvar; - bool pass = false; - int ret = pephclk(time, obs.Sat.id(), nav, dt, &tvar); - - if (ret > 0) - pass = true; - else - pass = ephclk(time, teph, obs, dt); - - if (pass == false) - { - tracepdeex(2, trace, "no satellite clock %s sat=%s\n", time.to_string(3).c_str(), obs.Sat.id().c_str()); - continue; - } - - time = time - dt; - - /* satellite position and clock at transmission time */ - pass = satpos(trace, time, teph, obs, ephType, offsetType, nav, applyRelativity); - - if (pass == false) - { - tracepdeex(3, trace, "satpos failed (no ephemeris?) %s sat=%s\n", time.to_string(3).c_str(), obs.Sat.id().c_str()); - - continue; - } - - /* if no precise clock available, use broadcast clock instead */ - if (obs.dtSat[0] == 0) - { - pass = ephclk(time, teph, obs, obs.dtSat[0]); - - if (pass == false) - { - continue; - } - - obs.dtSat[1] = 0; - obs.ephVar = SQR(STD_BRDCCLK); - } - } - - for (auto& obs : obsList) - { - if (obs.exclude) - { - continue; - } - - TestStack ts(obs.Sat); - - tracepdeex(4, trace, "%s sat=%s rs=%13.3f %13.3f %13.3f dtSat=%12.3f var=%7.3f svh=%02X\n", - obs.time.to_string(6).c_str(), - obs.Sat.id().c_str(), - obs.rSat[0], - obs.rSat[1], - obs.rSat[2], - obs.dtSat[0] * 1E9, - obs.ephVar, - obs.svh); - - TestStack::testMat("obs.rSat", obs.rSat); - } + adjustRelativity(obs, applyRelativity); + + tracepdeex(4, trace, "\n%s sat=%s rs=%13.3f %13.3f %13.3f dtSat=%12.3f var=%7.3f ephPosValid=%1X %s ephClkValid=%1X %s", + obs.time.to_string(6).c_str(), + obs.Sat.id().c_str(), + obs.rSat[0], + obs.rSat[1], + obs.rSat[2], + obs.satClk * 1E9, + obs.satClkVar, + obs.ephPosValid, + obs.posSource._to_string(), + obs.ephClkValid, + obs.clkSource._to_string()); + + return true; } - - -#if (0) -/* satellite position and clock with sbas correction -------------------------*/ -// int satpos_sbas(gtime_t time, gtime_t teph, SatSys Sat, const nav_t* nav, -// double* rs, double* dtSat, double* var, int* svh) -// { -// const sbssatp_t* sbs; -// int i; -// -// trace(4, __FUNCTION__ ": time=%s sat=%2d\n", time.to_string(3).c_str(), Sat); -// -// /* search sbas satellite correciton */ -// for (i = 0; i < nav->sbssat.nsat; i++) -// { -// sbs = nav->sbssat.sat + i; -// -// if (sbs->Sat == Sat) -// break; -// } -// -// if (i >= nav->sbssat.nsat) -// { -// trace(2, "no sbas correction for orbit: %s sat=%2d\n", time.to_string(0).c_str(), Sat); -// ephpos(time, teph, Sat, nav, -1, rs, dts, var, svh); -// *svh = -1; -// -// return 0; -// } -// -// /* satellite postion and clock by broadcast ephemeris */ -// if (!ephpos(time, teph, Sat, nav, sbs->lcorr.iode, rs, dts, var, svh)) -// return 0; -// -// /* sbas satellite correction (long term and fast) */ -// if (sbssatcorr(time, Sat, nav, rs, dts, var)) -// return 1; -// -// *svh = -1; -// -// return 0; -// } -#endif diff --git a/src/cpp/common/ephemeris.hpp b/src/cpp/common/ephemeris.hpp index c790851dc..649a8f467 100644 --- a/src/cpp/common/ephemeris.hpp +++ b/src/cpp/common/ephemeris.hpp @@ -1,85 +1,126 @@ -#ifndef __EPHEMERIS_HPP__ -#define __EPHEMERIS_HPP__ +#pragma once -#include - #include "eigenIncluder.hpp" #include "observations.hpp" -#include "streamTrace.hpp" #include "constants.hpp" -#include "antenna.hpp" #include "satSys.hpp" #include "gTime.hpp" +#include "trace.hpp" #include "enums.h" #include #include -#include +#include +#include using std::string; -using std::list; +using std::vector; using std::map; //forward declarations struct Navigation; -struct Obs; +struct GObs; struct Peph; -#define ANY_IODE -1 +#define ANY_IODE -1 +#define NO_SP3_CLK 999999.999999 +#define INVALID_CLOCK_VALUE NO_SP3_CLK + +struct KeplerEph +{ + double A = 0; ///< semi major axis + double e = 0; ///< eccentricity + double i0 = 0; ///< inclination + double OMG0 = 0; ///< right ascension of ascending node + double omg = 0; ///< argument of perigee + double M0 = 0; ///< mean anomoly + double deln = 0; ///< correction mean motion + double OMGd = 0; ///< rate of OMG + double idot = 0; ///< rate of inclination + double crc = 0; ///< correction radial cosine + double crs = 0; ///< correction radial sine + double cuc = 0; ///< correction lattitude cosine + double cus = 0; ///< correction lattitude sine + double cic = 0; ///< correction inclination cosine + double cis = 0; ///< correction inclination sine + double dn0d = 0; ///< rate of correction mean motion + double Adot = 0; ///< rate of A +}; + +struct BrdcEph +{ + +}; /** GPS/QZS/GAL/BDS broadcast ephemeris */ -struct Eph +struct Eph : BrdcEph, KeplerEph { E_NavMsgType type = E_NavMsgType::NONE; ///< message type SatSys Sat; ///< satellite number - int iode; ///< IODE + int iode; ///< GPS/QZS: IODE, GAL: IODnav int iodc; ///< IODC + int aode; ///< BDS AODE + int aodc; ///< BDS AODC int sva; ///< SV accuracy (URA index) E_Svh svh; ///< SV health - int week; ///< GPS/QZS: gps week, GAL: galileo week - int code; ///< GPS/QZS: code on L2, GAL/CMP: data sources - int flag; ///< GPS/QZS: L2 P data flag, CMP: nav type + int week; ///< GPS/QZS: gps week, GAL:gps week (i.e. galileo week + 1024), BDS: beidou week + int code; ///< GPS/QZS: code on L2, GAL: data source + int flag; ///< GPS L2 P data flag GTime toc; ///< time of clock GTime toe; ///< time of ephemeris GTime ttm; ///< transmission time - - double A; ///< semi major axis - double e; ///< eccentricity - double i0; ///< inclination - double OMG0; ///< right ascension of ascending node - double omg; ///< argument of perigee - double M0; ///< mean anomoly - double deln; ///< correction mean motion - double OMGd; ///< rate of OMG - double idot; ///< rate of inclination - double crc; ///< correction radial cosine - double crs; ///< correction radial sine - double cuc; ///< correction lattitude cosine - double cus; ///< correction lattitude sine - double cic; ///< correction inclination cosine - double cis; ///< correction inclination sine double toes; ///< TOE (s) in week double fit; ///< fit interval (h) - double f0; ///< SV clock parameter (af0) - double f1; ///< SV clock parameter (af1) - double f2; ///< SV clock parameter (af2) - double tgd[4]; ///< group delay parameters - ///< GPS/QZS:tgd[0]=TGD - ///< GAL :tgd[0]=BGD E5a/E1,tgd[1]=BGD E5b/E1 - ///< CMP :tgd[0]=BGD1,tgd[1]=BGD2 + double f0; ///< SV clock parameter (af0) + double f1; ///< SV clock parameter (af1) + double f2; ///< SV clock parameter (af2) + double tgd[4] = {}; ///< group delay parameters + ///< GPS/QZS:tgd[0]=TGD + ///< GAL :tgd[0]=BGD E5a/E1,tgd[1]=BGD E5b/E1 + ///< BDS :tgd[0]=BGD1,tgd[1]=BGD2 + + E_SatType orb = E_SatType::NONE; ///< BDS sat/orbit type + GTime top = {}; ///< time of prediction + double tops = 0; ///< t_op (s) in week + double ura[4] = {}; ///< user range accuracy or GAL SISA + ///< GPS/QZS CNVX: ura[0]=URAI_NED0, ura[1]=URAI_NED1, ura[2]=URAI_NED2, ura[3]=URAI_ED + double isc[6] = {}; ///< inter-signal corrections + ///< GPS/QZS CNAV: isc[0]=ISC_L1CA, isc[1]=ISC_L2C, isc[2]=ISC_L5I5, isc[3]=ISC_L5Q5 + ///< GPS/QZS CNV2: isc[0]=ISC_L1CA, isc[1]=ISC_L2C, isc[2]=ISC_L5I5, isc[3]=ISC_L5Q5, isc[4]=ISC_L1Cd, isc[5]=ISC_L1Cp + ///< BDS CNV1: isc[0]=ISC_B1Cd + ///< BDS CNV2: isc[1]=ISC_B2ad + double sis[5] = {}; ///< signal in space accuracy index + ///< BDS CNVX sis[0]=SISAI_oe, sis[1]=SISAI_ocb, sis[2]=SISAI_oc1, sis[3]=SISAI_oc2, sis[4]=SISMAI + + + // original messages from stream/rinex for debugging + double tocs; ///< TOC (s) within week + int weekRollOver; ///< week number (rolled over) + double sqrtA; ///< sqrt A + int e5a_hs = 0; ///< GAL E5a signal health status + int e5a_dvs = 0; ///< GAL E5a data validity status + int e5b_hs = 0; ///< GAL E5b signal health status + int e5b_dvs = 0; ///< GAL E5b data validity status + int e1_hs = 0; ///< GAL E1 signal health status + int e1_dvs = 0; ///< GAL E1 data validity status + double ttms; ///< transmission time (s) within week + int fitFlag; ///< fit flag + template void serialize(ARCHIVE& ar, const unsigned int& version) { ar & iode; ar & iodc; + ar & aode; + ar & aodc; ar & sva; ar & svh; ar & week; @@ -118,7 +159,7 @@ struct Eph /** GLONASS broadcast ephemeris */ -struct Geph +struct Geph : BrdcEph { E_NavMsgType type = E_NavMsgType::NONE; ///< message type SatSys Sat; ///< satellite number @@ -132,40 +173,59 @@ struct Geph Vector3d pos; ///< satellite position (ecef) (m) Vector3d vel; ///< satellite velocity (ecef) (m/s) Vector3d acc; ///< satellite acceleration (ecef) (m/s^2) - double taun,gamn; ///< SV clock bias (s)/relative freq bias + double taun; ///< SV clock bias (s) + double gammaN; ///< SV relative freq bias double dtaun; ///< delay between L1 and L2 (s) + + + // original messages from stream/rinex for debugging + double tofs; ///< TOF (s) within the current day + int tk_hour; ///< number of hours of TOF + int tk_min; ///< number of minutes of TOF + double tk_sec; ///< seconds of TOF + int tb; ///< number of 15 min of TOE + int glonassM; ///< type of GLO satellites + int NT; ///< calender number of day within 4-year interval + bool moreData; ///< availability of additional data + int N4; ///< 4-year interval number }; /** precise clock */ struct Pclk { - double clk; ///< satellite clock (s) - double std; ///< satellite clock std (s) - GTime time; ///< time (GPST) - int index; ///< clock index for multiple files + double clk = INVALID_CLOCK_VALUE; ///< satellite clock (s) + double clkStd = 0; ///< satellite clock std (s) + int clkIndex; ///< clock index for multiple files }; /** precise ephemeris */ -struct Peph +struct Peph : Pclk { SatSys Sat; ///< satellite number GTime time; ///< time (GPST) int index; ///< ephemeris index for multiple files - Vector3d Pos = Vector3d::Zero(); ///< satellite position (ecef) (m) - Vector3d PosStd = Vector3d::Zero(); ///< satellite position std (m) - Vector3d Vel = Vector3d::Zero(); ///< satellite velocity/clk-rate (m/s) - Vector3d VelStd = Vector3d::Zero(); ///< satellite velocity/clk-rate std (m/s) - double Clk = 0; - double ClkStd = 0; - double dCk = 0; - double dCkStd = 0; + VectorEcef pos; ///< satellite position (m) + Vector3d posStd = Vector3d::Zero(); ///< satellite position std (m) + VectorEcef vel; ///< satellite velocity/clk-rate (m/s) + Vector3d velStd = Vector3d::Zero(); ///< satellite velocity/clk-rate std (m/s) +}; + +/** Satellite attitude + */ +struct Att +{ + SatSys Sat; ///< satellite number + GTime time; ///< time (GPST) + int index; ///< ephemeris index for multiple files + E_ObxFrame frame; + Quaterniond q = Eigen::Quaterniond::Identity(); ///< satellite attitude represented w/ a quaternion }; /** SBAS ephemeris */ -struct Seph +struct Seph : BrdcEph { E_NavMsgType type = E_NavMsgType::NONE; ///< message type SatSys Sat; ///< satellite number @@ -173,18 +233,18 @@ struct Seph GTime tof; ///< time of message frame (GPST) int sva; ///< SV accuracy (URA index) E_Svh svh; ///< SV health - Vector3d pos; ///< satellite position (m) (ecef) - Vector3d vel; ///< satellite velocity (m/s) (ecef) - Vector3d acc; ///< satellite acceleration (m/s^2) (ecef) - double af0,af1; ///< satellite clock-offset/drift (s,s/s) - + VectorEcef pos; ///< satellite position (m) (ecef) + VectorEcef vel; ///< satellite velocity (m/s) (ecef) + VectorEcef acc; ///< satellite acceleration (m/s^2) (ecef) + double af0 = 0; ///< satellite clock-offset/drift (s) + double af1 = 0; ///< satellite clock-drift (s/s) int iode = 0; //unused, for templating only - int toe = 0; //unused, for templating only + GTime toe; //unused, for templating only }; /** GPS/QZS CNAV/CNAV-2 or BDS CNAV-1/CNAV-2/CNAV-3 ephemeris */ -struct Ceph +struct Ceph : KeplerEph { E_NavMsgType type = E_NavMsgType::NONE; ///< message type E_SatType orb = E_SatType::NONE; ///< BDS sat/orbit type @@ -199,25 +259,6 @@ struct Ceph GTime top = {}; ///< time of prediction GTime ttm = {}; ///< transmission time - - double A = 0; ///< semi major axis - double Adot = 0; ///< rate of A - double e = 0; ///< eccentricity - double i0 = 0; ///< inclination - double OMG0 = 0; ///< right ascension of ascending node - double omg = 0; ///< argument of perigee - double M0 = 0; ///< mean anomoly - double deln = 0; ///< correction mean motion - double dn0d = 0; ///< rate of correction mean motion - double OMGd = 0; ///< rate of OMG - double idot = 0; ///< rate of inclination - double crc = 0; ///< correction radial cosine - double crs = 0; ///< correction radial sine - double cuc = 0; ///< correction lattitude cosine - double cus = 0; ///< correction lattitude sine - double cic = 0; ///< correction inclination cosine - double cis = 0; ///< correction inclination sine - double ura[4] = {}; ///< user range accuracy ///< GPS/QZS: ura[0]=URAI_NED0, ura[1]=URAI_NED1, ura[2]=URAI_NED2, ura[3]=URAI_ED double isc[6] = {}; ///< inter-signal corrections @@ -325,140 +366,164 @@ struct ION struct Navigation; +Matrix3d ecef2rac( + Vector3d& rSat, + Vector3d& satVel); -template -EPHTYPE* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - Navigation& nav); -template<> -Eph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - Navigation& nav); +void cullOldEphs( + GTime time); -template<> -Geph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - Navigation& nav); +void cullOldSSRs( + GTime time); -template<> -Seph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - int iode, - Navigation& nav); -template -EPHTYPE* seleph( - Trace& trace, - GTime time, - SatSys Sat, - E_NavMsgType type, - int iode, - Navigation& nav); +struct KFState; -template<> -Ceph* seleph( - Trace& trace, - GTime time, - SatSys Sat, - E_NavMsgType type, - int iode, - Navigation& nav); -template -EPHTYPE* seleph( - Trace& trace, - GTime time, - E_Sys sys, - E_NavMsgType type, - Navigation& nav); +template TYPE* seleph(Trace& trace, GTime time, SatSys Sat, E_NavMsgType type, int iode, Navigation& nav); +template TYPE* seleph(Trace& trace, GTime time, E_Sys sys, E_NavMsgType type, Navigation& nav); + + +bool satclk( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + vector ephTypes, + Navigation& nav, + const KFState* kfState_ptr = nullptr); + +bool satpos( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + vector ephTypes, + E_OffsetType offsetType, + Navigation& nav, + const KFState* kfState_ptr = nullptr); + +bool satPosClk( + Trace& trace, + GTime teph, + GObs& obs, + Navigation& nav, + vector posSources, + vector clkSources, + E_OffsetType offsetType = E_OffsetType::COM, + E_Relativity applyRelativity = E_Relativity::ON, + const KFState* kfState_ptr = nullptr); -template<> -ION* seleph( - Trace& trace, - GTime time, - E_Sys sys, - E_NavMsgType type, +void readSp3ToNav( + string& file, + Navigation* nav, + int opt); + +bool readsp3( + std::istream& fileStream, + vector& pephList, + int opt, + E_TimeSys& tsys, + double* bfact); + +void orb2sp3( + Navigation& nav); + +void readOrbex( + string filepath, Navigation& nav); -template<> -EOP* seleph( + +bool satPosKalman( Trace& trace, - GTime time, - E_Sys sys, - E_NavMsgType type, - Navigation& nav); + GTime time, + SatPos& satPos, + const KFState* kfState_ptr); +bool satClkKalman( + Trace& trace, + GTime time, + SatPos& satPos, + const KFState* kfState_ptr); -Vector3d ecef2rac( - Vector3d& vecToRotate, - Vector3d& r, - Vector3d& v); -Matrix3d ecef2rac( - Vector3d& rSat, - Vector3d& satVel); +bool satPosRemote( + Trace& trace, + GTime time, + SatPos& satPos); +bool satClkRemote( + Trace& trace, + GTime time, + SatPos& satPos); -void cullOldEphs( - GTime time); -void cullOldSSRs( - GTime time); +bool satClkBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatSys Sat, + double& satClk, + double& satClkVel, + double& ephVar, + bool& ephClkValid, + int& obsIode, + Navigation& nav); +bool satPosBroadcast( + Trace& trace, + GTime time, + GTime teph, + SatSys Sat, + Vector3d& rSat, + Vector3d& satVel, + double& ephVar, + bool& ephPosValid, + int& obsIode, + Navigation& nav); -struct KFState; -int satpos( +bool satClkBroadcast( Trace& trace, GTime time, GTime teph, - Obs& obs, - E_Ephemeris ephType, - E_OffsetType offsetType, + SatPos& satPos, Navigation& nav, - bool applyRelativity = true, - KFState* kfState_ptr = nullptr); + int iode = ANY_IODE); -void satposs( +bool satPosBroadcast( Trace& trace, + GTime time, GTime teph, - ObsList& obsList, + SatPos& satPos, Navigation& nav, - E_Ephemeris ephType, - E_OffsetType offsetType = E_OffsetType::COM, - bool applyRelativity = true, - bool applyFlightTime = true); + int iode = ANY_IODE); -void readSp3ToNav( - string& file, - Navigation* nav, - int opt); -bool readsp3( - std::istream& fileStream, - list& pephList, - int opt, - bool& isUTC, - double* bfact); +bool satPosPrecise( + Trace& trace, + GTime time, + SatPos& satPos, + Navigation& nav); -double interppol( - const double* x, - double* y, - int n); +bool satClkPrecise( + Trace& trace, + GTime time, + SatPos& satPos, + Navigation& nav); -void orb2sp3( - Navigation& nav); -#endif +bool satPosSSR( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + Navigation& nav); + +bool satClkSSR( + Trace& trace, + GTime time, + GTime teph, + SatPos& satPos, + Navigation& nav); diff --git a/src/cpp/common/erp.cpp b/src/cpp/common/erp.cpp index 9d2156cab..804453633 100644 --- a/src/cpp/common/erp.cpp +++ b/src/cpp/common/erp.cpp @@ -11,31 +11,27 @@ using std::chrono::system_clock; using std::string; #include "peaCommitVersion.h" -#include "streamTrace.hpp" +#include "instrument.hpp" #include "navigation.hpp" #include "constants.hpp" #include "acsConfig.hpp" #include "algebra.hpp" #include "gTime.hpp" +#include "trace.hpp" #include "erp.hpp" /** read earth rotation parameters */ -int readerp( - string filename, ///< IGS ERP file (IGS ERP ver.2) +void readerp( + string filename, ///< IGS ERP file (IGS ERP ver.2) ERP& erp) ///< earth rotation parameters { - FILE* fp; - ERPData* erp_data; - -// trace(3,"%s: file=%s\n",__FUNCTION__, file); - std::ifstream filestream(filename); if (!filestream) { // trace(2,"erp file open error: file=%s\n",file); - return 0; + return; } while (filestream) @@ -44,46 +40,51 @@ int readerp( getline(filestream, line); - double v[14] = {}; - - if (sscanf(line.c_str(),"%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - v,v+1,v+2,v+3,v+4,v+5,v+6,v+7,v+8,v+9,v+10,v+11,v+12,v+13) < 5) + double v[14] = {}; + double mjdval = 0; + int found = sscanf(line.c_str(),"%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", + &mjdval,v+1,v+2,v+3,v+4,v+5,v+6,v+7,v+8,v+9,v+10,v+11,v+12,v+13); + if (found < 5) { continue; } + + MjDateUtc mjd; + mjd.val = mjdval; - ERPData erpData; + ERPValues erpv; - erpData.mjd = v[0]; - erpData.xp = v[1] * 1E-6*AS2R; - erpData.yp = v[2] * 1E-6*AS2R; - erpData.ut1_utc = v[3] * 1E-7; - erpData.lod = v[4] * 1E-7; - erpData.xpr = v[12] * 1E-6*AS2R; - erpData.ypr = v[13] * 1E-6*AS2R; + erpv.time = mjd; + erpv.xp = v[1] * 1E-6*AS2R; + erpv.yp = v[2] * 1E-6*AS2R; + erpv.ut1Utc = v[3] * 1E-7; + erpv.lod = v[4] * 1E-7; + erpv.xpr = v[12] * 1E-6*AS2R; + erpv.ypr = v[13] * 1E-6*AS2R; - erp.erpMap[erpData.mjd] = erpData; + erp.erpMap[erpv.time] = erpv; } - - return 1; } /** Get earth rotation parameter values */ -int geterp( +ERPValues geterp( ERP& erp, - double mjd, - ERPValues& erpv) + GTime time) { + Instrument instrument(__FUNCTION__); + + ERPValues erpv; + if (erp.erpMap.empty()) - return 0; + return erpv; //find two erps to interpolate between (may be duplicate) - ERPData* erp1_ptr; - ERPData* erp2_ptr; + ERPValues* erp1_ptr; + ERPValues* erp2_ptr; - auto it = erp.erpMap.lower_bound(mjd); + auto it = erp.erpMap.lower_bound(time); if (it == erp.erpMap.end()) { @@ -109,122 +110,32 @@ int geterp( erp1_ptr = &erp1; } - ERPData& erp1 = *erp1_ptr; - ERPData& erp2 = *erp2_ptr; + ERPValues& erp1 = *erp1_ptr; + ERPValues& erp2 = *erp2_ptr; //interpolate values between erps double a; - if (erp2.mjd == erp1.mjd) a = 0; - else a = (mjd - erp1.mjd) / (erp2.mjd - erp1.mjd); + if (erp2.time == erp1.time) a = 0; + else a = (time - erp1.time).to_double() + / (erp2.time - erp1.time).to_double(); - erpv.xp = (1-a) * erp1.xp + a * erp2.xp; - erpv.yp = (1-a) * erp1.yp + a * erp2.yp; - erpv.ut1_utc = (1-a) * erp1.ut1_utc + a * erp2.ut1_utc; - erpv.lod = (1-a) * erp1.lod + a * erp2.lod; + erpv.xp = (1-a) * erp1.xp + a * erp2.xp; + erpv.yp = (1-a) * erp1.yp + a * erp2.yp; + erpv.ut1Utc = (1-a) * erp1.ut1Utc + a * erp2.ut1Utc; + erpv.lod = (1-a) * erp1.lod + a * erp2.lod; - return 1; -} - -/** Get earth rotation parameter values - */ -int geterp( - ERP& erp, - GTime time, - ERPValues& erpv) -{ - const double ep[] = {2000, 1, 1, 12, 0, 0}; - double day; - -// trace(4,"geterp:\n"); - - double mjd = 51544.5 + (gpst2utc(time) - epoch2time(ep)) / 86400.0; //todo aaron, convert to function - - return geterp(erp, mjd, erpv); + return erpv; } -/* get earth rotation parameter values ----------------------------------------- -* get earth rotation parameter values -* args : erp_t *erp I earth rotation parameters -* double time I time (modified julian date) -* double *erpv O erp values {xp,yp,ut1_utc,lod} (rad,rad,s,s/d) -* return : status (1:ok,0:error) -*-----------------------------------------------------------------------------*/ -// int geterp_from_utc( -// const erp_t* erp, -// double leapSec, -// double mjd, -// double* erpv) -// { -// double day; -// -// // trace(4,"geterp:\n"); -// -// if (erp->n <= 0) -// return 0; -// -// if (mjd <= erp->data[0].mjd) -// { -// day = mjd-erp->data[0].mjd; -// -// erpv[0] = erp->data[0].xp + erp->data[0].xpr * day; -// erpv[1] = erp->data[0].yp + erp->data[0].ypr * day; -// erpv[2] = erp->data[0].ut1_utc - erp->data[0].lod * day; -// erpv[3] = erp->data[0].lod; -// erpv[4] = leapSec; -// -// return 1; -// } -// -// if (mjd >= erp->data[erp->n-1].mjd) -// { -// day = mjd-erp->data[erp->n-1].mjd; -// -// erpv[0] = erp->data[erp->n-1].xp + erp->data[erp->n-1].xpr * day; -// erpv[1] = erp->data[erp->n-1].yp + erp->data[erp->n-1].ypr * day; -// erpv[2] = erp->data[erp->n-1].ut1_utc - erp->data[erp->n-1].lod * day; -// erpv[3] = erp->data[erp->n-1].lod; -// erpv[4] = leapSec; -// -// return 1; -// } -// -// int i; -// int j = 0; -// int k = erp->n - 1; -// while (j < k-1) -// { -// i = (j+k) / 2; -// -// if (mjd < erp->data[i].mjd) -// k = i; -// else -// j = i; -// } -// -// double a; -// if (erp->data[j].mjd == erp->data[j+1].mjd) -// { -// a = 0.5; -// } -// else -// { -// a = (mjd - erp->data[j].mjd) / (erp->data[j+1].mjd - erp->data[j].mjd); -// } -// -// erpv[0] = (1-a) * erp->data[j].xp + a * erp->data[j+1].xp; -// erpv[1] = (1-a) * erp->data[j].yp + a * erp->data[j+1].yp; -// erpv[2] = (1-a) * erp->data[j].ut1_utc+ a * erp->data[j+1].ut1_utc; -// erpv[3] = (1-a) * erp->data[j].lod + a * erp->data[j+1].lod; -// erpv[4] = leapSec; -// -// return 1; -// } - void writeERP( string filename, - ERPData& erp, - GTime time) + ERPValues& erp) { + if (filename.empty()) + { + return; + } + std::ofstream erpStream(filename, std::ios::app); if (!erpStream) @@ -238,10 +149,8 @@ void writeERP( if (erpStream.tellp() == 0) { - // auto peaStopTime = boost::posix_time::from_time_t(system_clock::to_time_t(system_clock::now())); - erpStream << "VERSION 2" << std::endl; - erpStream << " Generated by GINAN " << GINAN_COMMIT_VERSION << " branch " << GINAN_BRANCH_NAME << /*" at " << peaStopTime <<*/ std::endl; + erpStream << " Generated by GINAN " << GINAN_COMMIT_VERSION << " branch " << GINAN_BRANCH_NAME << std::endl; erpStream << "----------------------------------------------------------------------------------------------------------------" << std::endl; erpStream << " MJD Xpole Ypole UT1-UTC LOD Xsig Ysig UTsig LODsig Nr Nf Nt Xrt Yrt" << std::endl; @@ -252,23 +161,23 @@ void writeERP( int numFixedRecs = 0; int numSats = 0; - double mjd = gpst2mjd(time); + MjDateUtc mjd = erp.time; tracepdeex(0, erpStream, "%8.4f %8d %8d %8d %8d %8d %8d %8d %8d %3d %3d %3d %8d %8d\n", - mjd, + mjd.to_double(), (int) (erp.xp * 1E6 * R2AS), (int) (erp.yp * 1E6 * R2AS), - (int) (erp.ut1_utc * 1E7), + (int) (erp.ut1Utc * 1E7), (int) (erp.lod * 1E7), - (int) (erp.xp_sigma * 1E6 * R2AS), - (int) (erp.yp_sigma * 1E6 * R2AS), - (int) (erp.ut1_utc_sigma * 1E7), - (int) (erp.lod_sigma * 1E7), + (int) (erp.xpSigma * 1E6 * R2AS), + (int) (erp.ypSigma * 1E6 * R2AS), + (int) (erp.ut1UtcSigma * 1E7), + (int) (erp.lodSigma * 1E7), numRecs, numFixedRecs, numSats, - (int) (erp.xpr * 1E6 * R2AS), - (int) (erp.ypr * 1E6 * R2AS)); + (int) (erp.xpr * 1E6 * R2AS), + (int) (erp.ypr * 1E6 * R2AS)); } void writeERPFromNetwork( @@ -277,7 +186,7 @@ void writeERPFromNetwork( { static GTime lastTime = GTime::noTime(); - if (abs(lastTime - kfState.time) < 10) + if (abs((lastTime - kfState.time).to_double()) < 10) { //dont write duplicate lines (closer than 10s (4dp mjd)) return; @@ -285,19 +194,69 @@ void writeERPFromNetwork( lastTime = kfState.time; - double ep[6]; - time2epoch(kfState.time, ep); - double jd = ymdhms2jd(ep); - - ERPData erpd; - erpd.mjd = jd - JD2MJD; + ERPValues erpv; + erpv.time = kfState.time; + + bool found = false; + + KFKey kfKey; + + kfKey.type = KF::EOP; + kfKey.num = 0; found |= kfState.getKFValue(kfKey, erpv.xp, &erpv.xpSigma ); erpv.xp *= MAS2R; erpv.xpSigma = sqrt(erpv.xpSigma) * MAS2R; + kfKey.num = 1; found |= kfState.getKFValue(kfKey, erpv.yp, &erpv.ypSigma ); erpv.yp *= MAS2R; erpv.ypSigma = sqrt(erpv.ypSigma) * MAS2R; + kfKey.num = 2; found |= kfState.getKFValue(kfKey, erpv.ut1Utc, &erpv.ut1UtcSigma ); erpv.ut1Utc *= MTS2S; erpv.ut1UtcSigma = sqrt(erpv.ut1UtcSigma) * MTS2S; + + kfKey.type = KF::EOP_RATE; + kfKey.num = 0; found |= kfState.getKFValue(kfKey, erpv.xpr, &erpv.xprSigma ); erpv.xpr *= MAS2R; erpv.xprSigma = sqrt(erpv.xprSigma) * MAS2R; + kfKey.num = 1; found |= kfState.getKFValue(kfKey, erpv.ypr, &erpv.yprSigma ); erpv.ypr *= MAS2R; erpv.yprSigma = sqrt(erpv.yprSigma) * MAS2R; + kfKey.num = 2; found |= kfState.getKFValue(kfKey, erpv.lod, &erpv.lodSigma ); erpv.lod *= MTS2S * -1; erpv.lodSigma = sqrt(erpv.lodSigma) * MTS2S; //lod is negative for some reason + + if (found) + { + //using old method, enter and return + + writeERP(filename, erpv); + + return; + } - kfState.getKFValue({.type = KF::EOP, .str= xp_str}, erpd.xp, &erpd.xp_sigma ); erpd.xp *= MAS2R; erpd.xp_sigma = sqrt(erpd.xp_sigma) * MAS2R; - kfState.getKFValue({.type = KF::EOP, .str= yp_str}, erpd.yp, &erpd.yp_sigma ); erpd.yp *= MAS2R; erpd.yp_sigma = sqrt(erpd.yp_sigma) * MAS2R; - kfState.getKFValue({.type = KF::EOP, .str= ut1_str}, erpd.ut1_utc, &erpd.ut1_utc_sigma ); erpd.ut1_utc *= MTS2S; erpd.ut1_utc_sigma = sqrt(erpd.ut1_utc_sigma) * MTS2S; - kfState.getKFValue({.type = KF::EOP_RATE, .str= xp_str}, erpd.xpr, &erpd.xpr_sigma ); erpd.xpr *= MAS2R; erpd.xpr_sigma = sqrt(erpd.xpr_sigma) * MAS2R; - kfState.getKFValue({.type = KF::EOP_RATE, .str= yp_str}, erpd.ypr, &erpd.ypr_sigma ); erpd.ypr *= MAS2R; erpd.ypr_sigma = sqrt(erpd.ypr_sigma) * MAS2R; - kfState.getKFValue({.type = KF::EOP_RATE, .str= ut1_str}, erpd.lod, &erpd.lod_sigma ); erpd.lod *= MTS2S * -1; erpd.lod_sigma = sqrt(erpd.lod_sigma) * MTS2S; //lod is negative for some reason + ERPValues erpvs[2]; + erpvs[0] = geterp(nav.erp, kfState.time); + erpvs[1] = geterp(nav.erp, kfState.time + 1); - writeERP(filename, erpd, kfState.time); + erpv = erpvs[0]; + erpv.time = kfState.time; + erpv.xpr = erpvs[1].xp - erpvs[0].xp; // per 1 second dt + erpv.ypr = erpvs[1].yp - erpvs[0].yp; // per 1 second dt + + for (int i = 0; i < 3; i++) + { + double adjust = 0; + double adjustVar = 0; + double rateAdjust = 0; + double rateAdjustVar = 0; + + KFKey kfKey; + kfKey.num = i; + + kfKey.type = KF::EOP_ADJUST; + kfState.getKFValue(kfKey, adjust, &adjustVar); + + kfKey.type = KF::EOP_RATE_ADJUST; + kfState.getKFValue(kfKey, rateAdjust, &rateAdjustVar); + + switch (i) + { + case 0: erpv.xp += adjust * MAS2R; erpv.xpSigma = sqrt(adjustVar) * MAS2R; + erpv.xpr += rateAdjust * MAS2R; erpv.xprSigma = sqrt(rateAdjustVar) * MAS2R; break; + case 1: erpv.yp += adjust * MAS2R; erpv.ypSigma = sqrt(adjustVar) * MAS2R; + erpv.ypr += rateAdjust * MAS2R; erpv.yprSigma = sqrt(rateAdjustVar) * MAS2R; break; + case 2: erpv.ut1Utc += adjust * MTS2S; erpv.ut1UtcSigma = sqrt(adjustVar) * MTS2S; + erpv.lod += rateAdjust * MTS2S * -1; erpv.lodSigma = sqrt(rateAdjustVar) * MTS2S; break; //lod is negative for some reason + default: + break; + } + } + + writeERP(filename, erpv); } diff --git a/src/cpp/common/erp.hpp b/src/cpp/common/erp.hpp index 551796c6f..84185b519 100644 --- a/src/cpp/common/erp.hpp +++ b/src/cpp/common/erp.hpp @@ -1,6 +1,5 @@ -#ifndef __ERP_HPP__ -#define __ERP_HPP__ +#pragma once #include #include @@ -9,70 +8,52 @@ using std::string; using std::map; -constexpr char xp_str[] = "_XP"; -constexpr char yp_str[] = "_YP"; -constexpr char ut1_str[] = "_UT1"; +constexpr char eopComments[][16] = {"XP (MAS)", "YP (MAS)", "UT1(MTS)"}; /** earth rotation parameter data type */ -struct ERPData +struct ERPValues { - double mjd = 0; ///< mjd (days) - double xp = 0; ///< pole offset (rad) - double yp = 0; ///< pole offset (rad) - double xpr = 0; ///< pole offset rate (rad/day) - double ypr = 0; ///< pole offset rate (rad/day) - double ut1_utc = 0; ///< ut1-utc (s) - double lod = 0; ///< delta length of day (s/day) + GTime time; - double xp_sigma = 0; - double yp_sigma = 0; - double xpr_sigma = 0; - double ypr_sigma = 0; - double ut1_utc_sigma = 0; - double lod_sigma = 0; -}; - -struct ERP -{ - map erpMap; -}; - -struct ERPValues -{ union { - double vals[6] = {}; + double vals[4] = {}; struct { - double xp; ///< rads - double yp; ///< rads - double ut1_utc; ///< seconds - double lod; ///< seconds/day - double leaps; + double xp; ///< pole offset (rad) + double yp; ///< pole offset (rad) + double ut1Utc; ///< ut1-utc (s) + double lod; ///< delta length of day (s/day) }; }; + + double xpr = 0; ///< pole offset rate (rad/day) + double ypr = 0; ///< pole offset rate (rad/day) + + double xpSigma = 0; + double ypSigma = 0; + double xprSigma = 0; + double yprSigma = 0; + double ut1UtcSigma = 0; + double lodSigma = 0; +}; + +struct ERP +{ + map erpMap; }; -struct GTime; struct KFState; -int readerp( +void readerp( string file, ERP& erp); -int geterp( - ERP& erp, - GTime time, - ERPValues& erpv); - -int geterp( +ERPValues geterp( ERP& erp, - double mjd, - ERPValues& erpv); + GTime time); void writeERPFromNetwork( string filename, KFState& kfState); - -#endif diff --git a/src/cpp/common/fileLog.cpp b/src/cpp/common/fileLog.cpp index 9e0cfeda7..1263e882c 100644 --- a/src/cpp/common/fileLog.cpp +++ b/src/cpp/common/fileLog.cpp @@ -28,7 +28,7 @@ void FileLog::consume( { string mess = log_string.c_str(); boost::erase_all(mess, "\n"); - if (mess == "") + if (mess.empty()) return; int logLevel = 2; @@ -49,11 +49,11 @@ void FileLog::consume( if (!logStream) return; - std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + GTime time = timeGet(); bsoncxx::builder::basic::document doc = {}; doc.append(kvp("label", "message")); -// doc.append(kvp("timestamp", std::put_time(std::localtime( &now ),"%F %X"))); + doc.append(kvp("Time", time.to_string())); doc.append(kvp("level", logLevel)); doc.append(kvp("str", mess)); diff --git a/src/cpp/common/fileLog.hpp b/src/cpp/common/fileLog.hpp index 738bfe37e..0433d5d05 100644 --- a/src/cpp/common/fileLog.hpp +++ b/src/cpp/common/fileLog.hpp @@ -1,16 +1,18 @@ -#ifndef FILELOG_H -#define FILELOG_H + +#pragma once #include "acsConfig.hpp" #include "gTime.hpp" #include -#include -#include namespace sinks = boost::log::sinks; + +#include +#include using std::string; + struct FileLog : public sinks::basic_formatted_sink_backend { static string path_log; @@ -21,5 +23,3 @@ struct FileLog : public sinks::basic_formatted_sink_backend 13 seconds before 0:00:00 UTC on Sunday, 22 August 1999 (midnight between 21 and 22 August) +const GTime BDS_t0 = GEpoch{2006, E_Month::JAN, 1, 0, 0, 0 + GPS_SUB_UTC_2006}; // beidou time reference as gps time - defined in utc 11:58:55.816 + +const int GPS_t0_sub_POSIX_t0 = 315964800; +const double MJD_j2000 = 51544.5; + + +const int secondsInWeek = 60 * 60 * 24 * 7; +const int secondsInDay = 60 * 60 * 24; +const long double secondsInDayP = 60 * 60 * 24; + +map> leapSecondMap = +{ + { GEpoch{2017, 1, 1, 0, 0, 18}, 18}, + { GEpoch{2015, 7, 1, 0, 0, 17}, 17}, + { GEpoch{2012, 7, 1, 0, 0, 16}, 16}, + { GEpoch{2009, 1, 1, 0, 0, 15}, 15}, + { GEpoch{2006, 1, 1, 0, 0, 14}, 14}, + { GEpoch{1999, 1, 1, 0, 0, 13}, 13}, + { GEpoch{1997, 7, 1, 0, 0, 12}, 12}, + { GEpoch{1996, 1, 1, 0, 0, 11}, 11}, + { GEpoch{1994, 7, 1, 0, 0, 10}, 10}, + { GEpoch{1993, 7, 1, 0, 0, 9}, 9}, + { GEpoch{1992, 7, 1, 0, 0, 8}, 8}, + { GEpoch{1991, 1, 1, 0, 0, 7}, 7}, + { GEpoch{1990, 1, 1, 0, 0, 6}, 6}, + { GEpoch{1988, 1, 1, 0, 0, 5}, 5}, + { GEpoch{1985, 7, 1, 0, 0, 4}, 4}, + { GEpoch{1983, 7, 1, 0, 0, 3}, 3}, + { GEpoch{1982, 7, 1, 0, 0, 2}, 2}, + { GEpoch{1981, 7, 1, 0, 0, 1}, 1}, + { GEpoch{1980, 1, 6, 0, 0, 0}, 0} +}; + ostream& operator <<(ostream& stream, const GTime& time) { - stream << time.time << ": " << time.sec; + stream << time.to_string(); + return stream; +} + +ostream& operator <<(ostream& stream, const Duration& duration) +{ + char buff[64]; + + int decimal = (duration.bigTime - floor(duration.bigTime)) * 100; + + snprintf(buff, sizeof(buff), "%02d:%02d:%02d.%02d", + (int) duration.bigTime / 60 / 60, + (int) duration.bigTime / 60 % 60, + (int) duration.bigTime % 60, + decimal); + + stream << buff; + return stream; } -/* string to number ------------------------------------------------------------ -* convert substring in string to number +/* convert substring in string to number * args : char *s I string ("... nnn.nnn ...") * int i,n I substring position and width * return : converted number (0.0:error) -*-----------------------------------------------------------------------------*/ +*/ double str2num(const char *s, int i, int n) { double value; @@ -41,13 +102,11 @@ double str2num(const char *s, int i, int n) return sscanf(str, "%lf", &value) == 1 ? value : 0; } -/* string to time -------------------------------------------------------------- -* convert substring in string to GTime struct +/* convert substring in string to GTime struct * args : char *s I string ("... yyyy mm dd hh mm ss ...") * int i,n I substring position and width * GTime *t O GTime struct -* return : status (0:ok,0>:error) -*-----------------------------------------------------------------------------*/ +* return : status (0:ok,0>:error)*/ int str2time( const char* s, int i, @@ -91,451 +150,253 @@ int str2time( return 0; } -/* convert calendar day/time to time ------------------------------------------- -* convert calendar day/time to GTime struct -* args : double *ep I day/time {year,month,day,hour,min,sec} -* return : GTime struct -* notes : proper in 1970-2037 or 1970-2099 (64bit time_t) -*-----------------------------------------------------------------------------*/ -GTime epoch2time(const double *ep) -{ - const int doy[] = {1,32,60,91,121,152,182,213,244,274,305,335}; - - GTime time = {}; - int year = (int) ep[0]; - int mon = (int) ep[1]; - int day = (int) ep[2]; - - if ( year < 1970 - || year > 2099 - || mon < 1 - || mon > 12) - { - return time; - } - - // leap year if year%4==0 in 1901-2099 - int days = (year-1970)*365+(year-1969)/4+doy[mon-1]+day-2+(year%4==0&&mon>=3?1:0); - int sec = (int) floor(ep[5]); - time.time = (time_t)days*86400+(int)ep[3]*3600+(int)ep[4]*60+sec; - time.sec = ep[5] - sec; - - return time; -} - GTime yds2time(const int* yds) { int year = yds[0]; int doy = yds[1]; int sec = yds[2]; - if (year<1970||2099 366) + { + return GTime::noTime(); + } - /* leap year if year%4==0 in 1901-2099 */ - int days=(year-1970)*365+(year-1969)/4 + doy - 2; + int leapDays = (year-1968-1) / 4 // -1968 = last leap year before 1970; -1 = year must end before applying leap-day + - (year-1900-1) / 100 + + (year-1600-1) / 400; + + int days = (year-1970)*365 + leapDays + doy - 1; - GTime time = {}; - time.time = (time_t)days*86400+sec; + PTime time = {}; + time.bigTime = days * 86400.0 + sec; //.0 to prevent eventual overflow return time; } -/* time to calendar day/time --------------------------------------------------- -* convert GTime struct to calendar day/time -* args : GTime t I GTime struct -* double *ep O day/time {year,month,day,hour,min,sec} -* return : none -* notes : proper in 1970-2037 or 1970-2099 (64bit time_t) -*-----------------------------------------------------------------------------*/ -void time2epoch(GTime t, double* ep) -{ - const int mday[] = - { - /* # of days in a month */ - 31,28,31,30,31,30,31,31,30,31,30,31, - 31,28,31,30,31,30,31,31,30,31,30,31, - 31,29,31,30,31,30,31,31,30,31,30,31, - 31,28,31,30,31,30,31,31,30,31,30,31 - }; - /* leap year if year % 4 == 0 in 1901-2099 */ - - int days = (int) (t.time / 86400); - int sec = (int) (t.time - (time_t) days * 86400); - - int doy = days % (365*4+1); - int mon; - for (mon = 0; mon < 48; mon++) - { - if (doy >= mday[mon]) - doy -= mday[mon]; - else - break; - } - ep[0] = 1970 + days / 1461 * 4 + mon / 12; - ep[1] = mon % 12 + 1; - ep[2] = doy + 1; - ep[3] = sec / 3600; - ep[4] = sec % 3600 / 60; - ep[5] = sec % 60 + t.sec; -} - -/* epoch to year doy sod converter---------------------------------------------- -* args : double *ep I day/time {year, mon, day, hour, min,sec} -* : int *yds O year, doy, sod -* return : none -*------------------------------------------------------------------------------*/ -void epoch2yds(double *ep, int *yds) +UYds::operator GTime() const { - const int mday[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + GTime time = yds2time(this->data()); + double leap = leapSeconds(time); + time += leap; + return time; +} - int year = ep[0]; - int month = ep[1]; - int dom = ep[2]; - int hour = ep[3]; - int minute = ep[4]; - int second = ep[5]; - int doy = dom; +GTime epoch2time(const double *ep) +{ + int year = (int) ep[0]; + int mon = (int) ep[1]; + int day = (int) ep[2]; + int hour = (int) ep[3]; + int min = (int) ep[4]; + double floatSec = ep[5]; - //add days for all previous months - for (int i = 1; i <= 12; i++) + if ( year < 1970 + || mon < 1 + || mon > 12) { - if (month > i) - { - doy += mday[i]; - } + return GTime::noTime(); } - /* all years 1900-2099 divisible by 4 are leap years */ - if ( month > 2 - &&year % 4 == 0) + const int dayOffsetFromMonth[] = {0,31,59,90,120,151,181,212,243,273,304,334}; + int dayOfYear = dayOffsetFromMonth[mon-1] + day; + + if ( ( mon >= 3) //after feb29 + &&( year % 4 == 0) //every 4 years + &&( year % 100 != 0 + ||year % 400 == 0)) { - doy++; + dayOfYear++; } - - yds[0] = year; - yds[1] = doy; - yds[2] = hour * 60 * 60 - + minute * 60 - + second; + int sec = (int) floor(floatSec); + double partialSec = floatSec - sec; + int secOfDay = hour * 60 * 60 + + min * 60 + + sec; + + int yds[3]; + yds[0] = year; + yds[1] = dayOfYear; + yds[2] = secOfDay; + GTime time = yds2time(yds); //todo aaron sketchy + time += partialSec; + + return time; } -/* gps time to time ------------------------------------------------------------ -* convert week and tow in gps time to GTime struct + +/* convert week and tow in gps time to GTime struct * args : int week I week number in gps time * double sec I time of week in gps time (s) * return : GTime struct -*-----------------------------------------------------------------------------*/ +*/ GTime gpst2time(int week, double sec) { - GTime t = epoch2time(gpst0); + GTime t = GPS_t0; if ( sec <-1E9 ||sec > 1E9) { sec = 0; } - t.time += 60*60*24*7*week + (int)sec; - t.sec = sec - (int)sec; + t.bigTime += secondsInWeek * week; + t.bigTime += sec; + return t; } -/* time to gps time ------------------------------------------------------------ -* convert GTime struct to week and tow in gps time +/* convert GTime struct to week and tow in gps time * args : GTime t I GTime struct * int *week IO week number in gps time (nullptr: no output) * return : time of week in gps time (s) -*-----------------------------------------------------------------------------*/ +*/ double time2gpst(GTime t, int *week) { - GTime t0 = epoch2time(gpst0); - - time_t sec = t.time - t0.time; - int w=(int)(sec/(86400*7)); + GTime t0 = GPS_t0; - if (week) *week=w; - return (double)(sec-w*86400*7)+t.sec; -} + auto sec = t.bigTime - t0.bigTime; + int w = (int)(sec / (86400*7)); -/* galileo system time to time ------------------------------------------------- -* convert week and tow in galileo system time (gst) to GTime struct -* args : int week I week number in gst -* double sec I time of week in gst (s) -* return : GTime struct -*-----------------------------------------------------------------------------*/ -GTime gst2time(int week, double sec) -{ - GTime t=epoch2time(gst0); + if (week) + *week = w; - if (sec<-1E9||1E9tm_year+1900; - ep[1]=tt->tm_mon+1; - ep[2]=tt->tm_mday; - ep[3]=tt->tm_hour; - ep[4]=tt->tm_min; - ep[5]=tt->tm_sec+tv.tv_usec*1E-6; - } - return epoch2time(ep); -} -/* gpstime to utc -------------------------------------------------------------- -* convert gpstime to utc considering leap seconds -* args : GTime t I time expressed in gpstime -* return : time expressed in utc -* notes : ignore slight time offset under 100 ns -*-----------------------------------------------------------------------------*/ -GTime gpst2utc( - GTime t) +PTime timeGet() { - for (int i = 0; leaps[i][0] > 0; i++) - { - GTime tu = t + leaps[i][6]; - - if ((tu - epoch2time(leaps[i])) >= 0) - return tu; - } - return t; + struct timeval timeVal{}; + gettimeofday(&timeVal, nullptr); + + PTime pTime; + pTime.bigTime = timeVal.tv_sec + + timeVal.tv_usec * 1e-6; + + return pTime; } -/* utc to gpstime -------------------------------------------------------------- -* convert utc to gpstime considering leap seconds -* args : GTime t I time expressed in utc -* return : time expressed in gpstime -* notes : ignore slight time offset under 100 ns -*-----------------------------------------------------------------------------*/ -GTime utc2gpst(GTime t) +/* GPStime - UTC */ +double leapSeconds( + GTime time) { - for (int i = 0; leaps[i][0] > 0; i++) + if (nav.leaps >= 0) + return nav.leaps; + + if (acsConfig.leap_seconds >= 0) + return acsConfig.leap_seconds; + + auto it = leapSecondMap.lower_bound(time); + if (it == leapSecondMap.end()) { - if ((t - epoch2time(leaps[i])) >= 0) //todo aaron, one leap second has a for loop.. check - return t -leaps[i][6]; + return 0; } - return t; -} -/* gpstime to bdt -------------------------------------------------------------- -* convert gpstime to bdt (beidou navigation satellite system time) -* args : GTime t I time expressed in gpstime -* return : time expressed in bdt -* notes : ref [8] 3.3, 2006/1/1 00:00 BDT = 2006/1/1 00:00 UTC -* no leap seconds in BDT -* ignore slight time offset under 100 ns -*-----------------------------------------------------------------------------*/ -GTime gpst2bdt(GTime t) -{ - return t - 14.0; + auto& [leapTime, seconds] = *it; + + return seconds; } -/* bdt to gpstime -------------------------------------------------------------- -* convert bdt (beidou navigation satellite system time) to gpstime -* args : GTime t I time expressed in bdt -* return : time expressed in gpstime -* notes : see gpst2bdt() -*-----------------------------------------------------------------------------*/ -GTime bdt2gpst(GTime t) -{ - return t + 14.0; -} -/* time to day and sec -------------------------------------------------------*/ -double time2sec(GTime time, GTime* day) +UtcTime gpst2utc( + GTime t) { - double ep[6],sec; - time2epoch(time,ep); - sec=ep[3]*3600.0+ep[4]*60.0+ep[5]; - ep[3]=ep[4]=ep[5]=0.0; - *day=epoch2time(ep); - return sec; + long double leaps = leapSeconds(t); + + UtcTime utcTime; + utcTime.bigTime = t.bigTime - leaps; + + return utcTime; } -/* utc to gmst ----------------------------------------------------------------- -* convert utc to gmst (Greenwich mean sidereal time) -* args : GTime t I time expressed in utc -* double ut1_utc I UT1-UTC (s) -* return : gmst (rad) -*-----------------------------------------------------------------------------*/ -double utc2gmst(GTime t, double ut1_utc) +GTime utc2gpst(UtcTime utcTime) { - const double ep2000[]={2000,1,1,12,0,0}; - - GTime tut = t + ut1_utc; - GTime tut0; - double ut = time2sec(tut,&tut0); - double t1 = (tut0 - epoch2time(ep2000))/86400.0/36525.0; - double t2 = t1*t1; - double t3 = t2*t1; - double gmst0 = 24110.54841+8640184.812866*t1+0.093104*t2-6.2E-6*t3; - double gmst = gmst0+1.002737909350795*ut; - - return fmod(gmst,86400.0)*PI/43200.0; /* 0 <= gmst <= 2*PI */ + GTime gTime; + gTime.bigTime = utcTime.bigTime; + + double leaps = leapSeconds(gTime); + leaps = leapSeconds(gTime - leaps); + + gTime.bigTime += leaps; + + return gTime; } -/* time to string -------------------------------------------------------------- -* convert GTime struct to string -* args : GTime t I GTime struct -* char *s O string ("yyyy/mm/dd hh:mm:ss.ssss") -* int n I number of decimals -* return : none -*-----------------------------------------------------------------------------*/ -void time2str( - GTime t, - char* s, - int n) +string GTime::to_string( + int n) const { - double ep[6]; - + GTime t = *this; + if (n < 0) n = 0; else if (n > 12) n = 12; - if (1 - t.sec < 0.5 / pow(10, n)) + double exper = pow(10, n); + + long double val = t.bigTime * exper; + val -= (long int) val; + + if (val > 0.5) { - t.time++; - t.sec = 0; + t.bigTime += 0.5 / exper; }; - time2epoch(t, ep); + GEpoch ep(t); + + char buff[64]; + snprintf(buff, sizeof(buff),"%04.0f-%02.0f-%02.0f %02.0f:%02.0f:%0*.*f", + ep[0], + ep[1], + ep[2], + ep[3], + ep[4], + n<=0?2:n+3,n<=0?0:n, + ep[5]); - sprintf(s,"%04.0f-%02.0f-%02.0f %02.0f:%02.0f:%0*.*f",ep[0],ep[1],ep[2], - ep[3],ep[4],n<=0?2:n+3,n<=0?0:n,ep[5]); -} - -/* time to day of year --------------------------------------------------------- -* convert time to day of year -* args : GTime t I GTime struct -* return : day of year (days) -*-----------------------------------------------------------------------------*/ -double time2doy(GTime t) -{ - double ep[6]; - - time2epoch(t,ep); - ep[1] = ep[2] = 1; - ep[3] = ep[4] = ep[5] = 0; - return (t - epoch2time(ep)) / 86400.0 + 1; + return buff; } -/* adjust gps week number ------------------------------------------------------ -* adjust gps week number using cpu time -* args : int week I not-adjusted gps week number -* return : adjusted gps week number -*-----------------------------------------------------------------------------*/ -int adjgpsweek(int week) -{ - int w; - (void)time2gpst(utc2gpst(timeget()),&w); - if (w<1560) w=1560; /* use 2009/12/1 if time is earlier than 2009/12/1 */ - return week+(w-week+512)/1024*1024; -} - - -/* set precision --------------------------------------------------------------- -* -* args : const double n I source number -* -* return : formatted number -*----------------------------------------------------------------------------*/ +/* set precision + */ double setdigits(const double n) { char str[128]; double m; - sprintf(str,"%.4f",n); + snprintf(str, sizeof(str),"%.4f",n); sscanf(str,"%lf",&m); return m; } -/* Julian day to YMDHMS -------------------------------------------------------- -* + +/* Julian day to YMDHMS * args : const double jd I Julian day * double ep[6] O Y,M,D,H,M,S -* -* return : none -* -* reference: [3] -*----------------------------------------------------------------------------*/ +*/ void jd2ymdhms(const double jd, double *ep) { int b,c,d,e; @@ -573,22 +434,7 @@ void jd2ymdhms(const double jd, double *ep) return; } -double gpst2mjd(const GTime time) //todo aaron, this gives different results to what is used elsewhere, no utc conversion, eg, in erp output code -{ - double ep[6]; - time2epoch(gpst2utc(time), ep); - double jd = ymdhms2jd(ep); - return jd - JD2MJD; -} -double utc2mjd(const GTime time) -{ - double ep[6]; - time2epoch(time, ep); - double jd = ymdhms2jd(ep); - return jd - JD2MJD; -} - /** YMDHMS to Julian Day * return : julian day */ @@ -612,12 +458,228 @@ double ymdhms2jd( double day = time[2] + hr / 24 - + min / 24/ 60 - + sec / 24/ 60 / 60; + + min / 24 / 60 + + sec / secondsInDay; - double jd = (floor(365.25*i)+floor(30.6001*(j+1))+day+1720981.5); + double jd = floor(365.25*i) + + floor(30.6001*(j+1)) + + day + + 1720981.5; // BOOST_LOG_TRIVIAL(debug) << "YMDH to JD: year=" << yr << " mon=" << mon << " day=" << day << " hour=" << hr << ", jd=" << jd; return jd; +}; + + +GTime::operator GEpoch() const +{ + PTime pTime = *this; + + GEpoch ep; + + const int mday[] = + { + /* # of days in a month */ + 31,28,31,30,31,30,31,31,30,31,30,31, + 31,28,31,30,31,30,31,31,30,31,30,31, + 31,29,31,30,31,30,31,31,30,31,30,31, + 31,28,31,30,31,30,31,31,30,31,30,31 + }; + + /* leap year if year % 4 == 0 in 1901-2099 */ + + int days = (int) (pTime.bigTime / secondsInDayP); + double remSecs = pTime.bigTime - (time_t) days * secondsInDay; + + int doy = days % (365*4+1); + int mon; + for (mon = 0; mon < 48; mon++) + { + if (doy >= mday[mon]) + doy -= mday[mon]; + else + break; + } + ep.year = 1970 + + days / 1461 * 4 //1461 = 365.25 * 4 + + mon / 12; + ep.month = mon % 12 + 1; + ep.day = doy + 1; + + ep.hour = (int) (remSecs / 3600); remSecs -= ep.hour * 3600; + ep.min = (int) (remSecs / 60); remSecs -= ep.min * 60; + ep.sec = (remSecs); + + return ep; } +GTime GTime::floorTime( + double period) const +{ + GTime roundedTime = *this; + + //need separate functions for fractional / whole seconds + //ignore fractions greater than one + if (period < 1) + { + double fractionalSeconds = bigTime - (long int) bigTime; + + int wholePeriods = fractionalSeconds / period; + + fractionalSeconds = wholePeriods * period; + + roundedTime.bigTime = fractionalSeconds + (long int) bigTime; + } + else + { + //round to nearest chunk by integer arithmetic + roundedTime.bigTime = ((long int) (roundedTime.bigTime / period)) * period; + } + + return roundedTime; +} + +/** Returns GTime in "dd-mmm-yyyy hh:mm:ss" format +*/ +string GTime::gregString() +{ + GEpoch epoch = *this; + char buffer[25]; + snprintf(buffer, 25, "%02d-%3s-%04d %02d:%02d:%02d", + (int)epoch.day, + E_Month::_from_integral((int)epoch.month)._to_string(), + (int)epoch.year, + (int)epoch.hour, + (int)epoch.min, + (int)epoch.sec); + return buffer; +} + + + +/** Use a time of modulus and recent time to calculate the new time + */ +GTime nearestTime( + GTime referenceEpoch, // + double tom, + GTime nearTime, + int mod) +{ + time_t seconds = (time_t) (nearTime.bigTime - referenceEpoch.bigTime); + int nearMod = seconds / mod; + int nearTom = seconds % mod; + + int deltaTom = tom - nearTom; + + int newMod = nearMod; + + if (deltaTom > + mod / 2) { newMod--; } + else if (deltaTom < - mod / 2) { newMod++; } + + GTime newTime = referenceEpoch + + newMod * mod + + tom; + + return newTime; +} + + +GTime::operator MjDateTT() const +{ + long double thisDate = *this; + long double thenDate = j2000TT; + + long double deltaDate = thisDate - thenDate; + deltaDate /= secondsInDayP; + + MjDateTT mjd; + mjd.val = MJD_j2000 + + deltaDate; + + return mjd; +} + +GTime::GTime( + MjDateTT mjdTT) +{ + long double deltaDays = mjdTT.val - MJD_j2000; + + bigTime = j2000TT.bigTime + + deltaDays * secondsInDayP; +} + +GTime::GTime( + MjDateUtc mjdUtc) +{ + long double deltaDays = mjdUtc.val - MJD_j2000; + + bigTime = j2000Utc.bigTime + + deltaDays * secondsInDayP; + + long double leaps = leapSeconds(*this); + + bigTime += leaps; +} + +MjDateUt1::MjDateUt1( + GTime time, + double ut1_utc) +{ + MjDateUtc mjdUtc = time; + + val = mjdUtc.val + + ut1_utc / secondsInDayP; +} + +MjDateUtc::MjDateUtc( + GTime time) +{ + long double thisDate = time; + long double thenDate = j2000Utc; + + long double deltaDate = thisDate - thenDate; + deltaDate /= secondsInDayP; + + long double leaps = leapSeconds(time); + + val = MJD_j2000 + + deltaDate + - leaps / secondsInDayP; +} + +GTime::GTime(GWeek gpsWeek, GTow tow) { *this = GPS_t0 + gpsWeek * secondsInWeek + tow; } +GTime::GTime(BWeek bdsWeek, BTow tow) { *this = BDS_t0 + bdsWeek * secondsInWeek + tow; } + +GEpoch ::operator GTime() const{ return epoch2time(this->data()); } +UtcTime ::operator GTime() const{ return utc2gpst(*this); } +GTime ::operator UtcTime() const{ return gpst2utc(*this); } + + +GTime::GTime(GTow tow, GTime nearTime) { *this = nearestTime(GPS_t0, tow, nearTime, secondsInWeek); } +GTime::GTime(BTow tow, GTime nearTime) { *this = nearestTime(BDS_t0, tow, nearTime, secondsInWeek); } + +GTime::GTime(RTod tod, GTime nearTime) +{ + RTod nearTod = nearTime; + + double delta = tod - nearTod; + + while (delta > +secondsInDay / 2) delta -= secondsInDay; + while (delta < -secondsInDay / 2) delta += secondsInDay; + + *this = nearTime + delta; +} + + +GTime::operator long double() const{ return bigTime; } + +GTime::operator GWeek() const{ Duration seconds = *this - GPS_t0; GWeek gWeek = seconds.to_int() / secondsInWeek; return gWeek; } +GTime::operator BWeek() const{ Duration seconds = *this - BDS_t0; BWeek bWeek = seconds.to_int() / secondsInWeek; return bWeek; } +GTime::operator GTow() const{ Duration seconds = *this - GPS_t0; GTow gTow = fmod(seconds.to_double(), (double)secondsInWeek); return gTow; } +GTime::operator BTow() const{ Duration seconds = *this - BDS_t0; BTow bTow = fmod(seconds.to_double(), (double)secondsInWeek); return bTow; } +GTime::operator RTod() const{ Duration seconds = *this - GLO_t0; RTod rTod = fmod(seconds.to_double()-leapSeconds(*this), (double)secondsInDay); return rTod; } + +PTime::operator GTime() const{ GTime gTime; gTime.bigTime = bigTime - GPS_t0_sub_POSIX_t0; return gTime;} +GTime::operator PTime() const{ PTime pTime; pTime.bigTime = bigTime + GPS_t0_sub_POSIX_t0; return pTime;} + +GTime::operator string() const{ return to_string(2); } diff --git a/src/cpp/common/gTime.hpp b/src/cpp/common/gTime.hpp index ee0c009ec..2e64deeb8 100644 --- a/src/cpp/common/gTime.hpp +++ b/src/cpp/common/gTime.hpp @@ -1,27 +1,193 @@ -#ifndef __GATIME_HPP__ -#define __GATIME_HPP__ +#pragma once #include #include #include +#include #include using std::ostream; using std::string; +using std::array; +struct PTime; struct GTime; +struct UtcTime; +struct GEpoch; +struct UEpoch; +struct GWeek; +struct GTow; +struct MjDateTT; +struct MjDateUtc; -void time2str(GTime t, char *str, int n); + + +#define GPS_SUB_UTC_2000 13 +#define GPS_SUB_UTC_2006 14 + + +extern const GTime GPS_t0; +extern const double MJD_j2000; +extern const int secondsInDay; + +string time2str(GTime t, int n); + +GTime epoch2time (const double *ep); + +double leapSeconds( GTime time ); + +struct Int +{ + int val = 0; + + Int() + { + + } + + Int( + const int& in) + : val {in} + { + + } + + operator int() const + { + return val; + } + + Int& operator =( + const int& in) + { + val = in; + return *this; + } +}; + +struct Double +{ + double val = 0; + + Double() + { + + } + + Double( + const double& in) + : val {in} + { + + } + + operator double() const + { + return val; + } + + Double& operator =( + const double& in) + { + val = in; + return *this; + } +}; + + +struct GWeek : Int +{ + GWeek( + int in) + { + val = in; + } +}; + +struct BWeek : Int +{ + BWeek( + int in) + { + val = in; + } +}; + +struct GTow : Double +{ + GTow( + double in) + { + val = in; + } +}; + +struct BTow : Double +{ + BTow( + double in) + { + val = in; + } +}; + +struct RTod : Double +{ + RTod( + double in) + { + val = in; + } +}; + +struct Duration +{ + long double bigTime = 0; + + double to_double() const + { + return (double) bigTime; + } + + long int to_int() const + { + return (long int) bigTime; + } + + bool operator < (const double& t2) const + { + if (this->bigTime < t2) return true; + else return false; + } + + bool operator > (const double& t2) const + { + if (this->bigTime > t2) return true; + else return false; + } + + long double operator - (const Duration& t2) const + { + return this->bigTime - t2.bigTime; + } + + double operator / (const Duration& t2) const + { + return this->bigTime / t2.bigTime; + } + + + friend ostream& operator<<(ostream& os, const Duration& time); +}; /** Time structure used throughout this software */ struct GTime { - time_t time = 0; ///< Time (s) expressed by standard time_t - double sec = 0; ///< Fractions of second ( 0 < sec < 1 ) + long double bigTime = 0; /** Uninitialised time for comparisons */ @@ -30,48 +196,48 @@ struct GTime GTime nothing; return nothing; } + + GTime( + GTow tow, + GTime nearTime); + + GTime( + BTow tow, + GTime nearTime); + + GTime( + RTod tod, + GTime nearTime); + + string to_string(int n = 2) const; - string to_string(int n) const + bool operator == (const GTime& t2) const { - char buff[64]; - time2str(*this, buff, n); - string result = buff; - return result; + if (this->bigTime != t2.bigTime) return false; + else return true; } - bool operator ==(const GTime &t2) const + bool operator != (const GTime& t2) const { - if (this->time != t2.time) return false; - if (this->sec != t2.sec) return false; - else return true; + return !(*this == t2); } - bool operator !=(const GTime &t2) const + bool operator < (const GTime& t2) const { - return !(*this == t2); + if (this->bigTime < t2.bigTime) return true; + else return false; } -// bool operator <(const GTime &t2) const -// { -// if (this->time < t2.time) return true; -// if (this->time > t2.time) return false; -// if (this->sec < t2.sec) return true; -// else return false; -// } - - bool operator <(const GTime &t2) const + bool operator > (const GTime& t2) const { - if (this->time < t2.time) return true; - if (this->time > t2.time) return false; - if (this->sec < t2.sec) return true; - else return false; + if (this->bigTime > t2.bigTime) return true; + else return false; } - - bool operator >(const GTime &t2) const + + bool operator >= (const GTime& t2) const { - if (this->time > t2.time) return true; - if (this->time < t2.time) return false; - if (this->sec > t2.sec) return true; + if (*this > t2) return true; + if (*this == t2) return true; else return false; } @@ -79,27 +245,20 @@ struct GTime GTime operator +(const double t) const { - GTime time = *this; - - time.sec += t; - - double fracSeconds = time.sec - (int) time.sec; - double intSeconds = time.sec - fracSeconds; - - time.time += intSeconds; - time.sec -= intSeconds; - - if (time.sec < 0) - { - time.sec += 1; - time.time -= 1; - } - return time; + GTime gTime = *this; + + gTime.bigTime += t; + + return gTime; } GTime operator +(const int t) const { - return *this + (double) t; + GTime gTime = *this; + + gTime.bigTime += t; + + return gTime; } GTime& operator+=(const double rhs) @@ -107,21 +266,19 @@ struct GTime *this = *this + rhs; return *this; } - - GTime operator -(const GTime t) const + + GTime& operator-=(const double rhs) { - GTime time = *this; + *this = *this - rhs; + return *this; + } - time.time -= t.time; - time.sec -= t.sec; - - if (time.sec < 0) - { - time.time -= 1; - time.sec += 1; - } + Duration operator -(const GTime t) const + { + Duration duration; + duration.bigTime = bigTime - t.bigTime; - return time; + return duration; } GTime operator -(const double t) const @@ -130,89 +287,323 @@ struct GTime return time; } - operator double() const + + GTime& operator++(int) { - return this->time + this->sec; + this->bigTime++; + return *this; } + GTime() + { + + } + GTime( + GWeek gpsWeek, + GTow tow); - GTime& operator++(int) + GTime( + BWeek bdsWeek, + BTow tow); + + GTime( + MjDateTT mjdTT); + + GTime( + MjDateUtc mjdUtc); + + + template + void serialize(ARCHIVE& ar, const unsigned int& version) { - this->time++; - return *this; + ar & bigTime; } + GTime floorTime( + double period) const; + + string gregString(); - boost::posix_time::ptime to_ptime() + operator long double() const; + operator MjDateTT() const; + operator GEpoch() const; + operator UtcTime() const; + operator GWeek() const; + operator BWeek() const; + operator GTow() const; + operator BTow() const; + operator PTime() const; + operator string() const; + operator RTod() const; +}; + +struct PTime +{ + long double bigTime = 0; + + PTime() { - return boost::posix_time::from_time_t(time); + } - GTime() + operator GTime() const; +}; + + +PTime timeGet(); + + +struct MjDateUtc +{ + long double val; + + MjDateUtc() { } - GTime(int t, int s) + MjDateUtc( + GTime time); + + double to_double() const { - time = t; - sec = s; + return (double) val; } +}; + + +struct MjDateUt1 +{ + long double val; - GTime(boost::posix_time::ptime p_time) + MjDateUt1() { - time = boost::posix_time::to_time_t(p_time); + } + + MjDateUt1( + GTime time, + double ut1_utc); + + double to_double() const + { + return (double) val; + } + + double to_j2000() const + { + return (double) (val - MJD_j2000); + } +}; +struct MjDateTT +{ + long double val; + + double to_double() const + { + return (double) val; + } + + double to_j2000() const + { + return (double) (val - MJD_j2000); + } +}; - template - void serialize(ARCHIVE& ar, const unsigned int& version) +struct UtcTime +{ + long double bigTime; + + UtcTime operator +(const double t) const + { + UtcTime time = *this; + + time.bigTime += t; + + return time; + } + + string to_string(int n) const { - long int time_int = time; - ar & time_int; - time = time_int; + GTime gTime; + gTime.bigTime = this->bigTime; + + return gTime.to_string(n); } - GTime roundTime( - int period) const + UtcTime() { - GTime roundedTime = *this; - //round to nearest chunk by integer arithmetic - long int roundTimeTime = roundedTime.time; - roundTimeTime /= period; - roundTimeTime *= period; - roundedTime.time = roundTimeTime; - return roundedTime; } + + operator GTime() const; }; +struct GEpoch : array +{ + GTime toGTime() const; + + operator GTime() const; + + double& year; + double& month; + double& day; + double& hour; + double& min; + double& sec; + + GEpoch( + double yearVal = 0, + double monthVal = 0, + double dayVal = 0, + double hourVal = 0, + double minVal = 0, + double secVal = 0) + : year { (*this)[0]}, + month { (*this)[1]}, + day { (*this)[2]}, + hour { (*this)[3]}, + min { (*this)[4]}, + sec { (*this)[5]} + { + year = yearVal; + month = monthVal; + day = dayVal; + hour = hourVal; + min = minVal; + sec = secVal; + } -GTime gpst2utc (GTime t); -GTime utc2gpst (GTime t); -GTime gpst2bdt (GTime t); -GTime bdt2gpst (GTime t); -GTime timeget (void); -double time2doy(GTime t); -double utc2gmst (GTime t, double ut1_utc); -int adjgpsweek(int week); + GEpoch( + const GEpoch& other) + : year { (*this)[0]}, + month { (*this)[1]}, + day { (*this)[2]}, + hour { (*this)[3]}, + min { (*this)[4]}, + sec { (*this)[5]} + { + //special copy constructor to deal with aliases + year = other.year; + month = other.month; + day = other.day; + hour = other.hour; + min = other.min; + sec = other.sec; + } + + GEpoch& operator = ( + const GEpoch& other) + { + year = other.year; + month = other.month; + day = other.day; + hour = other.hour; + min = other.min; + sec = other.sec; + + return *this; + } +}; -/* time and string functions -------------------------------------------------*/ -double str2num(const char *s, int i, int n); -GTime epoch2time (const double *ep); -GTime yds2time (const int* yds); +struct UYds : array +{ + int& year; + int& doy; + int& sod; + + UYds( + int yearval = 0, + int doyVal = 0, + int sodVal = 0) + : year{ (*this)[0]}, + doy { (*this)[1]}, + sod { (*this)[2]} + { + year = yearval; + doy = doyVal; + sod = sodVal; + } + + UYds( + const UYds& yds) + : year{ (*this)[0]}, + doy { (*this)[1]}, + sod { (*this)[2]} + { + //special copy constructor to deal with aliases + year = yds.year; + doy = yds.doy; + sod = yds.sod; + } + + UYds& operator = ( + const UYds& other) + { + year = other.year; + doy = other.doy; + sod = other.sod; + + return *this; + } + + UYds( + const GTime& time) + : year{ (*this)[0]}, + doy { (*this)[1]}, + sod { (*this)[2]} + { + double leap = leapSeconds(time); + GTime utc_Time = (time - leap); + GEpoch ep = utc_Time; + + //make new time with only the year of the input one, + GEpoch ep0(2000, 1, 1, 0, 0, 0); + ep0[0] = ep[0]; + + //subtract off the years + Duration toy = utc_Time - (GTime) ep0; -void time2epoch(GTime t, double *ep); -void epoch2yds(double *ep, int *yds); + year = (int) ep[0]; + doy = toy.to_int() / 86400 + 1; //(doy in bias SINEX (where yds is common) starts at 1) + sod = toy.to_int() % 86400; + } + + UYds& operator +=( + const double offset) + { + sod += offset; + while (sod > secondsInDay) { sod -= secondsInDay; doy++; } + while (sod < 0) { sod += secondsInDay; doy--; } + + while (doy > 366) { doy -= 365; year++; } + while (doy < 1) { doy += 365; year--; } //todo aaron, ew + + return *this; + } + + UYds& operator = ( + const GTime& time) + { + *this = UYds(time); + + return *this; + } + + operator GTime() const; +}; + +UtcTime gpst2utc (GTime t); +GTime utc2gpst (UtcTime t); + +double str2num(const char *s, int i, int n); GTime gpst2time(int week, double sec); double time2gpst(GTime t, int *week = nullptr); -GTime gst2time(int week, double sec); -double time2gst(GTime t, int *week = nullptr); - GTime bdt2time(int week, double sec); double time2bdt(GTime t, int *week = nullptr); @@ -222,14 +613,13 @@ int str2time( int n, GTime& t); - void jd2ymdhms(const double jd, double *ep); double ymdhms2jd(const double time[6]); -double gpst2mjd(const GTime time); - -double utc2mjd(const GTime time); - -#endif +GTime nearestTime( + GTime referenceEpoch, + double tom, + GTime nearTime, + int mod); diff --git a/src/cpp/common/gpx.cpp b/src/cpp/common/gpx.cpp index 351f47cad..0593a3713 100644 --- a/src/cpp/common/gpx.cpp +++ b/src/cpp/common/gpx.cpp @@ -1,11 +1,12 @@ #include -#include "streamTrace.hpp" +#include "coordinates.hpp" #include "constants.hpp" #include "algebra.hpp" #include "common.hpp" #include "gTime.hpp" +#include "trace.hpp" #include #include @@ -46,7 +47,7 @@ void writeGPXHeader( } output << gpxHeader; - output << ""; + output << ""; output << " \n"; output << "" << "" << name << "\n" @@ -56,12 +57,14 @@ void writeGPXHeader( void writeGPXEntry( Trace& output, + string id, KFState& kfState) { - double xyz[3]; + VectorEcef xyz; for (auto [kfKey, index] : kfState.kfIndexMap) { - if (kfKey.type != KF::REC_POS) + if ( kfKey.type != KF::REC_POS + ||kfKey.str != id) { continue; } @@ -69,17 +72,16 @@ void writeGPXEntry( kfState.getKFValue(kfKey, xyz[kfKey.num]); } - double pos[3]; - ecef2pos(xyz, pos); + VectorPos pos = ecef2pos(xyz); output << std::setprecision(10); output << " " - << "" << pos[2] << "" - << "" + << "" << pos.hgt() << "" + << "" << "\n"; } @@ -105,7 +107,7 @@ void writeGPX( output.seekp(gpxEndOfContentPositionMap[filename]); - writeGPXEntry(output, kfState); + writeGPXEntry(output, id, kfState); gpxEndOfContentPositionMap[filename] = output.tellp(); diff --git a/src/cpp/common/gpx.hpp b/src/cpp/common/gpx.hpp index 01c64718e..9fa5705f7 100644 --- a/src/cpp/common/gpx.hpp +++ b/src/cpp/common/gpx.hpp @@ -1,6 +1,5 @@ -#ifndef __GPX_HPP__ -#define __GPX_HPP__ +#pragma once @@ -8,5 +7,3 @@ void writeGPX( string filename, string id, KFState& kfState); - -#endif diff --git a/src/cpp/common/icdDecoder.hpp b/src/cpp/common/icdDecoder.hpp new file mode 100644 index 000000000..85b008589 --- /dev/null +++ b/src/cpp/common/icdDecoder.hpp @@ -0,0 +1,254 @@ + +#pragma once + +#include "rtcmDecoder.hpp" + +struct icdDecoder +{ + map>> subframeMap; + + /* decode Galileo I/NAV ephemeris ---------------------------------------------- + * decode Galileo I/NAV (ref [5] 4.3) + * args : unsigned char *buff I Galileo I/NAV subframe bits + * buff[ 0-15]: I/NAV word type 0 (128 bit) + * buff[16-31]: I/NAV word type 1 + * buff[32-47]: I/NAV word type 2 + * buff[48-63]: I/NAV word type 3 + * buff[64-79]: I/NAV word type 4 + * buff[80-95]: I/NAV word type 5 + * eph_t *eph IO ephemeris structure + * return : status (1:ok,0:error) + *-----------------------------------------------------------------------------*/ +// int decode_gal_inav( +// const unsigned char* buff, +// eph_t* eph) +// { +// double tow, toc, tt, sqrtA; +// int i, time_f, week, svid, e5b_hs, e1b_hs, e5b_dvs, e1b_dvs, type[6], iod_nav[4]; +// +// i = 0; /* word type 0 */ +// type[0] = getbitu(buff, i, 6); i += 6; +// time_f = getbitu(buff, i, 2); i += 2 + 88; +// week = getbitu(buff, i, 12); i += 12; /* gst-week */ +// tow = getbitu(buff, i, 20); +// +// i = 128; /* word type 1 */ +// type[1] = getbitu(buff, i, 6); i += 6; +// iod_nav[0] = getbitu(buff, i, 10); i += 10; +// eph->toes = getbitu(buff, i, 14) * 60.0; i += 14; +// eph->M0 = getbits(buff, i, 32) * P2_31 * SC2RAD; i += 32; +// eph->e = getbitu(buff, i, 32) * P2_33; i += 32; +// sqrtA = getbitu(buff, i, 32) * P2_19; +// +// i = 128 * 2; /* word type 2 */ +// type[2] = getbitu(buff, i, 6); i += 6; +// iod_nav[1] = getbitu(buff, i, 10); i += 10; +// eph->OMG0 = getbits(buff, i, 32) * P2_31 * SC2RAD; i += 32; +// eph->i0 = getbits(buff, i, 32) * P2_31 * SC2RAD; i += 32; +// eph->omg = getbits(buff, i, 32) * P2_31 * SC2RAD; i += 32; +// eph->idot = getbits(buff, i, 14) * P2_43 * SC2RAD; +// +// i = 128 * 3; /* word type 3 */ +// type[3] = getbitu(buff, i, 6); i += 6; +// iod_nav[2] = getbitu(buff, i, 10); i += 10; +// eph->OMGd = getbits(buff, i, 24) * P2_43 * SC2RAD; i += 24; +// eph->deln = getbits(buff, i, 16) * P2_43 * SC2RAD; i += 16; +// eph->cuc = getbits(buff, i, 16) * P2_29; i += 16; +// eph->cus = getbits(buff, i, 16) * P2_29; i += 16; +// eph->crc = getbits(buff, i, 16) * P2_5; i += 16; +// eph->crs = getbits(buff, i, 16) * P2_5; i += 16; +// eph->sva = getbitu(buff, i, 8); +// +// i = 128 * 4; /* word type 4 */ +// type[4] = getbitu(buff, i, 6); i += 6; +// iod_nav[3] = getbitu(buff, i, 10); i += 10; +// svid = getbitu(buff, i, 6); i += 6; +// eph->cic = getbits(buff, i, 16) * P2_29; i += 16; +// eph->cis = getbits(buff, i, 16) * P2_29; i += 16; +// toc = getbitu(buff, i, 14) * 60.0; i += 14; +// eph->f0 = getbits(buff, i, 31) * P2_34; i += 31; +// eph->f1 = getbits(buff, i, 21) * P2_46; i += 21; +// eph->f2 = getbits(buff, i, 6) * P2_59; +// +// i = 128 * 5; /* word type 5 */ +// type[5] = getbitu(buff, i, 6); i += 6 + 41; +// eph->tgd[0] = getbits(buff, i, 10) * P2_32; i += 10; /* BGD E5a/E1 */ +// eph->tgd[1] = getbits(buff, i, 10) * P2_32; i += 10; /* BGD E5b/E1 */ +// e5b_hs = getbitu(buff, i, 2); i += 2; +// e1b_hs = getbitu(buff, i, 2); i += 2; +// e5b_dvs = getbitu(buff, i, 1); i += 1; +// e1b_dvs = getbitu(buff, i, 1); +// +// /* test word types */ +// if ( type[0] != 0 +// || type[1] != 1 +// || type[2] != 2 +// || type[3] != 3 +// || type[4] != 4) +// { +// trace(3, "decode_gal_inav error: type=%d %d %d %d %d\n", type[0], type[1], type[2], type[3], type[4]); +// return 0; +// } +// +// /* test word type 0 time field */ +// if (time_f != 2) +// { +// trace(3, "decode_gal_inav error: word0-time=%d\n", time_f); +// return 0; +// } +// +// /* test consistency of iod_nav */ +// if ( iod_nav[0] != iod_nav[1] +// || iod_nav[0] != iod_nav[2] +// || iod_nav[0] != iod_nav[3]) +// { +// trace(3, "decode_gal_inav error: ionav=%d %d %d %d\n", iod_nav[0], iod_nav[1], iod_nav[2], iod_nav[3]); +// return 0; +// } +// +// if (!(eph->sat = satno(SYS_GAL, svid))) +// { +// trace(2, "decode_gal_inav svid error: svid=%d\n", svid); +// return 0; +// } +// +// eph->A = sqrtA * sqrtA; +// eph->iode = eph->iodc = iod_nav[0]; +// eph->svh = (e5b_hs << 7) | (e5b_dvs << 6) | (e1b_hs << 1) | e1b_dvs; +// eph->ttr = gst2time(week, tow); +// tt = timediff(gst2time(week, eph->toes), eph->ttr); /* week complient to toe */ +// +// if (tt > +302400.0) week--; +// else if (tt < -302400.0) week++; +// +// eph->toe = gst2time(week, eph->toes); +// eph->toc = gst2time(week, toc); +// eph->week = week + 1024; /* gal-week = gst-week + 1024 */ +// eph->code = 1; /* data source = I/NAV E1B */ +// +// return 1; +// } + + /* decode gps/qzss navigation data subframe 1 + */ + bool decodeGPSSubframe1( + vector& data, + Eph& eph) + { + int i = 24; + + double tow = getbituInc(data, i, 17) * 6.0; i = 48; + int week = getbituInc(data, i, 10); + eph.code = getbituInc(data, i, 2); + eph.sva = getbituInc(data, i, 4); + int svh = getbituInc(data, i, 6); + int iodc0 = getbituInc(data, i, 2); + eph.flag = getbituInc(data, i, 1); i += 87; + int tgd = getbitsInc(data, i, 8); + int iodc1 = getbituInc(data, i, 8); + double toc = getbituInc(data, i, 16) * 16.0; + eph.f2 = getbitsInc(data, i, 8) * P2_55; + eph.f1 = getbitsInc(data, i, 16) * P2_43; + eph.f0 = getbitsInc(data, i, 22) * P2_31; + + eph.svh = (E_Svh) svh; + eph.tgd[0] = tgd == -128 ? 0.0 : tgd * P2_31; /* ref [4] */ + eph.iodc = (iodc0 << 8) + iodc1; +// eph.week = adjgpsweek(week); /* week of tow */ //todo aaron +// eph.ttm = gpst2time(eph.week, tow); +// eph.toc = gpst2time(eph.week, toc); + + return true; + } + + /* decode gps/qzss navigation data subframe 2 + */ + bool decodeGPSSubframe2( + vector& data, + Eph& eph) + { + double sqrtA; + int i = 48; + + eph.iode = getbituInc(data, i, 8); + eph.crs = getbitsInc(data, i, 16) * P2_5; + eph.deln = getbitsInc(data, i, 16) * P2_43 * SC2RAD; + eph.M0 = getbitsInc(data, i, 32) * P2_31 * SC2RAD; + eph.cuc = getbitsInc(data, i, 16) * P2_29; + eph.e = getbituInc(data, i, 32) * P2_33; + eph.cus = getbitsInc(data, i, 16) * P2_29; + sqrtA = getbituInc(data, i, 32) * P2_19; + eph.toes = getbituInc(data, i, 16) * 16.0; + eph.fit = getbituInc(data, i, 1) ? 0.0 : 4.0; /* 0:4hr,1:>4hr */ + + eph.A = SQR(sqrtA); + + return true; + } + + /* decode gps/qzss navigation data subframe 3 + */ + bool decodeGPSSubframe3( + vector& data, + Eph& eph) + { + int i = 48; + + eph.cic = getbitsInc(data, i, 16) * P2_29; + eph.OMG0 = getbitsInc(data, i, 32) * P2_31 * SC2RAD; + eph.cis = getbitsInc(data, i, 16) * P2_29; + eph.i0 = getbitsInc(data, i, 32) * P2_31 * SC2RAD; + eph.crc = getbitsInc(data, i, 16) * P2_5; + eph.omg = getbitsInc(data, i, 32) * P2_31 * SC2RAD; + eph.OMGd = getbitsInc(data, i, 24) * P2_43 * SC2RAD; + int iode = getbituInc(data, i, 8); + eph.idot = getbitsInc(data, i, 14) * P2_43 * SC2RAD; + + /* check iode and iodc consistency */ + if ( iode != eph.iode + || iode != (eph.iodc & 0xFF)) + { + return false; + } + + /* adjustment for week handover */ + // double tow = time2gpst(eph.ttm, &eph.week); + // double toc = time2gpst(eph.toc); + double tow = GTow(eph.ttm); + double toc = GTow(eph.toc); + eph.week = GWeek(eph.ttm); + + if (eph.toes < tow - 302400.0) {eph.week++; tow -= 604800.0;} + else if (eph.toes > tow + 302400.0) {eph.week--; tow += 604800.0;} + + eph.toe = gpst2time(eph.week, eph.toes); + eph.toc = gpst2time(eph.week, toc); + eph.ttm = gpst2time(eph.week, tow); + + return true; + } + + /* decode gps/qzss navigation data frame */ + int decodeGpsSubframe( + vector& data, ///< data[0-29]: 24 bits x 10 words= + Eph& eph) + { + if (data.empty()) + { + return 0; + } + + int id = getbitu(data, 43, 3); /* subframe id */ + +// trace(3, "decodefrm: id=%d\n", id); + + switch (id) + { + case 1: return decodeGPSSubframe1(data, eph); + case 2: return decodeGPSSubframe2(data, eph); + case 3: return decodeGPSSubframe3(data, eph); + } + return 0; + } + +}; diff --git a/src/cpp/common/instrument.cpp b/src/cpp/common/instrument.cpp index f6a6b307a..85ab3421d 100644 --- a/src/cpp/common/instrument.cpp +++ b/src/cpp/common/instrument.cpp @@ -11,9 +11,10 @@ map Instrument::timeMap; map Instrument::callMap; -Instrument::Instrument(string desc) +Instrument::Instrument(string desc, bool print) { #ifdef ENABLE_UNIT_TESTS + this->print = print; start = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); description = desc; #endif @@ -29,6 +30,8 @@ Instrument::~Instrument() timeMap[description] += stop - start; callMap[description] += 1; + if (print) + printf("\n%40s took %15ld us", description.c_str(), stop - start); #endif } @@ -39,10 +42,21 @@ void Instrument::printStatus() { #ifdef ENABLE_UNIT_TESTS std::cout << std::endl << "Instrumentation:\n"; + + map sortedTimes; + for (auto& [desc, time] : timeMap) { auto calls = callMap[desc]; - printf("%30s took %15ldus over %5ld calls, averaging %ld\n", desc.c_str(), time, calls, time/calls); + + char buff[1000]; + snprintf(buff, sizeof(buff), "%40s took %15ld us over %5ld calls, averaging %ld\n", desc.c_str(), time, calls, time/calls); + sortedTimes[time] = buff; + } + + for (auto& [time, thing] : sortedTimes) + { + std::cout << thing; } #endif } diff --git a/src/cpp/common/instrument.hpp b/src/cpp/common/instrument.hpp index 79af1197a..61180eaa4 100644 --- a/src/cpp/common/instrument.hpp +++ b/src/cpp/common/instrument.hpp @@ -1,7 +1,5 @@ -#ifndef __INSTRUMENT_HPP__ -#define __INSTRUMENT_HPP__ - +#pragma once #include #include @@ -14,15 +12,18 @@ struct Instrument { static map timeMap; static map callMap; + + bool print = false; size_t start; string description; - Instrument(string desc); + Instrument( + string desc, + bool print = false); ~Instrument(); static void printStatus(); }; -#endif diff --git a/src/cpp/common/linearCombo.cpp b/src/cpp/common/linearCombo.cpp index 6e4fc2f85..6ede29054 100644 --- a/src/cpp/common/linearCombo.cpp +++ b/src/cpp/common/linearCombo.cpp @@ -2,11 +2,11 @@ // #pragma GCC optimize ("O0") #include "linearCombo.hpp" -#include "streamTrace.hpp" #include "testUtils.hpp" #include "satStat.hpp" #include "debug.hpp" #include "acsQC.hpp" +#include "trace.hpp" /** Create combinations between specific observation values @@ -110,7 +110,7 @@ S_LC& getLC( /** Get/calculate linear combination values for an observation */ S_LC& getLC( - Obs& obs, ///< Observation to compute values form + GObs& obs, ///< Observation to compute values form lc_t& lcBase, ///< Linear combination base object E_FType fA, ///< Frequency type A E_FType fB) ///< Frequency type B @@ -118,7 +118,7 @@ S_LC& getLC( //try to get existing LC from the observation's satStat object S_LC& lc = getLC(lcBase, fA, fB); - if (lc.valid == true) + if (lc.valid) { return lc; } @@ -170,7 +170,7 @@ S_LC& getLC( /** Prepare a base object for linear combinations using observation data */ void lcPrepareBase( - Obs& obs, ///< Observation data to use + GObs& obs, ///< Observation data to use lc_t& lcBase) ///< Linear combination base object to prepare { lcBase.time = obs.time; @@ -179,9 +179,9 @@ void lcPrepareBase( for (auto& [ft, sig] : obs.Sigs) { auto& satStat = *obs.satStat_ptr; - auto& sigStat = satStat.sigStatMap[ft]; + auto& sigStat = satStat.sigStatMap[ft2string(ft)]; - sigStat.lambda = obs.satNav_ptr->lamMap[ft]; //todo aaron need to extend codes slightly to separate GPS/CMP signals with same name. + sigStat.lambda = obs.satNav_ptr->lamMap[ft]; //populate variables for later use. lcBase.L_m[ft] = sig.L * sigStat.lambda; @@ -193,16 +193,11 @@ void lcPrepareBase( */ void obs2lc( Trace& trace, ///< Trace to output to - Obs& obs, ///< Observation to prepare combinations for + GObs& obs, ///< Observation to prepare combinations for lc_t& lcBase) ///< Linear combination base object to use { - TestStack ts(__FUNCTION__ + obs.Sat.id()); - int lv = 3; - - int week; - double sec = time2gpst(obs.time, &week); - + int sys = obs.Sat.sys; /* SBS and LEO are not included */ @@ -213,34 +208,53 @@ void obs2lc( return; } + E_FType frq1 = F1; + E_FType frq2 = F2; + E_FType frq3 = F5; + if (sys == E_Sys::GLO) + { + frq1 = G1; + frq2 = G2; + } + if (sys == E_Sys::GAL) + frq2 = F7; + if (sys == E_Sys::BDS) + { + frq1 = B1; + frq2 = B3; + frq3 = F5; + } + + char strprefix[64]; - sprintf(strprefix, "%3d %7.1f sat=%4s", week, sec, obs.Sat.id().c_str()); + snprintf(strprefix, sizeof(strprefix), "%3s sat=%4s", obs.time.to_string().c_str(), obs.Sat.id().c_str()); lcPrepareBase(obs, lcBase); -// artificialSlip(trace, obs, lcBase, strprefix); - //iterate pairwise over the frequencies. - S_LC& lc12 = getLC(obs, lcBase, F1, F2); - S_LC& lc15 = getLC(obs, lcBase, F1, F5); - S_LC& lc25 = getLC(obs, lcBase, F2, F5); - - tracepdeex(lv, trace, "%s zd L -- L1 =%14.4f L2 =%14.4f L5 =%14.4f\n", strprefix, lcBase.L_m[F1], lcBase.L_m[F2], lcBase.L_m[F5]); - tracepdeex(lv, trace, "%s zd P -- P1 =%14.4f P2 =%14.4f P5 =%14.4f\n", strprefix, lcBase.P[F1], lcBase.P[F2], lcBase.P[F5]); - tracepdeex(lv, trace, "%s gf L -- gf12=%14.4f gf15=%14.4f gf25=%14.4f\n", strprefix, lc12.GF_Phas_m, lc15.GF_Phas_m, lc25.GF_Phas_m); - tracepdeex(lv, trace, "%s gf P -- gf12=%14.4f gf15=%14.4f gf25=%14.4f\n", strprefix, lc12.GF_Code_m, lc15.GF_Code_m, lc25.GF_Code_m); - tracepdeex(lv, trace, "%s mw L -- mw12=%14.4f mw15=%14.4f mw25=%14.4f\n", strprefix, lc12.MW_c, lc15.MW_c, lc25.MW_c); - tracepdeex(lv, trace, "%s wl L -- wl12=%14.4f wl15=%14.4f wl25=%14.4f\n", strprefix, lc12.WL_Phas_m, lc15.WL_Phas_m, lc25.WL_Phas_m); - tracepdeex(lv, trace, "%s if L -- if12=%14.4f if15=%14.4f if25=%14.4f\n", strprefix, lc12.IF_Phas_m, lc15.IF_Phas_m, lc25.IF_Phas_m); - tracepdeex(lv, trace, "%s if P -- if12=%14.4f if15=%14.4f if25=%14.4f\n", strprefix, lc12.IF_Code_m, lc15.IF_Code_m, lc25.IF_Code_m); - tracepdeex(lv, trace, "%s mp P -- mp1 =%14.4f mp2 =%14.4f mp5 =%14.4f\n", strprefix, lcBase.mp[F1], lcBase.mp[F2], lcBase.mp[F5]); - - TestStack::testMat("lc12.GF_Phas_m", lc12.GF_Phas_m); - TestStack::testMat("lc12.GF_Code_m", lc12.GF_Code_m); - TestStack::testMat("lc12.MW_c", lc12.MW_c); - TestStack::testMat("lc15.GF_Phas_m", lc15.GF_Phas_m); - TestStack::testMat("lc15.GF_Code_m", lc15.GF_Code_m); - TestStack::testMat("lc15.MW_c", lc15.MW_c); + S_LC& lc12 = getLC(obs, lcBase, frq1, frq2); + S_LC& lc15 = getLC(obs, lcBase, frq1, frq3); + S_LC& lc25 = getLC(obs, lcBase, frq2, frq3); + + tracepdeex(lv, trace, "%s zd L -- L1 =%14.4f L2 =%14.4f L5 =%14.4f\n", strprefix, lcBase.L_m[frq1], lcBase.L_m[frq2], lcBase.L_m[frq3]); + tracepdeex(lv, trace, "%s zd P -- P1 =%14.4f P2 =%14.4f P5 =%14.4f\n", strprefix, lcBase.P[frq1], lcBase.P[frq2], lcBase.P[frq3]); + tracepdeex(lv, trace, "%s gf L -- gf12=%14.4f gf15=%14.4f gf25=%14.4f\n", strprefix, lc12.GF_Phas_m, lc15.GF_Phas_m, lc25.GF_Phas_m); + tracepdeex(lv, trace, "%s gf P -- gf12=%14.4f gf15=%14.4f gf25=%14.4f\n", strprefix, lc12.GF_Code_m, lc15.GF_Code_m, lc25.GF_Code_m); + tracepdeex(lv, trace, "%s mw L -- mw12=%14.4f mw15=%14.4f mw25=%14.4f\n", strprefix, lc12.MW_c, lc15.MW_c, lc25.MW_c); + tracepdeex(lv, trace, "%s wl L -- wl12=%14.4f wl15=%14.4f wl25=%14.4f\n", strprefix, lc12.WL_Phas_m, lc15.WL_Phas_m, lc25.WL_Phas_m); + tracepdeex(lv, trace, "%s if L -- if12=%14.4f if15=%14.4f if25=%14.4f\n", strprefix, lc12.IF_Phas_m, lc15.IF_Phas_m, lc25.IF_Phas_m); + tracepdeex(lv, trace, "%s if P -- if12=%14.4f if15=%14.4f if25=%14.4f\n", strprefix, lc12.IF_Code_m, lc15.IF_Code_m, lc25.IF_Code_m); + tracepdeex(lv, trace, "%s mp P -- mp1 =%14.4f mp2 =%14.4f mp5 =%14.4f\n", strprefix, lcBase.mp[frq1], lcBase.mp[frq2], lcBase.mp[frq3]); + + traceJson(lv, trace, obs.time, + { + {"data", __FUNCTION__ }, + {"Sat", obs.Sat.id() } + }, + { + {"L1", lcBase.L_m[frq1] }, {"L2", lcBase.L_m[frq2] }, //etc + {"mp1", lcBase.mp[frq1] }, {"mp2", lcBase.mp[frq2] }, + }); } /** Function to prepare some predefined linear combinations from a list of observations @@ -249,21 +263,16 @@ void obs2lcs( Trace& trace, ///< Trace to output to ObsList& obsList) ///< List of bservation to prepare combinations for { - TestStack ts(__FUNCTION__); - - int week; int lv = 3; if (obsList.empty()) { return; } - - double sec = time2gpst(obsList.front().time, &week); - tracepdeex(lv, trace, "\n *-------- PDE form LC %3d %7.1f --------*\n", week, sec); + tracepdeex(lv, trace, "\n *-------- PDE form LC %s --------*\n", obsList.front()->time.to_string().c_str()); - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { if (obs.exclude) { diff --git a/src/cpp/common/linearCombo.hpp b/src/cpp/common/linearCombo.hpp index 1d7296ece..b4395ff90 100644 --- a/src/cpp/common/linearCombo.hpp +++ b/src/cpp/common/linearCombo.hpp @@ -1,14 +1,14 @@ -#ifndef __LINEAR_COMBO_H_ -#define __LINEAR_COMBO_H_ + +#pragma once #include using std::map; #include "observations.hpp" -#include "streamTrace.hpp" -#include "gTime.hpp" #include "satSys.hpp" +#include "gTime.hpp" +#include "trace.hpp" #include "enums.h" @@ -39,13 +39,6 @@ typedef struct double lam_B; double lam_WL; double lam_NL; -// double gf; ///< geometry-free LC for phase (m) -// double gfc; ///< geometry-free LC for code (m) -// double wl; ///< wide-lane LC for phase (m) -// double If; ///< ionosphere-free LC for phase (m) -// double ifc; ///< ionosphere-free LC for code (m) -// double mw; ///< Melbourne Wenbunna LC for phase (cycle) -// double nl; ///< Narrow-lane LC for code (m) } S_LC; typedef struct @@ -65,10 +58,9 @@ struct Navigation; S_LC getLC(double L_A, double L_B, double P_A, double P_B, double lamA, double lamB, double* c1_out, double* c2_out); S_LC& getLC(lc_t& lcBase, E_FType fA, E_FType fB); -S_LC& getLC(Obs& obs, lc_t& lcBase, E_FType fA, E_FType fB); +S_LC& getLC(GObs& obs, lc_t& lcBase, E_FType fA, E_FType fB); void obs2lcs( Trace& trace, ObsList& obsList); -#endif diff --git a/src/cpp/common/metaData.hpp b/src/cpp/common/metaData.hpp index 299086c8d..28e490b71 100644 --- a/src/cpp/common/metaData.hpp +++ b/src/cpp/common/metaData.hpp @@ -1,6 +1,5 @@ -#ifndef __METADATA__HPP__ -#define __METADATA__HPP__ +#pragma once #include @@ -12,10 +11,12 @@ using std::string; #define ERP_FILENAME_STR ((string)"erpFilename") #define TRACE_FILENAME_STR ((string)"traceFilename") #define TROP_FILENAME_STR ((string)"tropFilename") -#define SOLUTION_FILENAME_STR ((string)"solutionFilename") +#define COST_FILENAME_STR ((string)"costFilename") +#define SOL_FILENAME_STR ((string)"solutionFilename") #define IONEX_FILENAME_STR ((string)"ionexFilename") #define IONSTEC_FILENAME_STR ((string)"ionstecFilename") #define ION_FILENAME_STR ((string)"ionFilename") +#define SP3_FILENAME_STR ((string)"sp3Filename") +#define CLK_FILENAME_STR ((string)"clkFilename") -#endif diff --git a/src/cpp/common/mongo.cpp b/src/cpp/common/mongo.cpp index 35b0f56ac..9ea786272 100644 --- a/src/cpp/common/mongo.cpp +++ b/src/cpp/common/mongo.cpp @@ -2,9 +2,9 @@ // #pragma GCC optimize ("O0") - #include "observations.hpp" #include "rtcmEncoder.hpp" +#include "instrument.hpp" #include "acsConfig.hpp" #include "satStat.hpp" #include "common.hpp" @@ -14,109 +14,80 @@ #include -namespace sinks = boost::log::sinks; +using bsoncxx::types::b_date; -Mongo* mongo_ptr = nullptr; +namespace sinks = boost::log::sinks; -void mongoooo() -{ - if (mongo_ptr) - return; +Mongo* localMongo_ptr = nullptr; +Mongo* remoteMongo_ptr = nullptr; - if (acsConfig.enable_mongo == false) - { - return; - } - - try - { - mongo_ptr = new Mongo(acsConfig.mongo_uri); - } - catch (...) {} // just eat any exception - if (mongo_ptr == nullptr) - { - return; - } +mongocxx::instance Mongo::instance; //single static instance of the driver - Mongo& mongo = *mongo_ptr; - auto c = mongo.pool.acquire(); - mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; - - BOOST_LOG_TRIVIAL(info) << "Mongo connecting to database : " << acsConfig.mongo_database; - try +void mongoooo() +{ + for (auto config_ptr : {&acsConfig.localMongo, &acsConfig.remoteMongo}) { - if (acsConfig.delete_mongo_history) - { - db["Measurements"] .drop(); - db["MeasurementsIndex"] .drop(); - db["States"] .drop(); - db["StatesIndex"] .drop(); - db["Console"] .drop(); - db["SSRData"] .drop(); - } + Mongo** mongo_ptr_ptr; + + if (config_ptr == &acsConfig.localMongo) mongo_ptr_ptr = &localMongo_ptr; + else mongo_ptr_ptr = &remoteMongo_ptr; + + auto& mongo_ptr = *mongo_ptr_ptr; + + if (mongo_ptr) + continue; - //create compound and simple indicies for most useful types + auto& config = *config_ptr; - db["Measurements"] .create_index( - document{} - << "Epoch" << 1 - << "Site" << 1 - << "Sat" << 1 - << finalize, - {}); + if (config.enable == false) + { + continue; + } - db["MeasurementsIndex"] .create_index( - document{} - << "Site" << 1 - << "Sat" << 1 - << finalize, - {}); - - db["States"] .create_index( - document{} - << "Epoch" << 1 - << "Site" << 1 - << "Sat" << 1 - << finalize, - {}); - - db["StatesIndex"] .create_index( - document{} - << "Site" << 1 - << "Sat" << 1 - << finalize, - {}); - - db["SSRData"] .create_index( - document{} - << "Epoch" << 1 - << "Sat" << 1 - << "Type" << 1 - << "Data" << 1 - << "ObsCode" << 1 - << finalize, - {}); - - if (acsConfig.output_mongo_logs) + try + { + mongo_ptr = new Mongo(config.uri); + } + catch (...) {} // just eat any exception + + if (mongo_ptr == nullptr) { - // Construct the sink - using MongoLogSink = sinks::synchronous_sink; + continue; + } - boost::shared_ptr mongoLogSink = boost::make_shared(); + Mongo& mongo = *mongo_ptr; - // Register the sink in the logging core - boost::log::core::get()->add_sink(mongoLogSink); + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[config.database]; + BOOST_LOG_TRIVIAL(info) << "Mongo connecting to database : " << config.database << " @ " << config.uri; + try + { + if (config.delete_history) + { + db.drop(); + } + + if (config.output_logs) + { + // Construct the sink + using MongoLogSink = sinks::synchronous_sink; + + boost::shared_ptr mongoLogSink = boost::make_shared(); + + // Register the sink in the logging core + boost::log::core::get()->add_sink(mongoLogSink); + } + + BOOST_LOG_TRIVIAL(info) << "Mongo connected to database : " << config.database; + } + catch (...) + { + BOOST_LOG_TRIVIAL(error) << "Error: Mongo connection failed - check if service is running at " << config.uri; + exit(1); } - - BOOST_LOG_TRIVIAL(info) << "Mongo connected to database : " << acsConfig.mongo_database; - } - catch (...) - { - BOOST_LOG_TRIVIAL(error) << "Error: Mongo connection failed - check if service is running at " << acsConfig.mongo_uri; - exit(1); } } @@ -124,22 +95,22 @@ void MongoLogSinkBackend::consume( boost::log::record_view const& rec, sinks::basic_formatted_sink_backend::string_type const& log_string) { - if (mongo_ptr == nullptr) + if (localMongo_ptr == nullptr) { return; } - Mongo& mongo = *mongo_ptr; + Mongo& mongo = *localMongo_ptr; auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.localMongo.database]; mongocxx::collection coll = db ["Console"]; //add a azimuth to a chunk coll.insert_one( document{} - << "Epoch" << bsoncxx::types::b_date {std::chrono::system_clock::from_time_t(tsync.time)} + << "Epoch" << b_date {std::chrono::system_clock::from_time_t((time_t)((PTime)tsync).bigTime)} << "Log" << log_string.c_str() << finalize ); diff --git a/src/cpp/common/mongo.hpp b/src/cpp/common/mongo.hpp index 6c5954945..ae562aa6f 100644 --- a/src/cpp/common/mongo.hpp +++ b/src/cpp/common/mongo.hpp @@ -1,6 +1,5 @@ -#ifndef ___MONGO_HPP__ -#define ___MONGO_HPP__ +#pragma once #include @@ -19,26 +18,32 @@ #include #include +#include +#include #include using std::string; +using std::vector; +using std::deque; using std::map; -#include "station.hpp" +#include "networkEstimator.hpp" #include "observations.hpp" +#include "station.hpp" #include "algebra.hpp" -#include "networkEstimator.hpp" struct DBEntry { - map> stringMap; - map> timeMap; - map> doubleMap; - map> intMap; - map> vectorMap; + map> stringMap; + map> timeMap; + map> doubleMap; + map> intMap; + map> vectorMap; + map, bool>> doubleArrayMap; + map, bool>> boolArrayMap; }; using bsoncxx::builder::stream::close_array; @@ -53,9 +58,9 @@ namespace sinks = boost::log::sinks; struct Mongo { - mongocxx::instance instance; // This should be done only once. - mongocxx::uri uri; - mongocxx::pool pool; + static mongocxx::instance instance; // This should be done only once. + mongocxx::uri uri; + mongocxx::pool pool; Mongo(string uriString) : uri{uriString}, pool{uri} { @@ -63,28 +68,54 @@ struct Mongo } }; -#define SSR_DATA "Data" -#define SSR_PHAS_BIAS "PBias" -#define SSR_CODE_BIAS "CBias" -#define SSR_EPHEMERIS "Eph" -#define SSR_CLOCK "Clk" - -#define SSR_DB "SSRData" - -#define SSR_EPOCH "Epoch" -#define SSR_UPDATED "Updated" -#define SSR_SAT "Sat" -#define SSR_IODE "Iode" -#define SSR_POS "Pos" -#define SSR_VEL "Vel" -#define SSR_OBSCODE "ObsCode" -#define SSR_BIAS "Bias" -#define SSR_VAR "Var" - -#define SSR_BRDC "Brdc" -#define SSR_PREC "Prec" - - +#define SSR_DB "SSRData" + +#define SSR_DATA "Data" +#define SSR_PHAS_BIAS "PBias" +#define SSR_CODE_BIAS "CBias" +#define SSR_EPHEMERIS "Eph" +#define SSR_CLOCK "Clk" + +#define IGS_ION_META "igsSSRMeta" +#define IGS_ION_ENTRY "igsSSREntry" + + +#define SSR_EPOCH "Epoch" +#define SSR_UPDATED "Updated" +#define SSR_SAT "Sat" +#define SSR_IODE "Iode" +#define SSR_POS "Pos" +#define SSR_VEL "Vel" +#define SSR_OBSCODE "ObsCode" +#define SSR_BIAS "Bias" +#define SSR_VAR "Var" + +#define IGS_ION_NLAY "ionoMetNlay" +#define IGS_ION_NBAS "ionoMetNbas" +#define IGS_ION_QLTY "ionoMetQlty" +#define SSR_ION_IND "ionoBasInd" +#define IGS_ION_HGT "ionoBasHgt" +#define IGS_ION_DEG "ionoBasDeg" +#define IGS_ION_ORD "ionoBasOrd" +#define IGS_ION_PAR "ionoBasPar" +#define IGS_ION_VAL "ionoBasVal" + +#define SSR_BRDC "Brdc" +#define SSR_PREC "Prec" + +#define REMOTE_DATA_DB "Remote" + +#define REMOTE_DATA "Data" +#define REMOTE_EPOCH "Epoch" +#define REMOTE_ORBIT "Orbit" +#define REMOTE_CLOCK "Clock" +#define REMOTE_SAT "Sat" +#define REMOTE_UPDATED "Updated" +#define REMOTE_POS "Pos" +#define REMOTE_VEL "Vel" +#define REMOTE_CLK "Clk" +#define REMOTE_CLK_DRIFT "ClkRate" +#define REMOTE_STR "Str" struct MongoLogSinkBackend : public sinks::basic_formatted_sink_backend { @@ -96,10 +127,14 @@ struct MongoLogSinkBackend : public sinks::basic_formatted_sink_backend lastBrdcIode; + template RETTYPE getStraddle( - GTime targetTime, + GTime referenceTime, deque& ssrVec) { RETTYPE ssr; ssr.valid = true; - //try to find a set of things that straddle the target time, with the same iode + //try to find a set of things that straddle the reference time, with the same iode int bestI = -1; int bestJ = -1; @@ -36,18 +41,12 @@ RETTYPE getStraddle( //no good, iodes dont match continue; } - -// if ( fabs(bestI.time.time - targetTime.time) > acsConfig. -// ||fabs(bestJ.time.time - targetTime.time) > acsConfig. -// { -// continue; -// } //these are acceptable - store them for later bestI = i; bestJ = j; - if (entryJ.time > targetTime) + if (entryJ.time > referenceTime) { //this is as close as we will come to a straddle break; @@ -68,13 +67,17 @@ RETTYPE getStraddle( return ssr; } -map mongoReadSSRData( - GTime targetTime, - SSRMeta ssrMeta, - int masterIod, - E_Sys targetSys) +/** Read orbits and clocks from Mongo DB +*/ +SsrOutMap mongoReadOrbClk( + GTime referenceTime, ///< reference time (t0) of SSR correction + SSRMeta& ssrMeta, ///< SSR message metadata + int masterIod, ///< IOD SSR + E_Sys targetSys) ///< target system { - map ssrOutMap; + SsrOutMap ssrOutMap; + + auto& mongo_ptr = remoteMongo_ptr; if (mongo_ptr == nullptr) { @@ -85,14 +88,13 @@ map mongoReadSSRData( Mongo& mongo = *mongo_ptr; auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.remoteMongo.database]; mongocxx::collection coll = db[SSR_DB]; - -// targetTime.time += 300; // std::cout << "\nTrying to get things for " << targetTime.to_string(0) << std::endl; - bsoncxx::types::b_date btime{std::chrono::system_clock::from_time_t(targetTime.time)}; + b_date btime{std::chrono::system_clock::from_time_t((time_t)((PTime)referenceTime).bigTime)}; + bool changeIod = false; auto sats = getSysSats(targetSys); for (auto Sat : sats) { @@ -103,9 +105,6 @@ map mongoReadSSRData( for (string data : {SSR_EPHEMERIS, SSR_CLOCK}) for (bool less : {false, true}) { - if (data == SSR_EPHEMERIS && 0) continue; - if (data == SSR_CLOCK && 0) continue; - string moreLess; int sortDir; if (less) { moreLess = "$lte"; sortDir = -1; } @@ -133,19 +132,18 @@ map mongoReadSSRData( for (auto doc : cursor) { - GTime timeUpdate; - GTime timeEpoch; - + PTime timeUpdate; auto tp = doc[SSR_UPDATED ].get_date(); - timeUpdate.time = std::chrono::system_clock::to_time_t(tp); + timeUpdate.bigTime = std::chrono::system_clock::to_time_t(tp); + PTime timeEpoch; tp = doc[SSR_EPOCH ].get_date(); - timeEpoch.time = std::chrono::system_clock::to_time_t(tp); + timeEpoch.bigTime = std::chrono::system_clock::to_time_t(tp); if (data == SSR_EPHEMERIS) { EphValues ephValues; - ephValues.time.time = std::chrono::system_clock::to_time_t(tp); + ephValues.time = timeEpoch; for (int i = 0; i < 3; i++) { @@ -155,7 +153,8 @@ map mongoReadSSRData( ephValues.precVel(i) = doc[SSR_VEL SSR_PREC + std::to_string(i)].get_double(); } - ephValues.iode = doc[SSR_IODE].get_int32(); + ephValues.ephVar = doc[SSR_VAR ].get_double(); + ephValues.iode = doc[SSR_IODE ].get_int32(); if (less) ephVec .push_front (ephValues); else ephVec .push_back (ephValues); @@ -166,12 +165,12 @@ map mongoReadSSRData( if (data == SSR_CLOCK) { ClkValues clkValues; - clkValues.time.time = std::chrono::system_clock::to_time_t(tp); + clkValues.time = timeEpoch; clkValues.brdcClk = doc[SSR_CLOCK SSR_BRDC].get_double(); clkValues.precClk = doc[SSR_CLOCK SSR_PREC].get_double(); - clkValues.iode = doc[SSR_IODE ].get_int32(); + clkValues.iode = doc[SSR_IODE ].get_int32(); // std::cout << Sat.id() << " less:" << less << " brdc:" << broadcast << " " << clkValues.time.to_string(0) << std::endl; @@ -200,11 +199,11 @@ map mongoReadSSRData( // std::cout << Sat.id() << "Final eprecs:" << " iode: " << a.iode << " "<< a.time.to_string(0) << std::endl; // } - //try to find a set of things that straddle the target time, with the same iode + //try to find a set of things that straddle the reference time, with the same iode //do for both broadcast and precise values SSROut ssrOut; - ssrOut.ephInput = getStraddle(targetTime, ephVec); - ssrOut.clkInput = getStraddle(targetTime, clkVec); + ssrOut.ephInput = getStraddle(referenceTime, ephVec); + ssrOut.clkInput = getStraddle(referenceTime, clkVec); if (ssrOut.ephInput.valid == false) { @@ -218,19 +217,64 @@ map mongoReadSSRData( } ssrOutMap[Sat] = ssrOut; + + if (ssrOut.ephInput.vals[0].iode != lastBrdcIode[Sat]) + { + changeIod = true; + lastBrdcIode[Sat] = ssrOut.ephInput.vals[0].iode; + } + } + + if (changeIod) + { + currentSSRIod++; + + if (currentSSRIod > 15) + currentSSRIod = 0; } + + masterIod = currentSSRIod; return ssrOutMap; } +/** Group and sort biases in Mongo DB to avoid unnecessary requests +*/ +void mongoGroupSortBias( + bsoncxx::builder::stream::document& doc) +{ + doc << "_id" + << open_document + << SSR_SAT << "$Sat" + << SSR_OBSCODE << "$ObsCode" + << close_document + + << "lastEpoch" + << open_document + << "$max" + << open_document + << "$mergeObjects" + << open_array + << open_document + << SSR_EPOCH << "$Epoch" + << close_document + << "$$ROOT" + << close_array + << close_document + << close_document; +} + +/** Read phase biases from Mongo DB +*/ SsrPBMap mongoReadPhaseBias( - GTime time, - SSRMeta ssrMeta, - int masterIod, - E_Sys targetSys) + SSRMeta& ssrMeta, ///< SSR message metadata + int masterIod, ///< IOD SSR + E_Sys targetSys) ///< target system { SsrPBMap ssrPBMap; + auto& mongo_ptr = remoteMongo_ptr; + if (mongo_ptr == nullptr) { MONGO_NOT_INITIALISED_MESSAGE; @@ -242,81 +286,78 @@ SsrPBMap mongoReadPhaseBias( Mongo& mongo = *mongo_ptr; auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.remoteMongo.database]; mongocxx::collection coll = db[SSR_DB]; - bsoncxx::types::b_date btime{std::chrono::system_clock::from_time_t(time.time)}; + mongocxx::pipeline p; + p.match(bsoncxx::builder::basic::make_document(bsoncxx::builder::basic::kvp(SSR_DATA, SSR_PHAS_BIAS))); + // p.sort (bsoncxx::builder::basic::make_document(bsoncxx::builder::basic::kvp(SSR_EPOCH, 1))); + + bsoncxx::builder::stream::document doc = {}; + + mongoGroupSortBias(doc); + p.group(doc.view()); - for (auto Sat : sats) + auto cursor = coll.aggregate(p, mongocxx::options::aggregate{}); + + for (auto resultDoc : cursor) { - SSRPhasBias ssrPhasBias; - ssrPhasBias.ssrMeta = ssrMeta; - ssrPhasBias.iod = masterIod; - - // Find the latest document according to t0_time. - auto docSys = document{} << SSR_SAT << Sat.id() - << SSR_DATA << SSR_PHAS_BIAS - << finalize; - - auto docSort = document{} << SSR_EPOCH << -1 - << finalize; // Get newest entry. + auto entry = resultDoc["lastEpoch"]; + auto strView = entry[SSR_SAT ].get_utf8().value; + string satStr = strView.to_string(); + SatSys Sat(satStr.c_str()); - auto findOpts = mongocxx::options::find{}; - findOpts.sort(docSort.view()); - - auto cursor = coll.find(docSys.view(), findOpts); - - ssrPhasBias.t0.time = 0; - for (auto satDoc : cursor) - { - GTime t0; - auto tp = satDoc[SSR_EPOCH ].get_date(); - t0.time = std::chrono::system_clock::to_time_t(tp); - - BiasVar biasVar; - ssrPhasBias.t0 = t0; - ssrPhasBias.ssrPhase.dispBiasConistInd = satDoc["dispBiasConistInd"].get_int32(); - ssrPhasBias.ssrPhase.MWConistInd = satDoc["MWConistInd" ].get_int32(); - ssrPhasBias.ssrPhase.yawAngle = satDoc["yawAngle" ].get_double(); - ssrPhasBias.ssrPhase.yawRate = satDoc["yawRate" ].get_double(); - - SSRPhaseCh ssrPhaseCh; - ssrPhaseCh.signalIntInd = satDoc["signalIntInd" ].get_int32(); - ssrPhaseCh.signalWidIntInd = satDoc["signalWidIntInd" ].get_int32(); - ssrPhaseCh.signalDisconCnt = satDoc["signalDisconCnt" ].get_int32(); - - auto strView = satDoc[SSR_OBSCODE ].get_utf8().value; - string obsStr = strView.to_string(); - E_ObsCode obsCode = E_ObsCode::_from_string(obsStr.c_str()); - - biasVar.bias = satDoc[SSR_BIAS ].get_double(); - biasVar.var = satDoc[SSR_VAR ].get_double(); - - ssrPhasBias.obsCodeBiasMap [obsCode] = biasVar; - ssrPhasBias.ssrPhaseChs [obsCode] = ssrPhaseCh; - } + if (Sat.sys != targetSys) + continue; + + SSRPhasBias& ssrPhasBias = ssrPBMap[Sat]; + ssrPhasBias.ssrMeta = ssrMeta; + ssrPhasBias.iod = masterIod; + + auto tp = entry[SSR_EPOCH ].get_date(); + PTime t0; + t0.bigTime = std::chrono::system_clock::to_time_t(tp); + + if (!t0.bigTime) + continue; - if (ssrPhasBias.t0.time != 0) - { - // std::cout << "Phase Bias frame . "; - // std::cout << "satId : " << Sat.id(); - // std::cout << ". Num Observation codes : " << ssrPhasBias.obsCodeBiasMap.size() << std::endl; - //std::cout << "Num : " << targetSys._to_string() << " Bias read " << ssrPBMap[ssrPhasBias.t0].size() << std::endl; - ssrPBMap[Sat] = ssrPhasBias; - } + ssrPhasBias.t0 = t0; + ssrPhasBias.ssrPhase.dispBiasConistInd = entry["dispBiasConistInd" ].get_int32(); + ssrPhasBias.ssrPhase.MWConistInd = entry["MWConistInd" ].get_int32(); + ssrPhasBias.ssrPhase.yawAngle = entry["yawAngle" ].get_double(); + ssrPhasBias.ssrPhase.yawRate = entry["yawRate" ].get_double(); + + SSRPhaseCh ssrPhaseCh; + ssrPhaseCh.signalIntInd = entry["signalIntInd" ].get_int32(); + ssrPhaseCh.signalWLIntInd = entry["signalWLIntInd" ].get_int32(); + ssrPhaseCh.signalDisconCnt = entry["signalDisconCnt" ].get_int32(); + + strView = entry[SSR_OBSCODE ].get_utf8().value; + string obsStr = strView.to_string(); + E_ObsCode obsCode = E_ObsCode::_from_string(obsStr.c_str()); + + BiasVar biasVar; + biasVar.bias = entry[SSR_BIAS ].get_double(); + biasVar.var = entry[SSR_VAR ].get_double(); + + ssrPhasBias.obsCodeBiasMap [obsCode] = biasVar; // last entry wins + ssrPhasBias.ssrPhaseChs [obsCode] = ssrPhaseCh; } - + return ssrPBMap; } +/** Read code biases from Mongo DB +*/ SsrCBMap mongoReadCodeBias( - GTime time, - SSRMeta ssrMeta, - int masterIod, - E_Sys targetSys) + SSRMeta& ssrMeta, ///< SSR message metadata + int masterIod, ///< IOD SSR + E_Sys targetSys) ///< target system { SsrCBMap ssrCBMap; + auto& mongo_ptr = remoteMongo_ptr; + if (mongo_ptr == nullptr) { MONGO_NOT_INITIALISED_MESSAGE; @@ -328,61 +369,505 @@ SsrCBMap mongoReadCodeBias( Mongo& mongo = *mongo_ptr; auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.remoteMongo.database]; mongocxx::collection coll = db[SSR_DB]; - bsoncxx::types::b_date btime{std::chrono::system_clock::from_time_t(time.time)}; + mongocxx::pipeline p; + p.match(bsoncxx::builder::basic::make_document(bsoncxx::builder::basic::kvp(SSR_DATA, SSR_CODE_BIAS))); + // p.sort (bsoncxx::builder::basic::make_document(bsoncxx::builder::basic::kvp(SSR_EPOCH, 1))); + + bsoncxx::builder::stream::document doc = {}; + + mongoGroupSortBias(doc); + p.group(doc.view()); - for (auto Sat : sats) + auto cursor = coll.aggregate(p, mongocxx::options::aggregate{}); + + for (auto resultDoc : cursor) { - SSRCodeBias ssrCodeBias; - ssrCodeBias.ssrMeta = ssrMeta; - ssrCodeBias.iod = masterIod; - ssrCodeBias.t0.time = 0; - - // Find the latest document according to t0_time. - auto docSys = document{} << SSR_SAT << Sat.id() - << SSR_DATA << SSR_CODE_BIAS - << SSR_EPOCH - << open_document - << "$lt" << btime - << close_document - << finalize; - - auto docSort = document{} << SSR_EPOCH << 1 - << finalize; + auto entry = resultDoc["lastEpoch"]; + auto strView = entry[SSR_SAT ].get_utf8().value; + string satStr = strView.to_string(); + SatSys Sat(satStr.c_str()); + + if (Sat.sys != targetSys) + continue; + + SSRCodeBias& ssrCodeBias = ssrCBMap[Sat]; + ssrCodeBias.ssrMeta = ssrMeta; + ssrCodeBias.iod = masterIod; + + auto tp = entry[SSR_EPOCH ].get_date(); + PTime t0; + t0.bigTime = std::chrono::system_clock::to_time_t(tp); + + if (!t0.bigTime) + continue; - auto findOpts = mongocxx::options::find{}; - findOpts.limit(1); + ssrCodeBias.t0 = t0; + + strView = entry[SSR_OBSCODE ].get_utf8().value; + string obsStr = strView.to_string(); + E_ObsCode obsCode = E_ObsCode::_from_string(obsStr.c_str()); + + BiasVar biasVar; + biasVar.bias = entry[SSR_BIAS ].get_double(); + biasVar.var = entry[SSR_VAR ].get_double(); + + ssrCodeBias.obsCodeBiasMap[obsCode] = biasVar; // last entry wins + } + + return ssrCBMap; +} + +/** Read GPS/GAL/BDS/QZS ephemeris from Mongo DB +*/ +Eph mongoReadEphemeris( + GTime targetTime, ///< target system + SatSys Sat, ///< satellite to read ephemeris of + RtcmMessageType rtcmMessCode) ///< RTCM message code to read ephemeris of +{ + Eph eph; + E_NavMsgType type; + + auto& mongo_ptr = remoteMongo_ptr; + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + return eph; + } + + Mongo& mongo = *mongo_ptr; + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[acsConfig.remoteMongo.database]; + mongocxx::collection coll = db["Ephemeris"]; + + b_date btime{std::chrono::system_clock::from_time_t((time_t)((PTime)targetTime).bigTime)}; + + switch (rtcmMessCode) + { + case +RtcmMessageType:: GPS_EPHEMERIS: // fallthrough + case +RtcmMessageType:: QZS_EPHEMERIS: type = E_NavMsgType::LNAV; break; + case +RtcmMessageType:: BDS_EPHEMERIS: type = E_NavMsgType::D1; break; + case +RtcmMessageType:: GAL_FNAV_EPHEMERIS: type = E_NavMsgType::FNAV; break; + case +RtcmMessageType:: GAL_INAV_EPHEMERIS: type = E_NavMsgType::INAV; break; + default: + BOOST_LOG_TRIVIAL(error) << "Error, attempting to upload incorrect message type.\n"; + return eph; + } + + // Find the latest document according to t0_time. + auto docSys = document{} << "Sat" << Sat.id() + << "Type" << type._to_string() + << finalize; + + auto docSort = document{} << "ToeGPST" << -1 // Newest entry comes first + << finalize; + + auto findOpts = mongocxx::options::find{}; + findOpts.sort(docSort.view()); + findOpts.limit(1); // Only get the first entry + + auto cursor = coll.find(docSys.view(), findOpts); + + for (auto satDoc : cursor) + { + eph.Sat = Sat; + eph.type = type; + + PTime ptoe; + auto toe = satDoc["ToeGPST" ].get_date(); + ptoe.bigTime = std::chrono::system_clock::to_time_t(toe); + eph.toe = ptoe; + + PTime ptoc; + auto toc = satDoc["TocGPST" ].get_date(); + ptoc.bigTime = std::chrono::system_clock::to_time_t(toc); + eph.toc = ptoc; + + eph.weekRollOver = satDoc["WeekDecoded" ].get_int32(); + eph.week = satDoc["WeekAdjusted" ].get_int32(); + eph.toes = satDoc["ToeSecOfWeek" ].get_double(); + eph.tocs = satDoc["TocSecOfWeek" ].get_double(); + + eph.aode = satDoc["AODE" ].get_int32(); + eph.aodc = satDoc["AODC" ].get_int32(); + eph.iode = satDoc["IODE" ].get_int32(); + eph.iodc = satDoc["IODC" ].get_int32(); + + eph.f0 = satDoc["f0" ].get_double(); + eph.f1 = satDoc["f1" ].get_double(); + eph.f2 = satDoc["f2" ].get_double(); + + eph.sqrtA = satDoc["SqrtA" ].get_double(); + eph.A = satDoc["A" ].get_double(); + eph.e = satDoc["e" ].get_double(); + eph.i0 = satDoc["i0" ].get_double(); + eph.idot = satDoc["iDot" ].get_double(); + eph.omg = satDoc["omg" ].get_double(); + eph.OMG0 = satDoc["OMG0" ].get_double(); + eph.OMGd = satDoc["OMGDot" ].get_double(); + eph.M0 = satDoc["M0" ].get_double(); + eph.deln = satDoc["DeltaN" ].get_double(); + eph.crc = satDoc["Crc" ].get_double(); + eph.crs = satDoc["Crs" ].get_double(); + eph.cic = satDoc["Cic" ].get_double(); + eph.cis = satDoc["Cis" ].get_double(); + eph.cuc = satDoc["Cuc" ].get_double(); + eph.cus = satDoc["Cus" ].get_double(); + + eph.tgd[0] = satDoc["TGD0" ].get_double(); + eph.tgd[1] = satDoc["TGD1" ].get_double(); + eph.sva = satDoc["URAIndex" ].get_int32(); + + if ( eph.Sat.sys == +E_Sys::GPS + ||eph.Sat.sys == +E_Sys::QZS) + { + eph.ura[0] = satDoc["URA" ].get_double(); + int svh = satDoc["SVHealth" ].get_int32(); eph.svh = (E_Svh)svh; + eph.code = satDoc["CodeOnL2" ].get_int32(); + eph.flag = satDoc["L2PDataFlag" ].get_int32(); + eph.fitFlag = satDoc["FitFlag" ].get_int32(); + eph.fit = satDoc["FitInterval" ].get_double(); + } + else if (eph.Sat.sys == +E_Sys::GAL) + { + eph.ura[0] = satDoc["SISA" ].get_double(); + int svh = satDoc["SVHealth" ].get_int32(); eph.svh = (E_Svh)svh; + eph.e5a_hs = satDoc["E5aHealth" ].get_int32(); + eph.e5a_dvs = satDoc["E5aDataValidity" ].get_int32(); + eph.e5b_hs = satDoc["E5bHealth" ].get_int32(); + eph.e5b_dvs = satDoc["E5bDataValidity" ].get_int32(); + eph.e1_hs = satDoc["E1Health" ].get_int32(); + eph.e1_dvs = satDoc["E1DataValidity" ].get_int32(); + eph.code = satDoc["DataSource" ].get_int32(); + } + else if (eph.Sat.sys == +E_Sys::BDS) + { + eph.ura[0] = satDoc["URA" ].get_double(); + int svh = satDoc["SVHealth" ].get_int32(); eph.svh = (E_Svh)svh; + } + } + + return eph; +} + +/** Read GLO ephemeris from Mongo DB +*/ +Geph mongoReadGloEphemeris( + GTime targetTime, ///< target system + SatSys Sat) ///< satellite to read ephemeris of +{ + Geph geph; + + auto& mongo_ptr = remoteMongo_ptr; + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + return geph; + } + + Mongo& mongo = *mongo_ptr; + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[acsConfig.remoteMongo.database]; + mongocxx::collection coll = db["Ephemeris"]; + + b_date btime{std::chrono::system_clock::from_time_t((time_t)((PTime)targetTime).bigTime)}; + + // Find the latest document according to t0_time. + auto docSys = document{} << "Sat" << Sat.id() + << finalize; + + auto docSort = document{} << "ToeGPST" << -1 // Newest entry comes first + << finalize; + + auto findOpts = mongocxx::options::find{}; + findOpts.sort(docSort.view()); + findOpts.limit(1); // Only get the first entry + + auto cursor = coll.find(docSys.view(), findOpts); + + for (auto satDoc : cursor) + { + geph.Sat = Sat; + geph.type = E_NavMsgType::FDMA; + + PTime ptoe; + auto toe = satDoc["ToeGPST" ].get_date(); + ptoe.bigTime = std::chrono::system_clock::to_time_t(toe); + geph.toe = ptoe; + + PTime ptof; + auto tof = satDoc["TofGPST" ].get_date(); + ptof.bigTime = std::chrono::system_clock::to_time_t(tof); + geph.tof = ptof; + + geph.tb = satDoc["ToeSecOfDay" ].get_int32(); + geph.tk_hour = satDoc["TofHour" ].get_int32(); + geph.tk_min = satDoc["TofMin" ].get_int32(); + geph.tk_sec = satDoc["TofSec" ].get_double(); + + geph.iode = satDoc["IODE" ].get_int32(); - auto cursor = coll.find(docSys.view(), findOpts); + geph.taun = satDoc["TauN" ].get_double(); + geph.gammaN = satDoc["GammaN" ].get_double(); + geph.dtaun = satDoc["DeltaTauN" ].get_double(); + + geph.pos[0] = satDoc["PosX" ].get_double(); + geph.pos[1] = satDoc["PosY" ].get_double(); + geph.pos[2] = satDoc["PosZ" ].get_double(); + geph.vel[0] = satDoc["VelX" ].get_double(); + geph.vel[1] = satDoc["VelY" ].get_double(); + geph.vel[2] = satDoc["VelZ" ].get_double(); + geph.acc[0] = satDoc["AccX" ].get_double(); + geph.acc[1] = satDoc["AccY" ].get_double(); + geph.acc[2] = satDoc["AccZ" ].get_double(); + + geph.frq = satDoc["FrquencyNumber" ].get_int32(); + int svh = satDoc["SVHealth" ].get_int32(); geph.svh = (E_Svh)svh; + geph.age = satDoc["Age" ].get_int32(); - for (auto satDoc : cursor) + geph.glonassM = satDoc["GLONASSM" ].get_int32(); + geph.NT = satDoc["NumberOfDayIn4Year" ].get_int32(); + geph.moreData = satDoc["AdditionalData" ].get_bool(); + geph.N4 = satDoc["4YearIntervalNumber" ].get_int32(); + } + + return geph; +} + + +SSRAtm mongoReadIGSIonosphere( + GTime time, + SSRMeta ssrMeta, + int masterIod) +{ + SSRAtm ssrAtm; + + auto& mongo_ptr = remoteMongo_ptr; + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + return ssrAtm; + } + ssrAtm.ssrMeta = ssrMeta; + + Mongo& mongo = *mongo_ptr; + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[acsConfig.remoteMongo.database]; + mongocxx::collection coll = db[SSR_DB]; + + b_date btime{std::chrono::system_clock::from_time_t((time_t)((PTime)time).bigTime)}; + + // Find the latest document according to t0_time. + auto docSys = document{} << SSR_DATA << IGS_ION_META + << SSR_EPOCH + << open_document + << "$lt" << btime + << close_document + << finalize; + + auto docSort = document{} << SSR_EPOCH << 1 + << finalize; + + auto findOpts = mongocxx::options::find{}; + findOpts.limit(1); + + auto cursor = coll.find(docSys.view(), findOpts); + + SSRAtmGlobal atmGlob; + int nbasis; + for (auto atmDoc : cursor) + { + PTime t0; + auto tp = atmDoc[SSR_EPOCH ].get_date(); + t0.bigTime = std::chrono::system_clock::to_time_t(tp); + + atmGlob.time = t0; + + atmGlob.numberLayers = atmDoc[IGS_ION_NLAY ].get_int32(); + nbasis = atmDoc[IGS_ION_NBAS ].get_int32(); + atmGlob.vtecQuality = atmDoc[IGS_ION_QLTY ].get_double(); + for (int i=0; i < atmGlob.numberLayers; i++) { - GTime t0; - auto tp = satDoc[SSR_EPOCH ].get_date(); - t0.time = std::chrono::system_clock::to_time_t(tp); - - ssrCodeBias.t0 = t0; - auto strView = satDoc[SSR_OBSCODE ].get_utf8().value; - string obsStr = strView.to_string(); - E_ObsCode obsCode = E_ObsCode::_from_string(obsStr.c_str()); - - BiasVar biasVar; - biasVar.bias = satDoc[SSR_BIAS ].get_double(); - biasVar.var = satDoc[SSR_VAR ].get_double(); - ssrCodeBias.obsCodeBiasMap[obsCode] = biasVar; + string hghStr = "Height_"+std::to_string(i); + atmGlob.layers[i].height = atmDoc[hghStr ].get_double(); } + } + + auto timobj = b_date {std::chrono::system_clock::from_time_t(atmGlob.time.bigTime)}; + auto docEntr = document{} << SSR_DATA << IGS_ION_ENTRY + << SSR_EPOCH << timobj + << finalize; + auto cursor2 = coll.find(docEntr.view(), mongocxx::options::find{}); + + map maxBasis; + for (auto atmDoc : cursor2) + { + SphComp sphComp; + sphComp.hind = atmDoc[IGS_ION_HGT ].get_int32(); + sphComp.degree = atmDoc[IGS_ION_DEG ].get_int32(); + sphComp.order = atmDoc[IGS_ION_ORD ].get_int32(); + sphComp.parity = atmDoc[IGS_ION_PAR ].get_int32(); - if (ssrCodeBias.t0.time != 0) + sphComp.coeffc = atmDoc[IGS_ION_VAL ].get_double(); + sphComp.variance = 0; + + SSRVTEClayer& laydata = atmGlob.layers[sphComp.hind]; + + laydata.sphHarmonic[maxBasis[sphComp.hind]] = sphComp; + maxBasis[sphComp.hind]++; + + if (laydata.maxDegree < sphComp.degree) laydata.maxDegree = sphComp.degree; + if (laydata.maxOrder < sphComp.order) laydata.maxOrder = sphComp.order; + } + + atmGlob.iod = masterIod; + + ssrAtm.atmosGlobalMap[atmGlob.time] = atmGlob; + + return ssrAtm; +} + +map> mongoReadOrbits( + GTime time, + SatSys Sat, + bool remote) +{ + map> predictedPosMap; + + Mongo* mongo_ptr; + + if (remote) mongo_ptr = remoteMongo_ptr; + else mongo_ptr = localMongo_ptr; + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + return predictedPosMap; + } + + Mongo& mongo = *mongo_ptr; + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[acsConfig.remoteMongo.database]; + mongocxx::collection coll = db[REMOTE_DATA_DB]; + + b_date btime{std::chrono::system_clock::from_time_t((time_t)((PTime)time).bigTime)}; + + // Find the latest document according to t0_time. + auto docSys = document{}; + + docSys << REMOTE_DATA << REMOTE_ORBIT; + if (Sat.prn) docSys << REMOTE_SAT << Sat.id(); + if (time != GTime::noTime()) docSys << REMOTE_EPOCH << btime; + + auto findOpts = mongocxx::options::find{}; + if ( Sat.prn != 0 + &&time != GTime::noTime()) + { + findOpts.limit(1); + } + + auto cursor = coll.find(docSys.view(), findOpts); + + for (auto doc : cursor) + { +// PTime updated; +// auto tp = doc[REMOTE_UPDATED ].get_date(); +// updated.bigTime = std::chrono::system_clock::to_time_t(tp); + + PTime time; + auto tp2 = doc[REMOTE_EPOCH ].get_date(); + time.bigTime = std::chrono::system_clock::to_time_t(tp2); + + Vector6d inertialState = Vector6d::Zero(); + + for (int i = 0; i < 3; i++) { - //std::cout << "Code Bias.\n" - //std::cout << "satId : " << sat.id() << std::endl; - //std::cout << "Num Observation codes : " << ssrCodeBias.codeBias_map.size() << std::endl; - //std::cout << "Num : " << targetSys._to_string() << " Bias read " << ssrCBMap[ssrCodeBias.t0].size() << std::endl; - ssrCBMap[Sat] = ssrCodeBias; + inertialState(i + 0) = doc[REMOTE_POS + std::to_string(i)].get_double(); + inertialState(i + 3) = doc[REMOTE_VEL + std::to_string(i)].get_double(); } + + string sat = doc[REMOTE_SAT].get_utf8().value.to_string(); + + SatSys Sat(sat.c_str()); + + predictedPosMap[Sat][time] = inertialState; } - return ssrCBMap; + return predictedPosMap; +} + +map>> mongoReadClocks( + GTime time, + string str, + bool remote) +{ + map>> predictedClkMap; + + Mongo* mongo_ptr; + + if (remote) mongo_ptr = remoteMongo_ptr; + else mongo_ptr = localMongo_ptr; + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + return predictedClkMap; + } + + Mongo& mongo = *mongo_ptr; + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[acsConfig.remoteMongo.database]; + mongocxx::collection coll = db[REMOTE_DATA_DB]; + + b_date btime{std::chrono::system_clock::from_time_t((time_t)((PTime)time).bigTime)}; + + // Find the latest document according to t0_time. + auto docSys = document{}; + + docSys << REMOTE_DATA << REMOTE_CLOCK; + if (str.empty() == false) docSys << REMOTE_SAT << str; + if (time != GTime::noTime()) docSys << REMOTE_EPOCH << btime; + + auto findOpts = mongocxx::options::find{}; + if ( str.empty() == false + &&time != GTime::noTime()) + { + findOpts.limit(1); + } + + auto cursor = coll.find(docSys.view(), findOpts); + + for (auto doc : cursor) + { +// PTime updated; +// auto tp = doc[REMOTE_UPDATED ].get_date(); +// updated.bigTime = std::chrono::system_clock::to_time_t(tp); + PTime time; + auto tp2 = doc[REMOTE_EPOCH ].get_date(); + time.bigTime = std::chrono::system_clock::to_time_t(tp2); + + + tuple clocks; + + auto& [clock, drift] = clocks; + + clock = doc[REMOTE_CLK] .get_double(); + drift = doc[REMOTE_CLK_DRIFT] .get_double(); + + string str = doc[REMOTE_STR].get_utf8().value.to_string(); + + predictedClkMap[str][time] = clocks; + } + + return predictedClkMap; } diff --git a/src/cpp/common/mongoRead.hpp b/src/cpp/common/mongoRead.hpp index c8f54ada9..6fe4f5633 100644 --- a/src/cpp/common/mongoRead.hpp +++ b/src/cpp/common/mongoRead.hpp @@ -1,38 +1,48 @@ -#ifndef READMONGO_H -#define READMONGO_H -#include - -#include -#include +#pragma once +#include "rtcmEncoder.hpp" #include "mongo.hpp" -#include "ssr.hpp" +struct SSRMeta; -SsrClkOutMap mongoReadClocks( - GTime curTime, - SSRMeta ssrMeta, - int masterIod, - E_Sys targetSys); -SsrCBMap mongoReadCodeBias( - GTime curTime, - SSRMeta ssrMeta, - int masterIod, - E_Sys targetSys); +SsrOutMap mongoReadOrbClk( + GTime referenceTime, + SSRMeta& ssrMeta, + int masterIod, + E_Sys targetSys); -map mongoReadSSRData( - GTime targetTime, - SSRMeta ssrMeta, - int masterIod, - E_Sys targetSys); +SsrCBMap mongoReadCodeBias( + SSRMeta& ssrMeta, + int masterIod, + E_Sys targetSys); SsrPBMap mongoReadPhaseBias( - GTime curTime, + SSRMeta& ssrMeta, + int masterIod, + E_Sys targetSys); + +Eph mongoReadEphemeris( + GTime targetTime, + SatSys Sat, + RtcmMessageType rtcmMessCode); + +Geph mongoReadGloEphemeris( + GTime targetTime, + SatSys Sat); + +SSRAtm mongoReadIGSIonosphere( + GTime time, SSRMeta ssrMeta, - int masterIod, - E_Sys targetSys); + int masterIod); +map> mongoReadOrbits( + GTime time = GTime::noTime(), + SatSys Sat = SatSys(), + bool remote = false); -#endif +map>> mongoReadClocks( + GTime time = GTime::noTime(), + string str = "", + bool remote = false); diff --git a/src/cpp/common/mongoWrite.cpp b/src/cpp/common/mongoWrite.cpp index 0b79bfb83..6736cc7be 100644 --- a/src/cpp/common/mongoWrite.cpp +++ b/src/cpp/common/mongoWrite.cpp @@ -4,9 +4,12 @@ #include "observations.hpp" #include "rtcmEncoder.hpp" +#include "coordinates.hpp" #include "instrument.hpp" #include "mongoWrite.hpp" #include "GNSSambres.hpp" +#include "orbitProp.hpp" +#include "rtcmTrace.hpp" #include "biasSINEX.hpp" #include "acsConfig.hpp" #include "satStat.hpp" @@ -15,19 +18,44 @@ #include +#include + #include +using bsoncxx::builder::stream::close_array; +using bsoncxx::builder::stream::close_document; +using bsoncxx::builder::stream::document; +using bsoncxx::builder::stream::finalize; +using bsoncxx::builder::stream::open_array; +using bsoncxx::builder::stream::open_document; using bsoncxx::builder::basic::kvp; +using bsoncxx::types::b_date; + +using std::make_pair; + +b_date bDate( + GTime time) +{ + int fractionalMilliseconds = (time.bigTime - (long int) time.bigTime) * 1000; + + auto stdTime = std::chrono::system_clock::from_time_t((time_t)((PTime)time).bigTime); + + stdTime += std::chrono::milliseconds(fractionalMilliseconds); + + return b_date(stdTime); +} void mongoTestStat( KFState& kfState, TestStatistics& testStatistics) { + auto& mongo_ptr = localMongo_ptr; + if (mongo_ptr == nullptr) { MONGO_NOT_INITIALISED_MESSAGE; - acsConfig.output_mongo_test_stats = false; + acsConfig.localMongo.output_test_stats = false; return; } @@ -38,12 +66,9 @@ void mongoTestStat( auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.localMongo.database]; mongocxx::collection coll = db ["States"]; - mongocxx::options::update options; - options.upsert(true); - mongocxx::options::bulk_write bulk_opts; bulk_opts.ordered(false); @@ -63,24 +88,15 @@ void mongoTestStat( for (auto& [state, value] : entries) { - mongocxx::model::update_one mongo_req( - document{} - << "Epoch" << bsoncxx::types::b_date {std::chrono::system_clock::from_time_t(kfState.time.time)} - << "Site" << kfState.id + acsConfig.mongo_suffix - << "Sat" << "" + acsConfig.mongo_suffix - << "State" << state - << finalize, - - document{} - << "$set" - << open_document - << "x0" << value - << close_document - << finalize - ); + bsoncxx::builder::stream::document doc{}; + doc << "Epoch" << bDate(kfState.time) + << "Site" << kfState.id + acsConfig.localMongo.suffix + << "Sat" << "" + acsConfig.localMongo.suffix + << "State" << state + << "x" << value; - mongo_req.upsert(true); - bulk.append(mongo_req); + bsoncxx::document::value doc_val = doc << finalize; + bulk.append(mongocxx::model::insert_one(doc_val.view())); update = true; } @@ -90,14 +106,16 @@ void mongoTestStat( } } -void mongoMeasSatStat( - StationMap& stationMap) +void mongoTrace( + string json) { + auto& mongo_ptr = localMongo_ptr; + if (mongo_ptr == nullptr) { MONGO_NOT_INITIALISED_MESSAGE; - acsConfig.output_mongo_measurements = false; + acsConfig.localMongo.output_trace = false; return; } @@ -108,93 +126,36 @@ void mongoMeasSatStat( auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.localMongo.database]; - for (auto pseudoIndex : {false, true}) - { - string collectionName = "Measurements"; - if (pseudoIndex) - collectionName += "Index"; - - mongocxx::collection coll = db[collectionName]; - - mongocxx::options::update options; - options.upsert(true); - - mongocxx::options::bulk_write bulk_opts; - bulk_opts.ordered(false); - - auto bulk = coll.create_bulk_write(bulk_opts); - bool update = false; - - for (auto& [id, rec] : stationMap) - for (auto& obs : rec.obsList) - { - if (obs.exclude) - continue; + string collectionName = "Trace"; + + mongocxx::collection coll = db[collectionName]; - if (obs.satStat_ptr == nullptr) - continue; + mongocxx::options::bulk_write bulk_opts; + bulk_opts.ordered(false); - SatStat& satStat = *obs.satStat_ptr; + auto bulk = coll.create_bulk_write(bulk_opts); - bsoncxx::builder::basic::document keyDoc = {}; - if (pseudoIndex == false) - { - //only add epoch data to full collection, not the pseudoIndex subset - keyDoc.append(kvp("Epoch", bsoncxx::types::b_date {std::chrono::system_clock::from_time_t(tsync.time)} )); - } - - { - keyDoc.append(kvp("Site", obs.mount + acsConfig.mongo_suffix )); - keyDoc.append(kvp("Sat", obs.Sat.id() )); - } - - bsoncxx::builder::basic::document valDoc = {}; - valDoc.append(kvp("Azimuth", pseudoIndex ? true : satStat.az * R2D )); - valDoc.append(kvp("Elevation", pseudoIndex ? true : satStat.el * R2D )); - valDoc.append(kvp("Nadir", pseudoIndex ? true : satStat.nadir * R2D )); - valDoc.append(kvp("sunDotSat", pseudoIndex ? true : satStat.sunDotSat )); - valDoc.append(kvp("sunCrossSat", pseudoIndex ? true : satStat.sunCrossSat )); - valDoc.append(kvp("slip", pseudoIndex ? true : satStat.slip )); - valDoc.append(kvp("Phase Windup", pseudoIndex ? true : satStat.phw )); - - mongocxx::model::update_one mongo_req( - keyDoc.extract(), - - document{} - << "$set" << valDoc - << finalize - ); - - mongo_req.upsert(true); - bulk.append(mongo_req); - update = true; - } + bool update = false; - if (update) - bulk.execute(); - } + auto doc = bsoncxx::from_json(json); + + bulk.append(mongocxx::model::insert_one(doc.view())); + + bulk.execute(); } - -void mongoMeasResiduals( - GTime time, - vector& obsKeys, - VectorXd& prefits, - VectorXd& postfits, - MatrixXd& variance, - string suffix, - int beg, - int num) +void mongoOutputConfig( + string& config) { + auto& mongo_ptr = localMongo_ptr; + if (mongo_ptr == nullptr) { MONGO_NOT_INITIALISED_MESSAGE; - acsConfig.output_mongo_measurements = false; - return; } @@ -204,158 +165,260 @@ void mongoMeasResiduals( auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.localMongo.database]; - for (auto pseudoIndex : {false, true}) - { - string collectionName = "Measurements"; - if (pseudoIndex) - collectionName += "Index"; - - mongocxx::collection coll = db[collectionName]; - - mongocxx::options::update options; - options.upsert(true); - mongocxx::options::bulk_write bulk_opts; - bulk_opts.ordered(false); + string collectionName = "Config"; + + mongocxx::collection coll = db[collectionName]; - auto bulk = coll.create_bulk_write(bulk_opts); + mongocxx::options::bulk_write bulk_opts; + bulk_opts.ordered(false); - bool update = false; + auto bulk = coll.create_bulk_write(bulk_opts); - if (num < 0) - { - num = prefits.rows(); - } + bool update = false; + + try + { + auto doc = bsoncxx::from_json(config); - options.upsert(true); - for (int i = beg; i < beg + num; i++) - { - ObsKey& obsKey = obsKeys[i]; - - string name = obsKey.type + std::to_string(obsKey.num); - - bsoncxx::builder::basic::document keyDoc = {}; - if (pseudoIndex == false) - { - //only add epoch data to full collection, not the pseudoIndex subset - keyDoc.append(kvp("Epoch", bsoncxx::types::b_date {std::chrono::system_clock::from_time_t(time.time)} )); - } - - { - keyDoc.append(kvp("Site", obsKey.str + acsConfig.mongo_suffix + suffix )); - keyDoc.append(kvp("Sat", obsKey.Sat.id() + suffix )); - } - - bsoncxx::builder::basic::document valDoc = {}; - valDoc.append(kvp(name + "-Prefit", pseudoIndex ? true : prefits(i) )); - valDoc.append(kvp(name + "-Postfit", pseudoIndex ? true : postfits(i) )); - valDoc.append(kvp(name + "-Variance", pseudoIndex ? true : variance(i,i) )); - - mongocxx::model::update_one mongo_req( - keyDoc.extract(), - - document{} - << "$set" << valDoc - << finalize - ); - - mongo_req.upsert(true); - - bulk.append(mongo_req); - update = true; - } - - if (update) - { - bulk.execute(); - } + bulk.append(mongocxx::model::insert_one(doc.view())); + + bulk.execute(); + } + catch (...) + { + BOOST_LOG_TRIVIAL(warning) << "Warning: Could not output config to mongo, likely due to empty entries in yaml."; } } -void mongoMeasComponents( - KFMeas& kfMeas) -{ +void mongoMeasSatStat( + StationMap& stationMap) +{ + auto& mongo_ptr = localMongo_ptr; + if (mongo_ptr == nullptr) { MONGO_NOT_INITIALISED_MESSAGE; - acsConfig.output_mongo_measurements = false; + acsConfig.localMongo.output_measurements = false; return; } Instrument instrument(__FUNCTION__); - + Mongo& mongo = *mongo_ptr; - + auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; + mongocxx::database db = client[acsConfig.localMongo.database]; + + + string collectionName = "Geometry"; - for (auto pseudoIndex : {false, true}) + mongocxx::collection coll = db[collectionName]; + + mongocxx::options::bulk_write bulk_opts; + bulk_opts.ordered(false); + + auto bulk = coll.create_bulk_write(bulk_opts); + + bool update = false; + + for (auto& [id, rec] : stationMap) + for (auto& obs : only(rec.obsList)) { - string collectionName = "Measurements"; - if (pseudoIndex) - collectionName += "Index"; + if (obs.exclude) + continue; + + if (obs.satStat_ptr == nullptr) + continue; + + SatStat& satStat = *obs.satStat_ptr; + + bsoncxx::builder::stream::document doc{}; + doc << "Epoch" << bDate(tsync) + << "Site" << obs.mount + << "Sat" << obs.Sat.id() + << "Series" << acsConfig.localMongo.suffix + << "Azimuth" << satStat.az * R2D + << "Elevation" << satStat.el * R2D; + + bsoncxx::document::value doc_val = doc << finalize; + bulk.append(mongocxx::model::insert_one(doc_val.view())); + update = true; + } + + if (update) + bulk.execute(); +} + + + +void mongoMeasResiduals( + GTime time, + KFMeas& kfMeas, + string suffix, + int beg, + int num) +{ + Instrument instrument(__FUNCTION__); + + for (auto mongo_ptr_ptr : {&localMongo_ptr, &remoteMongo_ptr}) + { + auto& mongo_ptr = *mongo_ptr_ptr; - mongocxx::collection coll = db[collectionName]; + MongoOptions* config_ptr; + if (mongo_ptr_ptr == &localMongo_ptr) config_ptr = &acsConfig.localMongo; + else config_ptr = &acsConfig.remoteMongo; + + auto& config = *config_ptr; + + if (config.output_measurements == false) + { + continue; + } - mongocxx::options::update options; - options.upsert(true); + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + + config.output_measurements = false; + + continue; + } + + Mongo& mongo = *mongo_ptr; + + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[config.database]; + + string collectionName = "Measurements"; + + mongocxx::collection coll = db[collectionName]; + mongocxx::options::bulk_write bulk_opts; bulk_opts.ordered(false); - + auto bulk = coll.create_bulk_write(bulk_opts); - + bool update = false; + + if (num < 0) + { + num = kfMeas.obsKeys.size(); + } + + map, vector> lookup; - options.upsert(true); - for (int i = 0; i < kfMeas.obsKeys.size(); i++) + map indexSeries; + map indexLabel; + map indexSite; + map indexSat; + + for (int i = beg; i < beg + num; i++) { - ObsKey& obsKey = kfMeas.obsKeys[i]; - auto& componentList = kfMeas.componentLists[i]; + KFKey& obsKey = kfMeas.obsKeys[i]; - string name = obsKey.type + std::to_string(obsKey.num); - - bsoncxx::builder::basic::document keyDoc = {}; - if (pseudoIndex == false) - { - //only add epoch data to full collection, not the pseudoIndex subset - keyDoc.append(kvp("Epoch", bsoncxx::types::b_date {std::chrono::system_clock::from_time_t(tsync.time)} )); - } + string commentString = ""; + if (obsKey.comment.empty() == false) + commentString = obsKey.comment + "-"; - { - keyDoc.append(kvp("Site", obsKey.str + acsConfig.mongo_suffix )); - keyDoc.append(kvp("Sat", obsKey.Sat.id() )); - } + string name = commentString + std::to_string(obsKey.num); + + lookup[make_tuple(obsKey.str, obsKey.Sat.id())].push_back(i); + } + + for (auto& [description, index] : lookup) + { + bsoncxx::builder::stream::document doc{}; + auto& [site, sat] = description; + doc << "Epoch" << bDate(time) + << "Site" << site + << "Sat" << sat + << "Series" << config.suffix + suffix; + + indexSeries [config.suffix + suffix] = true; + indexSite [site] = true; + indexSat [sat] = true; - bsoncxx::builder::basic::document valDoc = {}; - for (auto& component : componentList) + for (int& i : index) { - auto& [comp, value, desc] = component; + KFKey& obsKey = kfMeas.obsKeys[i]; - valDoc.append(kvp(name + "-" + comp, pseudoIndex ? true : value )); + string commentString = ""; + if (obsKey.comment.empty() == false) + commentString = obsKey.comment + "-"; + + string name = commentString + std::to_string(obsKey.num); + + doc << name + "-Prefit" << kfMeas.V (i) + << name + "-Postfit" << kfMeas.VV (i) + << name + "-Variance" << kfMeas.R (i,i); + + indexLabel[name + "-Prefit"] = true; + indexLabel[name + "-Postfit"] = true; + indexLabel[name + "-Variance"] = true; + + if ( config.output_components == false + ||kfMeas.componentLists.empty()) + { + continue; + } + + auto& componentList = kfMeas.componentLists[i]; + + for (auto& component : componentList) + { + auto& [comp, value, desc] = component; + + string label = name + " " + KF::_from_integral_unchecked(obsKey.type)._to_string() + " " + comp._to_string(); + + doc << label << value; + + indexLabel[label] = true; + } } - mongocxx::model::update_one mongo_req( - keyDoc.extract(), - - document{} - << "$set" << valDoc - << finalize - ); + bsoncxx::document::value doc_val = doc << finalize; + + bulk.append(mongocxx::model::insert_one(doc_val.view())); - mongo_req.upsert(true); - bulk.append(mongo_req); update = true; } - + if (update) { bulk.execute(); + + auto addIndices = [&](string name, map index) + { + mongocxx::options::update options; + options.upsert(true); + + auto eachDoc = document{}; + + auto arrayDoc = eachDoc << "$each" << open_array; + for (auto &[indexName, unused]: index) + { + arrayDoc << indexName; + } + arrayDoc << close_array; + + auto findDoc = document{} << "type" << name << finalize; + auto updateDoc = document{} << "$addToSet" << open_document << "Values" << eachDoc << close_document << finalize; + + db["Content"].update_one(findDoc.view(), updateDoc.view(), options); + }; + + addIndices("Measurements", indexLabel); + addIndices("Series", indexSeries); + addIndices("Site", indexSite); + addIndices("Sat", indexSat); } } } @@ -364,40 +427,53 @@ void mongoStates( KFState& kfState, string suffix) { - if (mongo_ptr == nullptr) - { - MONGO_NOT_INITIALISED_MESSAGE; - - acsConfig.output_mongo_states = false; - - return; - } - Instrument instrument(__FUNCTION__); - Mongo& mongo = *mongo_ptr; - - auto c = mongo.pool.acquire(); - mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; - - for (auto pseudoIndex : {false, true}) + for (auto mongo_ptr_ptr : {&localMongo_ptr, &remoteMongo_ptr}) { - string collectionName = "States"; - if (pseudoIndex) - collectionName += "Index"; + auto& mongo_ptr = *mongo_ptr_ptr; - mongocxx::collection coll = db[collectionName]; + MongoOptions* config_ptr; + if (mongo_ptr_ptr == &localMongo_ptr) config_ptr = &acsConfig.localMongo; + else config_ptr = &acsConfig.remoteMongo; + + auto& config = *config_ptr; + + if (config.output_states == false) + { + continue; + } + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + + config.output_states = false; + + return; + } + + Instrument instrument(__FUNCTION__); + + Mongo& mongo = *mongo_ptr; + + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[config.database]; mongocxx::options::update options; options.upsert(true); - + mongocxx::options::bulk_write bulk_opts; bulk_opts.ordered(false); + + auto bulk = db["States"].create_bulk_write(bulk_opts); - auto bulk = coll.create_bulk_write(bulk_opts); - - bool update = false; + map, vector>> lookup; + map indexSeries; + map indexState; + map indexSite; + map indexSat; for (auto& [key, index] : kfState.kfIndexMap) { @@ -405,86 +481,151 @@ void mongoStates( { continue; } - - bsoncxx::builder::basic::document keyDoc = {}; - if (pseudoIndex == false) - { - //only add epoch data to full collection, not the index subset - keyDoc.append(kvp("Epoch", bsoncxx::types::b_date {std::chrono::system_clock::from_time_t(kfState.time.time)} )); - } - - { - keyDoc.append(kvp("Site", key.str + acsConfig.mongo_suffix + suffix )); - keyDoc.append(kvp("Sat", key.Sat.id() + acsConfig.mongo_suffix + suffix )); - keyDoc.append(kvp("State", KF::_from_integral_unchecked(key.type)._to_string() )); - } - - bsoncxx::builder::basic::document valDoc = {}; - valDoc.append(kvp("x" + std::to_string(key.num), pseudoIndex ? true : kfState.x (index) )); - valDoc.append(kvp("dx" + std::to_string(key.num), pseudoIndex ? true : kfState.dx (index) )); - valDoc.append(kvp("P" + std::to_string(key.num), pseudoIndex ? true : kfState.P (index,index) )); - string setType; - - if (pseudoIndex) setType = "$setOnInsert"; - else setType = "$set"; + lookup[make_tuple(key.str, key.Sat.id(), KF::_from_integral_unchecked(key.type)._to_string())].push_back(make_pair(index, key.num)); + } + + vector documents; + + bool update = false; + + for (auto &[description, index] : lookup) + { + auto &[site, sat, state] = description; + + bsoncxx::builder::stream::document doc{}; + doc << "Epoch" << bDate(kfState.time) + << "Site" << site + << "Sat" << sat + << "State" << state + << "Series" << config.suffix + suffix; + + indexSeries [config.suffix + suffix] = true; + indexState [state] = true; + indexSat [sat] = true; + indexSite [site] = true; + + auto array_builder = doc << "x" << open_array; for (auto &[i, num]: index) array_builder << kfState.x (i); array_builder << close_array; + array_builder = doc << "dx" << open_array; for (auto &[i, num]: index) array_builder << kfState.dx (i); array_builder << close_array; + array_builder = doc << "P" << open_array; for (auto &[i, num]: index) array_builder << kfState.P (i,i); array_builder << close_array; + array_builder = doc << "Num" << open_array; for (auto &[i, num]: index) array_builder << num; array_builder << close_array; - bsoncxx::builder::basic::document valThing = {}; - valThing.append(kvp(setType, valDoc)); + bsoncxx::document::value doc_val = doc << finalize; - mongocxx::model::update_one mongo_req( - keyDoc .extract(), - valThing.extract()); + bulk.append(mongocxx::model::insert_one(doc_val.view())); update = true; + } + + if (update) + { + bulk.execute(); - mongo_req.upsert(true); - bulk.append(mongo_req); - + auto addIndices = [&](string name, map index) + { + auto eachDoc = document{}; + + auto arrayDoc = eachDoc << "$each" << open_array; + for (auto &[indexStr, unused]: index) + { + arrayDoc << indexStr; + } + arrayDoc << close_array; + + auto findDoc = document{} << "type" << name << finalize; + auto updateDoc = document{} << "$addToSet" << open_document << "Values" << eachDoc << close_document << finalize; + + db["Content"].update_one(findDoc.view(), updateDoc.view(), options); + }; + addIndices("Series",indexSeries); + addIndices("State", indexState); + addIndices("Site", indexSite); + addIndices("Sat", indexSat); + } + } +} + + +void mongoCull( + GTime time) +{ + for (auto mongo_ptr_ptr : {&localMongo_ptr, &remoteMongo_ptr}) + { + auto& mongo_ptr = *mongo_ptr_ptr; + + MongoOptions* config_ptr; + if (mongo_ptr_ptr == &localMongo_ptr) config_ptr = &acsConfig.localMongo; + else config_ptr = &acsConfig.remoteMongo; + + auto& config = *config_ptr; + + if (config.cull_history == false) + { + continue; + } + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + return; } - if (update) + Mongo& mongo = *mongo_ptr; + + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[config.database]; + + for (auto collection: {SSR_DB, REMOTE_DATA_DB}) { - Instrument instrument("execution"); - bulk.execute(); + mongocxx::collection coll = db[collection]; + + using bsoncxx::builder::basic::kvp; + + b_date btime{std::chrono::system_clock::from_time_t((time_t)((PTime)(time - config.min_cull_age)).bigTime)}; + + // Remove all documents that match a condition. + auto docSys = document{} << SSR_EPOCH + << open_document + << "$lt" << btime + << close_document + << finalize; + + coll.delete_many(docSys.view()); } } } -void mongoCull( - GTime cullTime) +document entryToDocument( + DBEntry& entry, + bool type) { - if (mongo_ptr == nullptr) - { - MONGO_NOT_INITIALISED_MESSAGE; - return; - } - - Mongo& mongo = *mongo_ptr; - - auto c = mongo.pool.acquire(); - mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; - mongocxx::collection coll = db[SSR_DB]; - - using bsoncxx::builder::basic::kvp; + // builder::document builds an empty BSON document + document doc = {}; - bsoncxx::types::b_date btime{std::chrono::system_clock::from_time_t(cullTime.time)}; + for (auto&[k,v]:entry.stringMap) {auto& [e,b] = v; if (type == b) doc << k << e;} + for (auto&[k,v]:entry.intMap) {auto& [e,b] = v; if (type == b) doc << k << e;} + for (auto&[k,v]:entry.doubleMap) {auto& [e,b] = v; if (type == b) doc << k << e;} + for (auto&[k,v]:entry.timeMap) {auto& [e,b] = v; if (type == b) doc << k << b_date{std::chrono::system_clock::from_time_t((time_t)((PTime)e).bigTime)};} + for (auto&[k,v]:entry.vectorMap) {auto& [e,b] = v; if (type == b) for (int i=0;i<3;i++) doc << k + std::to_string(i) << e[i];} + for (auto&[k,v]:entry.doubleArrayMap) {auto& [e,b] = v; if (type == b) { auto builder = doc << k << open_array; for (auto& a : e) builder << a; builder << close_array; }} + for (auto&[k,v]:entry.boolArrayMap) {auto& [e,b] = v; if (type == b) { auto builder = doc << k << open_array; for (auto& a : e) builder << a; builder << close_array; }} - // Remove all documents that match a condition. - auto docSys = document{} << SSR_EPOCH - << open_document - << "$lt" << btime - << close_document - << finalize; - - coll.delete_many(docSys.view()); + return doc; } + void mongoOutput( - list& dbEntryList) + vector& dbEntryList, + MongoOptions& config, + string collection) { + Mongo* mongo_ptr; + + if (config.local) mongo_ptr = localMongo_ptr; + else mongo_ptr = remoteMongo_ptr; + if (mongo_ptr == nullptr) { MONGO_NOT_INITIALISED_MESSAGE; @@ -495,8 +636,8 @@ void mongoOutput( auto c = mongo.pool.acquire(); mongocxx::client& client = *c; - mongocxx::database db = client[acsConfig.mongo_database]; - mongocxx::collection coll = db[SSR_DB]; + mongocxx::database db = client[config.database]; + mongocxx::collection coll = db[collection]; mongocxx::options::update options; options.upsert(true); @@ -508,28 +649,15 @@ void mongoOutput( bool update = false; - using bsoncxx::builder::basic::kvp; + using bsoncxx::builder::basic::kvp; for (auto& entry : dbEntryList) { // builder::document builds an empty BSON document - bsoncxx::builder::basic::document keys = {}; - bsoncxx::builder::basic::document vals = {}; - bsoncxx::builder::basic::document Vals = {}; + auto keys = entryToDocument(entry, true); + auto vals = entryToDocument(entry, false); - for (bool key : {false, true}) - { - auto* ptr = &keys; - if (key) ptr = &keys; - else ptr = &vals; - auto& doc = *ptr; - - for (auto&[k,v]:entry.stringMap) {auto& [e,b] = v; if (key == b) doc.append(kvp(k, e));} - for (auto&[k,v]:entry.intMap) {auto& [e,b] = v; if (key == b) doc.append(kvp(k, e));} - for (auto&[k,v]:entry.doubleMap) {auto& [e,b] = v; if (key == b) doc.append(kvp(k, e));} - for (auto&[k,v]:entry.timeMap) {auto& [e,b] = v; if (key == b) doc.append(kvp(k, bsoncxx::types::b_date {std::chrono::system_clock::from_time_t(e.time)}));} - for (auto&[k,v]:entry.vectorMap) {auto& [e,b] = v; if (key == b) for (int i=0;i<3;i++) doc.append(kvp(k + std::to_string(i), e[i]));} - } + bsoncxx::builder::basic::document Vals = {}; Vals.append(kvp("$set", vals)); @@ -546,17 +674,29 @@ void mongoOutput( bulk.execute(); } +/** Write states generating SSR corrections to Mongo DB +*/ void prepareSsrStates( Trace& trace, ///< Trace to output to KFState& kfState, ///< Filter object to extract state elements from GTime time) ///< Time of current epoch { - list dbEntryList; + if ( acsConfig.localMongo. output_ssr_precursors == false + &&acsConfig.remoteMongo.output_ssr_precursors == false) + { + return; + } + + BOOST_LOG_TRIVIAL(info) + << "Calculating SSR message precursors\n"; + + vector dbEntryList; + + time.bigTime = (long int) (time.bigTime + 0.5); // time tags in mongo will be rounded up to whole sec - for (int i = 0; i < E_Sys::_size(); i++) + for (E_Sys sys : E_Sys::_values()) { - E_Sys sys = E_Sys::_values()[i]; - string sysName = E_Sys::_names() [i]; boost::algorithm::to_lower(sysName); + string sysName = boost::algorithm::to_lower_copy((string) sys._to_string()); if (acsConfig.process_sys[sys] == false) continue; @@ -567,14 +707,14 @@ void prepareSsrStates( for (auto& Sat : sats) { // Create a dummy observation - Obs obs; + GObs obs; obs.Sat = Sat; auto& satNav = nav.satNavMap[obs.Sat]; SatStat satStatDummy; obs.satStat_ptr = &satStatDummy; - obs.satNav_ptr = &satNav; // for satpos_ssr() + obs.satNav_ptr = &satNav; GTime teph = time; @@ -582,11 +722,11 @@ void prepareSsrStates( for (int tpredict = 0; tpredict <= acsConfig.ssrOpts.prediction_duration; tpredict += acsConfig.ssrOpts.prediction_interval) { GTime pTime = time + tpredict; - bool pass = false; + bool pass = true; //broadcast values - - pass = satpos(trace, pTime, pTime, obs, E_Ephemeris::BROADCAST, E_OffsetType::APC, nav, false); + pass &= satclk(nullStream, pTime, pTime, obs, {E_Source::BROADCAST}, nav); + pass &= satpos(nullStream, pTime, pTime, obs, {E_Source::BROADCAST}, E_OffsetType::APC, nav); if (pass == false) { BOOST_LOG_TRIVIAL(info) @@ -595,68 +735,34 @@ void prepareSsrStates( continue; } - int iode = obs.iode; + int iodeClk = obs.iodeClk; + int iodePos = obs.iodePos; +// int iodcrc = ? Vector3d brdcPos = obs.rSat; Vector3d brdcVel = obs.satVel; - double brdcClkVal = obs.dtSat[0] * CLIGHT; + double brdcClkVal = obs.satClk * CLIGHT; - //precise clock - double precClkVal = 0; - switch (acsConfig.ssrOpts.clock_source) + pass = true; + pass &= satclk(nullStream, pTime, pTime, obs, acsConfig.ssrOpts.ephemeris_sources, nav, &kfState); + pass &= satpos(nullStream, pTime, pTime, obs, acsConfig.ssrOpts.ephemeris_sources, E_OffsetType::APC, nav, &kfState); + if (obs.satClk == INVALID_CLOCK_VALUE) { - case E_Ephemeris::BROADCAST: - case E_Ephemeris::PRECISE: - case E_Ephemeris::SSR: - { - pass = satpos(trace, pTime, pTime, obs, acsConfig.ssrOpts.clock_source, E_OffsetType::APC, nav, false); - - precClkVal = obs.dtSat[0] * CLIGHT; - - break; - } - case E_Ephemeris::KALMAN: - { - //currently can't predict clocks - if (tpredict == 0) - { - pass = kfState.getKFValue({.type = KF::SAT_CLOCK, .Sat = Sat}, precClkVal); - } - - break; - } + pass = false; } + + //precise clock + double precClkVal = obs.satClk * CLIGHT; - if (pass == false) - { - BOOST_LOG_TRIVIAL(info) - << Sat.id() << " failed ssrClk precise prediction.\n"; + if (pass == false) + { + BOOST_LOG_TRIVIAL(info) << Sat.id() << " failed ssrprecise prediction.\n"; continue; - } - - //precise orbit - switch (acsConfig.ssrOpts.ephemeris_source) - { - case E_Ephemeris::BROADCAST: - case E_Ephemeris::PRECISE: - case E_Ephemeris::SSR: - { - pass = satpos(trace, pTime, pTime, obs, acsConfig.ssrOpts.ephemeris_source, E_OffsetType::APC, nav, false); - - break; - } - } - - if (pass == false) - { - BOOST_LOG_TRIVIAL(info) - << Sat.id() << " failed ssrEph precise prediction.\n"; - break; - } - - Vector3d precPos = obs.rSat; - Vector3d precVel = obs.satVel; + } + Vector3d precPos = obs.rSat; + Vector3d precVel = obs.satVel; + double posVar = obs.posVar; //output the valid entries { @@ -668,7 +774,7 @@ void prepareSsrStates( entry.doubleMap [SSR_CLOCK SSR_BRDC ] = {brdcClkVal, false}; entry.doubleMap [SSR_CLOCK SSR_PREC ] = {precClkVal, false}; entry.timeMap [SSR_UPDATED ] = {time, false}; - entry.intMap [SSR_IODE ] = {iode, false}; + entry.intMap [SSR_IODE ] = {iodeClk, false}; dbEntryList.push_back(entry); } @@ -683,16 +789,18 @@ void prepareSsrStates( entry.vectorMap [SSR_VEL SSR_BRDC ] = {brdcVel, false}; entry.vectorMap [SSR_POS SSR_PREC ] = {precPos, false}; entry.vectorMap [SSR_VEL SSR_PREC ] = {precVel, false}; + entry.doubleMap [SSR_VAR ] = {posVar, false}; entry.timeMap [SSR_UPDATED ] = {time, false}; - entry.intMap [SSR_IODE ] = {iode, false}; + entry.intMap [SSR_IODE ] = {iodePos, false}; dbEntryList.push_back(entry); } } - switch (acsConfig.ssrOpts.code_bias_source) + E_Source source = acsConfig.ssrOpts.code_bias_sources.front(); + switch (source) { - case E_Ephemeris::PRECISE: + case E_Source::PRECISE: { for (auto& obsCode : acsConfig.code_priorities[Sat.sys]) { @@ -710,7 +818,7 @@ void prepareSsrStates( entry.timeMap [SSR_EPOCH ] = {time, true}; entry.stringMap [SSR_OBSCODE ] = {obsCode._to_string(), true}; - entry.doubleMap [SSR_BIAS ] = {-bias, false}; + entry.doubleMap [SSR_BIAS ] = {bias, false}; entry.doubleMap [SSR_VAR ] = {bvar, false}; entry.timeMap [SSR_UPDATED ] = {time, false}; @@ -719,7 +827,8 @@ void prepareSsrStates( break; } - case E_Ephemeris::SSR: + + case E_Source::SSR: { auto it = satNav.receivedSSR.ssrCodeBias_map.upper_bound(time); if (it == satNav.receivedSSR.ssrCodeBias_map.end()) @@ -745,11 +854,76 @@ void prepareSsrStates( break; } + + case E_Source::KALMAN: + { + for (auto& obsCode : acsConfig.code_priorities[Sat.sys]) + { + double bias = 0; + double bvar = 0; + bool pass = queryBiasOutput(trace, time, Sat,"", obsCode, bias, bvar, CODE); + if (pass == false) + { + continue; + } + + DBEntry entry; + entry.stringMap [SSR_DATA ] = {SSR_CODE_BIAS, true}; + entry.stringMap [SSR_SAT ] = {Sat.id(), true}; + entry.timeMap [SSR_EPOCH ] = {time, true}; + entry.stringMap [SSR_OBSCODE ] = {obsCode._to_string(), true}; + + entry.doubleMap [SSR_BIAS ] = {bias, false}; + entry.doubleMap [SSR_VAR ] = {bvar, false}; + entry.timeMap [SSR_UPDATED ] = {time, false}; + + dbEntryList.push_back(entry); + } + + break; + } } - switch (acsConfig.ssrOpts.phase_bias_source) + source = acsConfig.ssrOpts.phase_bias_sources.front(); + switch (source) { - case E_Ephemeris::SSR: + case E_Source::PRECISE: + { + for (auto& obsCode : acsConfig.code_priorities[Sat.sys]) + { + double bias = 0; + double bvar = 0; + bool pass = getBiasSinex(trace, time, Sat.id(), Sat, obsCode, PHAS, bias, bvar); + if (pass == false) + { + continue; + } + + DBEntry entry; + entry.stringMap [SSR_DATA ] = {SSR_PHAS_BIAS, true}; + entry.stringMap [SSR_SAT ] = {Sat.id(), true}; + entry.timeMap [SSR_EPOCH ] = {time, true}; + entry.stringMap [SSR_OBSCODE ] = {obsCode._to_string(), true}; + + entry.doubleMap [SSR_BIAS ] = {bias, false}; + entry.doubleMap [SSR_VAR ] = {bvar, false}; + entry.timeMap [SSR_UPDATED ] = {time, false}; + + entry.intMap ["dispBiasConistInd"] = {0, false}; + entry.intMap ["MWConistInd" ] = {1, false}; + entry.doubleMap ["yawAngle" ] = {0, false}; /* To Do: reflect internal yaw calculation here */ + entry.doubleMap ["yawRate" ] = {0, false}; /* To Do: reflect internal yaw calculation here */ + entry.intMap ["signalIntInd" ] = {1, false}; + entry.intMap ["signalWLIntInd" ] = {2, false}; + entry.intMap ["signalDisconCnt" ] = {0, false}; + + dbEntryList.push_back(entry); + } + + break; + } + + case E_Source::SSR: { auto it = satNav.receivedSSR.ssrPhasBias_map.upper_bound(time); if (it == satNav.receivedSSR.ssrPhasBias_map.end()) @@ -777,7 +951,7 @@ void prepareSsrStates( entry.doubleMap ["yawAngle" ] = {ssrPhase.yawAngle, false}; entry.doubleMap ["yawRate" ] = {ssrPhase.yawRate, false}; entry.intMap ["signalIntInd" ] = {ssrPhaseChs[obsCode].signalIntInd, false}; - entry.intMap ["signalWidIntInd" ] = {ssrPhaseChs[obsCode].signalWidIntInd, false}; + entry.intMap ["signalWLIntInd" ] = {ssrPhaseChs[obsCode].signalWLIntInd, false}; entry.intMap ["signalDisconCnt" ] = {ssrPhaseChs[obsCode].signalDisconCnt, false}; dbEntryList.push_back(entry); @@ -786,38 +960,14 @@ void prepareSsrStates( break; } - case E_Ephemeris::KALMAN: + case E_Source::KALMAN: { double bias; double bvar; - if (queryBiasOutput(trace, Sat, E_AmbTyp::UCL1, bias, bvar)) - { - E_ObsCode obsCode = acsConfig.clock_codesL1[sys]; - DBEntry entry; - entry.stringMap [SSR_DATA ] = {SSR_PHAS_BIAS, true}; - entry.stringMap [SSR_SAT ] = {Sat.id(), true}; - entry.timeMap [SSR_EPOCH ] = {time, true}; - entry.stringMap [SSR_OBSCODE ] = {obsCode._to_string(), true}; - - entry.doubleMap [SSR_BIAS ] = {bias, false}; - entry.doubleMap [SSR_VAR ] = {bvar, false}; - entry.timeMap [SSR_UPDATED ] = {time, false}; - - entry.intMap ["dispBiasConistInd"] = {0, false}; - entry.intMap ["MWConistInd" ] = {1, false}; - entry.doubleMap ["yawAngle" ] = {0, false}; /* To Do: reflect internal yaw calculation here */ - entry.doubleMap ["yawRate" ] = {0, false}; /* To Do: reflect internal yaw calculation here */ - entry.intMap ["signalIntInd" ] = {1, false}; - entry.intMap ["signalWidIntInd" ] = {2, false}; - entry.intMap ["signalDisconCnt" ] = {0, false}; - - dbEntryList.push_back(entry); - } - - if (queryBiasOutput(trace, Sat, E_AmbTyp::UCL2, bias, bvar)) + for (auto& obsCode : acsConfig.code_priorities[sys]) + if (queryBiasOutput(trace, time, Sat, "", obsCode, bias, bvar, PHAS)) { - E_ObsCode obsCode = acsConfig.clock_codesL2[sys]; DBEntry entry; entry.stringMap [SSR_DATA ] = {SSR_PHAS_BIAS, true}; entry.stringMap [SSR_SAT ] = {Sat.id(), true}; @@ -833,7 +983,7 @@ void prepareSsrStates( entry.doubleMap ["yawAngle" ] = {0, false}; /* To Do: reflect internal yaw calculation here */ entry.doubleMap ["yawRate" ] = {0, false}; /* To Do: reflect internal yaw calculation here */ entry.intMap ["signalIntInd" ] = {1, false}; - entry.intMap ["signalWidIntInd" ] = {2, false}; + entry.intMap ["signalWLIntInd" ] = {2, false}; entry.intMap ["signalDisconCnt" ] = {0, false}; dbEntryList.push_back(entry); @@ -845,13 +995,221 @@ void prepareSsrStates( } } - if (acsConfig.output_mongo_rtcm_messages) + // IGS SSR Ionosphere + E_Source source = acsConfig.ssrOpts.ionosphere_sources.front(); + switch (source) + { + case E_Source::SSR: + case E_Source::KALMAN: + { + auto it = nav.ssrAtm.atmosGlobalMap.lower_bound(time); + if (it == nav.ssrAtm.atmosGlobalMap.end()) + break; + + auto& [t0, atmGlob] = *it; + + if (fabs((atmGlob.time - time).to_double()) > acsConfig.ssrInOpts.global_vtec_valid_time) + break; + + if (atmGlob.layers.size()==0) + break; + + int nbasis=0; + for (auto& [hind, laydata]: atmGlob.layers) + for (auto& [bind, basdata]: laydata.sphHarmonic) + { + DBEntry entry; + entry.stringMap [SSR_DATA ] = {IGS_ION_ENTRY, true}; + entry.timeMap [SSR_EPOCH ] = {atmGlob.time, true}; + entry.intMap [SSR_ION_IND ] = {nbasis++, true}; + + entry.intMap [IGS_ION_HGT ] = {basdata.hind, false}; + entry.intMap [IGS_ION_DEG ] = {basdata.degree, false}; + entry.intMap [IGS_ION_ORD ] = {basdata.order, false}; + entry.intMap [IGS_ION_PAR ] = {basdata.parity, false}; + entry.doubleMap [IGS_ION_VAL ] = {basdata.coeffc, false}; + + dbEntryList.push_back(entry); + } + + { + DBEntry entry; + entry.stringMap [SSR_DATA ] = {IGS_ION_META, true}; + entry.timeMap [SSR_EPOCH ] = {atmGlob.time, true}; + + entry.intMap [IGS_ION_NLAY ] = {atmGlob.numberLayers, false}; + entry.intMap [IGS_ION_NBAS ] = {nbasis, false}; + entry.doubleMap [IGS_ION_QLTY ] = {atmGlob.vtecQuality, false}; + for (auto& [hind, laydata]: atmGlob.layers) + { + string hghStr = "Height_"+std::to_string(hind); + entry.doubleMap [hghStr ] = {laydata.height, false}; + } + dbEntryList.push_back(entry); + } + } + } + + if (acsConfig.localMongo. output_ssr_precursors) mongoOutput(dbEntryList, acsConfig.localMongo, SSR_DB); + if (acsConfig.remoteMongo. output_ssr_precursors) mongoOutput(dbEntryList, acsConfig.remoteMongo, SSR_DB); +} + +void outputMongoPredictions( + Trace& trace, ///< Trace to output to + Orbits& orbits, ///< Filter object to extract state elements from + GTime time, ///< Time of current epoch + MongoOptions& config) +{ + vector dbEntryList; + + time.bigTime = (long int) (time.bigTime + 0.5); // time tags in mongo will be rounded up to whole sec + + for (auto& orbit : orbits) + { + DBEntry entry; + entry.stringMap [REMOTE_DATA ] = {REMOTE_ORBIT, true}; + entry.stringMap [REMOTE_SAT ] = {orbit.Sat.id(), true}; + entry.timeMap [REMOTE_EPOCH ] = {time, true}; + + entry.timeMap [REMOTE_UPDATED ] = {tsync, false}; + entry.vectorMap [REMOTE_POS ] = {orbit.pos, false}; + entry.vectorMap [REMOTE_VEL ] = {orbit.vel, false}; + + dbEntryList.push_back(entry); + } + + BOOST_LOG_TRIVIAL(debug) + << "Writing to mongo\n"; + + mongoOutput(dbEntryList, config, REMOTE_DATA_DB); +} + +/** Write GPS/GAL/BDS/QZS ephemeris to Mongo DB +*/ +void mongoBrdcEph( + Eph& eph) ///< GPS/GAL/BDS/QZS ephemeris to write +{ + auto& mongo_ptr = remoteMongo_ptr; + + if (mongo_ptr == nullptr) { - BOOST_LOG_TRIVIAL(debug) - << "Writing to mongo\n"; + MONGO_NOT_INITIALISED_MESSAGE; - mongoCull(time - 300.0); - mongoOutput(dbEntryList); + acsConfig.remoteMongo.output_rtcm_messages = false; + + return; + } + + Instrument instrument(__FUNCTION__); + + Mongo& mongo = *mongo_ptr; + + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[acsConfig.remoteMongo.database]; + mongocxx::collection coll = db ["Ephemeris"]; + + mongocxx::options::update options; + options.upsert(true); + + mongocxx::options::bulk_write bulk_opts; + bulk_opts.ordered(false); + + auto bulk = coll.create_bulk_write(bulk_opts); + + bool update = false; + + bsoncxx::builder::basic::document keyDoc = {}; + + // Note the Satellite id is not set in rinex correctly as we a mixing GNSS systems. + keyDoc.append(kvp("Sat", eph.Sat.id() )); + keyDoc.append(kvp("Type", eph.type._to_string() )); + keyDoc.append(kvp("ToeGPST", b_date {std::chrono::system_clock::from_time_t((time_t)((PTime)eph.toe).bigTime)} )); + keyDoc.append(kvp("TocGPST", b_date {std::chrono::system_clock::from_time_t((time_t)((PTime)eph.toc).bigTime)} )); + + bsoncxx::builder::basic::document valDoc = {}; + + traceBrdcEphBody(valDoc, eph); + + mongocxx::model::update_one mongo_req( + keyDoc.extract(), + + document{} + << "$set" << valDoc + << finalize + ); + + mongo_req.upsert(true); + bulk.append(mongo_req); + update = true; + + if (update) + { + bulk.execute(); } } +/** Write GLO ephemeris to Mongo DB +*/ +void mongoBrdcEph( + Geph& geph) ///< GLO ephemeris to write +{ + auto& mongo_ptr = remoteMongo_ptr; + + if (mongo_ptr == nullptr) + { + MONGO_NOT_INITIALISED_MESSAGE; + + acsConfig.remoteMongo.output_rtcm_messages = false; + + return; + } + + Instrument instrument(__FUNCTION__); + + Mongo& mongo = *mongo_ptr; + + auto c = mongo.pool.acquire(); + mongocxx::client& client = *c; + mongocxx::database db = client[acsConfig.remoteMongo.database]; + mongocxx::collection coll = db ["Ephemeris"]; + + mongocxx::options::update options; + options.upsert(true); + + mongocxx::options::bulk_write bulk_opts; + bulk_opts.ordered(false); + + auto bulk = coll.create_bulk_write(bulk_opts); + + bool update = false; + + bsoncxx::builder::basic::document keyDoc = {}; + + // Note the Satellite id is not set in rinex correctly as we a mixing GNSS systems. + keyDoc.append(kvp("Sat", geph.Sat.id() )); + keyDoc.append(kvp("Type", geph.type._to_string() )); + keyDoc.append(kvp("ToeGPST", b_date {std::chrono::system_clock::from_time_t((time_t)((PTime)geph.toe).bigTime)} )); + keyDoc.append(kvp("TofGPST", b_date {std::chrono::system_clock::from_time_t((time_t)((PTime)geph.tof).bigTime)} )); + + bsoncxx::builder::basic::document valDoc = {}; + + traceBrdcEphBody(valDoc, geph); + + mongocxx::model::update_one mongo_req( + keyDoc.extract(), + + document{} + << "$set" << valDoc + << finalize + ); + + mongo_req.upsert(true); + bulk.append(mongo_req); + update = true; + + if (update) + { + bulk.execute(); + } +} diff --git a/src/cpp/common/mongoWrite.hpp b/src/cpp/common/mongoWrite.hpp index 36a1e4bf4..3c35f42f6 100644 --- a/src/cpp/common/mongoWrite.hpp +++ b/src/cpp/common/mongoWrite.hpp @@ -1,7 +1,5 @@ -#ifndef ___WRITEMONGO_HPP__ -#define ___WRITEMONGO_HPP__ - +#pragma once #include @@ -26,16 +24,16 @@ struct TestStatistics void mongoMeasResiduals( GTime time, - vector& obsKeys, - VectorXd& prefits, - VectorXd& postfits, - MatrixXd& variance, - string suffix = "", - int beg = 0, - int num = -1); + KFMeas& kfMeas, + string suffix = "", + int beg = 0, + int num = -1); + +void mongoTrace( + string json); -void mongoMeasComponents( - KFMeas& kfMeas); +void mongoOutputConfig( + string& config); void mongoStates( KFState& kfState, @@ -48,5 +46,22 @@ void mongoTestStat( KFState& kfState, TestStatistics& statistics); -#endif +void mongoBrdcEph( + Eph& eph); + +void mongoBrdcEph( + Geph& geph); + +struct OrbitState; +struct MongoOptions; + +typedef vector Orbits; + +void outputMongoPredictions( + Trace& trace, + Orbits& orbits, + GTime time, + MongoOptions& config); +void mongoCull( + GTime time); diff --git a/src/cpp/common/mqtt.cpp b/src/cpp/common/mqtt.cpp new file mode 100644 index 000000000..e7ed9b8bc --- /dev/null +++ b/src/cpp/common/mqtt.cpp @@ -0,0 +1,195 @@ + +// #pragma GCC optimize ("O0") + +#include +#include +#include +#include + +using std::shared_ptr; +using std::vector; + +#define MQTT_STD_VARIANT +#define MQTT_USE_WS + +#include + +#include "coordinates.hpp" +#include "algebra.hpp" + +// #include + +bool mqttIsInitialised = false; +std::shared_ptr>>> mqttClient_ptr; +boost::asio::io_context ioc; + +void outputMqtt( + KFState& kfState) +{ + if (mqttIsInitialised == false) + { + return; + } + + for (int dt : {0,1}) + { + kfState.stateTransition(std::cout, kfState.time + dt * 608400); + + for (auto& [kfKey, index] : kfState.kfIndexMap) + { + if ( kfKey.type != KF::REC_POS + ||kfKey.num != 0) + { + continue; + } + + Vector3d rRec; + for (int i = 0; i < 3; i++) + { + KFKey posKey = kfKey; + posKey.num = i; + kfState.getKFValue(posKey, rRec(i)); + } + + double pos[3]; + ecef2pos(rRec, pos); + + char data[2048]; + snprintf(data, sizeof(data), "{\"time\": \"%s\", \"coordinates\": [%25.20f, %25.20f], \"rotation\": 0}", kfState.time.to_string().c_str(), pos[1] * R2D, pos[0] * R2D); + + if (pos[0] * R2D < -10) + if (pos[1] * R2D > 112) + { + mqttClient_ptr->async_publish("site/" + kfKey.str, data, MQTT_NS::qos::exactly_once | MQTT_NS::retain::yes); + } + } + + } +} + +void mqttoooo() +{ + MQTT_NS::setup_log(); + + uint16_t port = 9001; + +// auto c = MQTT_NS::make_sync_client(ioc, "localhost", port); + mqttClient_ptr = MQTT_NS::make_async_client_ws(ioc, "localhost", port); + + auto& c = mqttClient_ptr; + + using packet_id_t = typename std::remove_reference_t::packet_id_t; + + // Setup client + c->set_client_id("ginan"); + c->set_clean_session(true); + + uint16_t pid_sub3 = c->acquire_unique_packet_id(); + + // Setup handlers + c->set_connack_handler( [&c, &pid_sub3](bool sp, MQTT_NS::connect_return_code connack_return_code) + { + std::cout << "[client] Connack handler called" << std::endl; + std::cout << "[client] Session Present: " << std::boolalpha << sp << std::endl; + std::cout << "[client] Connack Return Code: " << MQTT_NS::connect_return_code_to_str(connack_return_code) << std::endl; + + if (connack_return_code == MQTT_NS::connect_return_code::accepted) + { + mqttIsInitialised = true; +// pid_sub1 = c->subscribe("mqtt_client_cpp/topic1", MQTT_NS::qos::at_most_once); +// pid_sub3 = c->subscribe("iss", MQTT_NS::qos::at_least_once); +// c->publish("mqtt_client_cpp/topic2_1", "test2_1", MQTT_NS::qos::at_least_once); + c->async_publish( + "mqtt_client_cpp/topic1", + "test1", + MQTT_NS::qos::exactly_once, + // [optional] checking async_publish completion code + [] + (MQTT_NS::error_code ec){ + std::cout << "async_publish callback: " << ec.message() << std::endl; + } + ); + } +// c->async_subscribe( +// pid_sub3, +// "iss", +// MQTT_NS::qos::at_most_once/*, +// // [optional] checking async_subscribe completion code +// [] +// (MQTT_NS::error_code ec) +// { +// std::cout << "async_subscribe callback: " << ec.message() << std::endl; +// }*/ +// ); + + return true; + }); + + c->set_close_handler( [] () { std::cout << "[client] closed." << std::endl; }); + c->set_error_handler( [] (MQTT_NS::error_code ec) { std::cout << "[client] error: " << ec.message() << std::endl; }); + c->set_puback_handler( [&] (packet_id_t packet_id) { std::cout << "[client] puback received. packet_id: " << packet_id << std::endl; return true; }); + c->set_pubrec_handler( [&] (packet_id_t packet_id) { std::cout << "[client] pubrec received. packet_id: " << packet_id << std::endl; return true; }); + c->set_pubcomp_handler( [&] (packet_id_t packet_id) { std::cout << "[client] pubcomp received. packet_id: " << packet_id << std::endl; return true; }); + + c->set_suback_handler( + [&] + (packet_id_t packet_id, vector results) + { +// std::cout << "[client] suback received. packet_id: " << packet_id << std::endl; +// for (auto const& e : results) +// { +// std::cout << "[client] subscribe result: " << e << std::endl; +// } +// +// if (packet_id == pid_sub1) +// { +// c->publish("mqtt_client_cpp/topic1", "test1", MQTT_NS::qos::at_most_once); +// } +// else if (packet_id == pid_sub2) +// { +// c->publish("mqtt_client_cpp/topic2_1", "test2_1", MQTT_NS::qos::at_least_once); +// c->publish("mqtt_client_cpp/topic2_2", "test2_2", MQTT_NS::qos::exactly_once); +// } +// +// std::cout << std::endl; + return true; + }); + + c->set_publish_handler( + [&] + (MQTT_NS::optional packet_id, + MQTT_NS::publish_options pubopts, + MQTT_NS::buffer topic_name, + MQTT_NS::buffer contents) + { + std::cout + << "[client] publish received. " + << " dup: " << pubopts.get_dup() + << " qos: " << pubopts.get_qos() + << " retain: " << pubopts.get_retain() << std::endl; + + if (packet_id) + std::cout << "[client] packet_id: " << *packet_id << std::endl; + std::cout << "[client] topic_name: " << topic_name << std::endl; + std::cout << "[client] contents: " << contents << std::endl; + std::cout << std::endl; + + return true; + }); + + // Connect +// c->connect(); + mqttClient_ptr->async_connect( + // [optional] checking underlying layer completion code + [] + (MQTT_NS::error_code ec) + { + std::cout << "async_connect callback: " << ec.message() << std::endl; + } + ); +// c->disconnect(); + + + std::thread([](){ioc.run();}).detach(); +// ioc.run(); +} diff --git a/src/cpp/common/navigation.hpp b/src/cpp/common/navigation.hpp index 27e42e1c1..18aac5959 100644 --- a/src/cpp/common/navigation.hpp +++ b/src/cpp/common/navigation.hpp @@ -1,35 +1,27 @@ -#ifndef __NAVIGATION_HPP__ -#define __NAVIGATION_HPP__ + +#pragma once #include #include #include -#include #include -#include -#include -#include #include -#include #include #include -using std::unordered_set; -using std::unordered_map; using std::string; -using std::list; using std::map; using std::set; -#include "streamTrace.hpp" +#include "azElMapData.hpp" #include "ephemeris.hpp" #include "antenna.hpp" -#include "gravity.hpp" #include "orbits.hpp" #include "satSys.hpp" #include "gTime.hpp" +#include "trace.hpp" #include "enums.h" #include "ssr.hpp" #include "erp.hpp" @@ -38,9 +30,6 @@ using std::set; #define MAXDTE 900.0 /* max time difference to ephem time (s) */ -typedef map PephList; -typedef list PclkList; - struct TECPoint { double data = 0; ///< TEC grid data (tecu) @@ -59,61 +48,71 @@ struct tec_t vector tecPointVector; }; - struct SatNav { map lamMap; double wlbias; ///< wide-lane bias (cycle) SSRMaps receivedSSR; ///< SSR corrections + SSRMaps transmittedSSR; ///< SSR corrections SatOrbit satOrbit = {}; - Eph* eph_ptr = nullptr; - Geph* geph_ptr = nullptr; - Seph* seph_ptr = nullptr; - Ceph* ceph_ptr = nullptr; - STO* sto_ptr = nullptr; - EOP* eop_ptr = nullptr; - ION* ion_ptr = nullptr; + VectorEci aprioriPos; ///< Inertial satellite position at epoch time + + BrdcEph* eph_ptr = nullptr; + MatrixXd satPartialMat; ///< Partial derivative matrices for orbits + + AttStatus attStatus = {}; ///< Persistent data for attitude model + + string id; + string traceFilename; + + Vector3d antBoresight = {0,0,1}; + Vector3d antAzimuth = {0,1,0}; }; +/** navigation data type + */ struct Navigation { - ///< navigation data type - - map>>>> pcoMap; - map>>>> pcvMap; + //these are interpolated between, dont need greater + map> pephMap; ///< precise ephemeris + map> pclkMap; ///< precise clock + map> attMapMap; ///< attitudes - map>> ephMap; /* GPS/QZS/GAL/BDS ephemeris */ - map>> gephMap; /* GLONASS ephemeris */ - map>> sephMap; /* SBAS ephemeris */ - map>>> cephMap; /* GPS/QZS/BDS CNVX ephemeris */ - map>>> ionMap; /* ION messages */ - map>>> stoMap; /* STO messages */ - map>>> eopMap; /* EOP messages */ - map pephMap; /* precise ephemeris */ - map pclkMap; /* precise clock */ - map> tecMap; /* tec grid data */ + map, std::greater>> dragMap; + map, std::greater>> reflectorMap; + map>>>> pcoMap; + map>>>> pcvMap; - map satNavMap; + map>>> ephMap; ///< GPS/QZS/GAL/BDS ephemeris + map>>> gephMap; ///< GLONASS ephemeris + map>>> sephMap; ///< SBAS ephemeris + map>>> cephMap; ///< GPS/QZS/BDS CNVX ephemeris + map>>> ionMap; ///< ION messages + map>>> stoMap; ///< STO messages + map>>> eopMap; ///< EOP messages + map> tecMap; ///< tec grid data + map>> svnMap; ///< Sat SVNs + + map blocktypeMap; ///< svn blocktypes + + map satNavMap; + SSRAtm ssrAtm; -// list fcbList; /* satellite fcb data */ - vmf3_t vmf3 = {.m = 1}; - ERP erp; /* earth rotation parameters */ - int leaps; /* leap seconds (s) */ - char glo_fcn[MAXPRNGLO+1]; /* glonass frequency channel number + 8 */ - double glo_cpbias[4]; /* glonass code-phase bias {1C,1P,2C,2P} (m) */ + Vmf3 vmf3; + ERP erp; /* earth rotation parameters */ + int leaps = -1; /* leap seconds (s) */ + char glo_fcn[NSATGLO+1]; /* glonass frequency channel number + 8 */ + double glo_cpbias[4]; /* glonass code-phase bias {1C,1P,2C,2P} (m) */ - EGMCoef egm; struct jpl_eph_data* jplEph_ptr = nullptr; - - list podInfoList; + vector podInfoList; - double orography[NGRID] = {}; /* vmf3 orography information, config->orography */ - gptgrid_t gptg = {}; /* gpt grid information */ + gptgrid_t gptg = {}; ///< gpt grid information template void serialize(ARCHIVE& ar, const unsigned int& version) @@ -129,7 +128,7 @@ namespace boost::serialization template void serialize(ARCHIVE& ar, Navigation& nav) { - ar & nav.ephMap; +// ar & nav.ephMap; } } @@ -139,4 +138,3 @@ extern map defNavMsgType; extern Navigation nav; -#endif diff --git a/src/cpp/common/ntripBroadcast.cpp b/src/cpp/common/ntripBroadcast.cpp index 563122183..7101f5781 100644 --- a/src/cpp/common/ntripBroadcast.cpp +++ b/src/cpp/common/ntripBroadcast.cpp @@ -4,14 +4,20 @@ #include #include +#include + +using std::chrono::system_clock; +using std::chrono::time_point; + using bsoncxx::builder::basic::kvp; #include "ntripBroadcast.hpp" -#include "acsStream.hpp" #include "mongoRead.hpp" +#include "otherSSR.hpp" #include "fileLog.hpp" #include "gTime.hpp" + NtripBroadcaster ntripBroadcaster; namespace bp = boost::asio::placeholders; @@ -20,14 +26,7 @@ namespace bp = boost::asio::placeholders; using boost::posix_time::ptime; using boost::posix_time::time_duration; -ptime round_to( - ptime t, - time_duration period) -{ - auto units = (t.time_of_day() + period/2).total_seconds() / period.total_seconds(); - - return { t.date(), period*units }; -} +void debugSSR(GTime time, E_Sys sys); void NtripBroadcaster::startBroadcast() { @@ -48,10 +47,10 @@ void NtripUploader::serverResponse( unsigned int status_code, string http_version) { - if (acsConfig.output_log == false) + if (acsConfig.output_ntrip_log == false) return; - std::ofstream logStream(FileLog::path_log, std::ofstream::app); + std::ofstream logStream(networkTraceFilename, std::ofstream::app); if (!logStream) { @@ -59,12 +58,12 @@ void NtripUploader::serverResponse( return; } - auto time = std::chrono::system_clock::to_time_t(system_clock::now()); + GTime time = timeGet(); bsoncxx::builder::basic::document doc = {}; doc.append(kvp("label", "serverResponse")); doc.append(kvp("Stream", url.path.substr(1,url.path.length()))); -// doc.append(kvp("Time", std::put_time(std::localtime( &time ), "%F %X"))); + doc.append(kvp("Time", time.to_string())); doc.append(kvp("ServerStatus", (int)status_code)); doc.append(kvp("VersionHTTP", http_version)); @@ -88,7 +87,7 @@ void NtripUploader::write_handler( outMessagesMtx.unlock(); } -void NtripUploader::messageTimeout_hanlder( +void NtripUploader::messageTimeout_handler( const boost::system::error_code& err) { // BOOST_LOG_TRIVIAL(debug) << "started " << __FUNCTION__ << "\n"; @@ -97,117 +96,330 @@ void NtripUploader::messageTimeout_hanlder( ERROR_OUTPUT_RECONNECT_AND_RETURN; } - int period = streamConfig.update_interval; - int udiIndex = getUdiIndex(period); - - //fire this callback again in the future { - boost::posix_time::ptime now = boost::posix_time::second_clock::universal_time(); - auto then = round_to(now, boost::posix_time::seconds(period)); - then += boost::posix_time::seconds(period); - sendTimer.expires_at(then); - sendTimer.async_wait(boost::bind(&NtripUploader::messageTimeout_hanlder, this, bp::error)); + sendTimer.expires_from_now(boost::posix_time::milliseconds(500)); // check uploader twice a second to account for aliasing + sendTimer.async_wait(boost::bind(&NtripUploader::messageTimeout_handler, this, bp::error)); } + SSRMeta ssrMeta; + SsrOutMap ssrOutMap; - SSRMeta ssrMeta; - ssrMeta.ssrUpdateIntIndex = udiIndex; - if (ssrMeta.ssrUpdateIntIndex == -1) - BOOST_LOG_TRIVIAL(error) << "Error: ssrMeta.ssrUpdateIntIndex is not valid :" << ssrMeta.ssrUpdateIntIndex << ")."; + GTime nowTime = timeGet(); + GTime targetTime = nowTime.floorTime(1); - GTime nowTime = timeget(); - GTime targetTime; + if (targetTime == previousTargetTime) { - int week; - double tow = time2gpst(timeget() + period / 2, &week); - double roundedTow = ((int)(tow / period)) * period; - - ssrMeta.epochTime1s = roundedTow; - targetTime = gpst2time(week, roundedTow); + //already did this epoch + return; } + ssrMeta.receivedTime = targetTime; // for rtcmTrace (debugging) ssrMeta.multipleMessage = 1; // We assume there will be more messages. - if (streamConfig.itrf_datum) ssrMeta.referenceDatum = 1; // Orbit corrections, 0 - ITRF, 1 - Regional. - else ssrMeta.referenceDatum = 0; + if (streamConfig.itrf_datum) ssrMeta.referenceDatum = 0; // Orbit corrections, 0 - ITRF, 1 - Regional. + else ssrMeta.referenceDatum = 1; ssrMeta.provider = streamConfig.provider_id; - ssrMeta.provider = streamConfig.solution_id; - int masterIod = streamConfig.master_iod; - - for (auto RtcmMess : streamConfig.rtcmMessagesTypes) + ssrMeta.solution = streamConfig.solution_id; + + for (auto [messCode, msgOpts] : streamConfig.rtcmMsgOptsMap) { - if (RtcmMess == *streamConfig.rtcmMessagesTypes.rbegin()) + int updateInterval = msgOpts.udi; + + if ( updateInterval == 0 + ||((long int)targetTime) % updateInterval != 0) + { + continue; + } + + int udiIndex = getUdiIndex(updateInterval); + + ssrMeta.updateIntIndex = udiIndex; + + if (ssrMeta.updateIntIndex == -1) + BOOST_LOG_TRIVIAL(error) << "Error: ssrMeta.updateIntIndex is not valid :" << ssrMeta.updateIntIndex << ")."; + + if (messCode == streamConfig.rtcmMsgOptsMap.rbegin()->first) ssrMeta.multipleMessage = 0; - E_Sys sys; - switch (RtcmMess) + E_Sys sys = rtcmMessageSystemMap[messCode]; + + if (sys == +E_Sys::NONE) { - case +RtcmMessageType::GPS_SSR_COMB_CORR: - case +RtcmMessageType::GPS_SSR_PHASE_BIAS: - case +RtcmMessageType::GPS_SSR_CODE_BIAS: - sys = E_Sys::GPS; - break; - case +RtcmMessageType::GAL_SSR_COMB_CORR: - case +RtcmMessageType::GAL_SSR_CODE_BIAS: - case +RtcmMessageType::GAL_SSR_PHASE_BIAS: - sys = E_Sys::GAL; - break; + BOOST_LOG_TRIVIAL(error) << "Error: invalid message code system :" << messCode; + continue; } - switch (RtcmMess) + if (sys == +E_Sys::GLO) { RTod tod = targetTime; ssrMeta.epochTime1s = (int)tod; } + else if (sys == +E_Sys::BDS) { BTow tow = targetTime; ssrMeta.epochTime1s = (int)tow; } + else { GTow tow = targetTime; ssrMeta.epochTime1s = (int)tow; } + + GTime t0; + if (ssrMeta.updateIntIndex == 0) t0 = targetTime; + else t0 = targetTime + updateInterval / 2.0; + + switch (messCode) { - case +RtcmMessageType::GAL_SSR_PHASE_BIAS: case +RtcmMessageType::GPS_SSR_PHASE_BIAS: + case +RtcmMessageType::GLO_SSR_PHASE_BIAS: + case +RtcmMessageType::GAL_SSR_PHASE_BIAS: + case +RtcmMessageType::QZS_SSR_PHASE_BIAS: + case +RtcmMessageType::BDS_SSR_PHASE_BIAS: + case +RtcmMessageType::SBS_SSR_PHASE_BIAS: { - auto ssrPBMap = mongoReadPhaseBias(targetTime, ssrMeta, masterIod, sys); + auto ssrPBMap = mongoReadPhaseBias(ssrMeta, masterIod, sys); - auto buffer = encodeSsrPhase(ssrPBMap); + auto buffer = encodeSsrPhase(ssrPBMap, messCode); bool write = encodeWriteMessageToBuffer(buffer); if (write == false) { - std::cout << "RtcmMessageType::" << RtcmMess._to_string() << " was not written" << std::endl; + std::cout << "RtcmMessageType::" << messCode._to_string() << " was not written" << std::endl; } break; } - case +RtcmMessageType::GAL_SSR_CODE_BIAS: case +RtcmMessageType::GPS_SSR_CODE_BIAS: + case +RtcmMessageType::GLO_SSR_CODE_BIAS: + case +RtcmMessageType::GAL_SSR_CODE_BIAS: + case +RtcmMessageType::QZS_SSR_CODE_BIAS: + case +RtcmMessageType::BDS_SSR_CODE_BIAS: + case +RtcmMessageType::SBS_SSR_CODE_BIAS: { - auto ssrCBMap = mongoReadCodeBias(targetTime, ssrMeta, masterIod, sys); + auto ssrCBMap = mongoReadCodeBias(ssrMeta, masterIod, sys); - auto buffer = encodeSsrCode(ssrCBMap); + auto buffer = encodeSsrCode(ssrCBMap, messCode); bool write = encodeWriteMessageToBuffer(buffer); if (write == false) { - std::cout << "RtcmMessageType::" << RtcmMess._to_string() << " was not written" << std::endl; + std::cout << "RtcmMessageType::" << messCode._to_string() << " was not written" << std::endl; } break; } - case +RtcmMessageType::GAL_SSR_COMB_CORR: case +RtcmMessageType::GPS_SSR_COMB_CORR: + case +RtcmMessageType::GLO_SSR_COMB_CORR: + case +RtcmMessageType::GAL_SSR_COMB_CORR: + case +RtcmMessageType::QZS_SSR_COMB_CORR: + case +RtcmMessageType::BDS_SSR_COMB_CORR: + case +RtcmMessageType::SBS_SSR_COMB_CORR: + case +RtcmMessageType::GPS_SSR_ORB_CORR: + case +RtcmMessageType::GLO_SSR_ORB_CORR: + case +RtcmMessageType::GAL_SSR_ORB_CORR: + case +RtcmMessageType::QZS_SSR_ORB_CORR: + case +RtcmMessageType::BDS_SSR_ORB_CORR: + case +RtcmMessageType::SBS_SSR_ORB_CORR: + case +RtcmMessageType::GPS_SSR_CLK_CORR: + case +RtcmMessageType::GLO_SSR_CLK_CORR: + case +RtcmMessageType::GAL_SSR_CLK_CORR: + case +RtcmMessageType::QZS_SSR_CLK_CORR: + case +RtcmMessageType::BDS_SSR_CLK_CORR: + case +RtcmMessageType::SBS_SSR_CLK_CORR: + case +RtcmMessageType::GPS_SSR_HR_CLK_CORR: + case +RtcmMessageType::GLO_SSR_HR_CLK_CORR: + case +RtcmMessageType::GAL_SSR_HR_CLK_CORR: + case +RtcmMessageType::QZS_SSR_HR_CLK_CORR: + case +RtcmMessageType::BDS_SSR_HR_CLK_CORR: + case +RtcmMessageType::SBS_SSR_HR_CLK_CORR: { - auto ssrOutMap = mongoReadSSRData(targetTime, ssrMeta, masterIod, sys); + ssrOutMap = mongoReadOrbClk(t0, ssrMeta, masterIod, sys); - calculateSsrComb(targetTime, period, ssrMeta, masterIod, ssrOutMap); + calculateSsrComb(t0, updateInterval, ssrMeta, masterIod, ssrOutMap); - auto buffer = encodeSsrComb(ssrOutMap); + auto buffer = encodeSsrOrbClk(ssrOutMap, messCode); bool write = encodeWriteMessageToBuffer(buffer); + debugSSR(t0, sys); + if (write == false) { - std::cout << "RtcmMessageType::" << RtcmMess._to_string() << " was not written" << std::endl; + std::cout << "RtcmMessageType::" << messCode._to_string() << " was not written" << std::endl; } break; } + case +RtcmMessageType::GPS_SSR_URA: + case +RtcmMessageType::GLO_SSR_URA: + case +RtcmMessageType::GAL_SSR_URA: + case +RtcmMessageType::QZS_SSR_URA: + case +RtcmMessageType::BDS_SSR_URA: + case +RtcmMessageType::SBS_SSR_URA: + { + auto buffer = encodeSsrUra(ssrOutMap, messCode); + bool write = encodeWriteMessageToBuffer(buffer); + + if (write == false) + { + std::cout << "RtcmMessageType::" << messCode._to_string() << " was not written" << std::endl; + } + + break; + } + case +RtcmMessageType::GPS_EPHEMERIS: + case +RtcmMessageType::BDS_EPHEMERIS: + case +RtcmMessageType::QZS_EPHEMERIS: + case +RtcmMessageType::GAL_FNAV_EPHEMERIS: + case +RtcmMessageType::GAL_INAV_EPHEMERIS: + { + bool write = false; + + for (auto& sat : getSysSats(sys)) + { + auto eph = mongoReadEphemeris(targetTime, sat, messCode); + + if (eph.toe == GTime::noTime()) + continue; + + auto buffer = encodeEphemeris(eph, messCode); + write |= encodeWriteMessageToBuffer(buffer); + } + + if (write == false) + { + std::cout << "RtcmMessageType::" << messCode._to_string() << " was not written" << std::endl; + } + + break; + } + case +RtcmMessageType::GLO_EPHEMERIS: + { + bool write = false; + + for (auto& sat : getSysSats(sys)) + { + auto geph = mongoReadGloEphemeris(targetTime, sat); + + if (geph.toe == GTime::noTime()) + continue; + + auto buffer = encodeEphemeris(geph, messCode); + write |= encodeWriteMessageToBuffer(buffer); + } + + if (write == false) + { + std::cout << "RtcmMessageType::" << messCode._to_string() << " was not written" << std::endl; + } + + break; + } + + case +RtcmMessageType::IGS_SSR: + { + SSRAtm ssrAtm; + map> SSROutmaps; + map SSRCodmaps; + map SSRPhsmaps; + map SSRURAmaps; + + IgsSSRSubtype lastSubType = IgsSSRSubtype::IGS_SSR_GPS_NONE; + map approvedMessages; + + E_Sys sys; + for (auto [subType, subUdi] : msgOpts.igs_udi) + { + if ( subUdi == 0 + || ((long int)targetTime) % subUdi != 0) + { + continue; + } + int subUdiIndex = getUdiIndex(subUdi); + ssrMeta.updateIntIndex = subUdiIndex; + if (ssrMeta.updateIntIndex == 0) t0 = targetTime; + else t0 = targetTime + subUdi/2.0; + + switch (IGS_SSR_group(subType, sys)) + { + case 1: + case 2: + case 3: + case 4: + { + auto sysOutMap = mongoReadOrbClk(t0, ssrMeta, masterIod, sys); + calculateSsrComb(t0, subUdi, ssrMeta, masterIod, sysOutMap); + if (sysOutMap.empty() == false) + { + lastSubType = subType; + SSROutmaps[sys] = sysOutMap; + approvedMessages[subType] = true; + } + break; + } + case 5: + { + auto sysCBMap = mongoReadCodeBias(ssrMeta, masterIod, sys); + if (sysCBMap.empty() == false) + { + lastSubType = subType; + SSRCodmaps[sys] = sysCBMap; + approvedMessages[subType] = true; + } + break; + } + case 6: + { + auto sysPBMap = mongoReadPhaseBias(ssrMeta, masterIod, sys); + if (sysPBMap.empty() == false) + { + lastSubType = subType; + SSRPhsmaps[sys] = sysPBMap; + approvedMessages[subType] = true; + } + break; + } + case 7: + { + // auto sysUraMap = mongoReadUra(t0, ssrMeta, masterIod, sys); // Eugene: use sysOutMap? + // if (sysUraMap.empty() == false) + // { + // lastSubType = subType; + // SSRURAmaps[sys] = sysUraMap; + // approvedMessages[subType] = true; + // } + break; + } + case 8: + { + ssrAtm = mongoReadIGSIonosphere(targetTime, ssrMeta, masterIod); + if (ssrAtm.atmosGlobalMap.empty() == false) + { + lastSubType = subType; + approvedMessages[subType] = true; + } + break; + } + } + } + + if (approvedMessages.empty()) + break; + + for (auto [subType, subUdi] : msgOpts.igs_udi) + { + if (approvedMessages[subType] == false) + continue; + + bool last = (lastSubType == subType); + + switch(IGS_SSR_group (subType, sys)) + { + case 1: {auto buffer = encodeIGS_ORB(SSROutmaps[sys], sys, last); encodeWriteMessageToBuffer(buffer); break;} + case 2: {auto buffer = encodeIGS_CLK(SSROutmaps[sys], sys, last); encodeWriteMessageToBuffer(buffer); break;} + case 3: {auto buffer = encodeIGS_CMB(SSROutmaps[sys], sys, last); encodeWriteMessageToBuffer(buffer); break;} + case 4: {auto buffer = encodeIGS_HRC(SSROutmaps[sys], sys, last); encodeWriteMessageToBuffer(buffer); break;} + case 5: {auto buffer = encodeIGS_COD(SSRCodmaps[sys], sys, last); encodeWriteMessageToBuffer(buffer); break;} + case 6: {auto buffer = encodeIGS_PHS(SSRPhsmaps[sys], sys, last); encodeWriteMessageToBuffer(buffer); break;} + case 7: {auto buffer = encodeIGS_URA(SSRURAmaps[sys], sys, last); encodeWriteMessageToBuffer(buffer); break;} + case 8: {auto buffer = encodeIGS_ATM(ssrAtm, last); encodeWriteMessageToBuffer(buffer); break;} + } + } + break; + } default: - BOOST_LOG_TRIVIAL(error) << "Error, attempting to upload incorrect message type.\n"; + BOOST_LOG_TRIVIAL(error) << "Error, attempting to upload incorrect message type: " << messCode << std::endl; } } @@ -242,7 +454,7 @@ void NtripUploader::startBroadcast() // BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " Starting Send Loop.\n"; sendTimer.expires_from_now(boost::posix_time::seconds(1)); - sendTimer.async_wait(boost::bind(&NtripUploader::messageTimeout_hanlder, this, bp::error)); + sendTimer.async_wait(boost::bind(&NtripUploader::messageTimeout_handler, this, bp::error)); } void NtripUploader::connected() diff --git a/src/cpp/common/ntripBroadcast.hpp b/src/cpp/common/ntripBroadcast.hpp index 11466fcc7..d4f31d875 100644 --- a/src/cpp/common/ntripBroadcast.hpp +++ b/src/cpp/common/ntripBroadcast.hpp @@ -1,6 +1,5 @@ -#ifndef NTRIPSSRBROADCASTER_H -#define NTRIPSSRBROADCASTER_H +#pragma once #include @@ -25,6 +24,8 @@ struct NtripUploader : NtripSocket, RtcmEncoder boost::asio::deadline_timer sendTimer; int numberChunksSent = 0; + GTime previousTargetTime; ///< Time to prevent aliasing + string ntripStr = ""; string id = "NtripUploader"; @@ -35,7 +36,14 @@ struct NtripUploader : NtripSocket, RtcmEncoder : NtripSocket(url_str), sendTimer(io_service) { - rtcmMountPoint = url.path; + if (url.path.empty()) + { + BOOST_LOG_TRIVIAL(error) << "Error: Ntrip uploader created with empty url"; + + return; + } + + rtcmMountpoint = url.path.substr(1); // remove '/' if (acsConfig.output_encoded_rtcm_json) { @@ -67,7 +75,7 @@ struct NtripUploader : NtripSocket, RtcmEncoder void connected() override; - void messageTimeout_hanlder( + void messageTimeout_handler( const boost::system::error_code& err); void write_handler( @@ -94,4 +102,3 @@ struct NtripBroadcaster extern NtripBroadcaster ntripBroadcaster; -#endif diff --git a/src/cpp/common/ntripSocket.cpp b/src/cpp/common/ntripSocket.cpp index 19b454bb7..93f228967 100644 --- a/src/cpp/common/ntripSocket.cpp +++ b/src/cpp/common/ntripSocket.cpp @@ -1,14 +1,26 @@ // #pragma GCC optimize ("O0") -#include "ntripSocket.hpp" +// #define BSONCXX_POLY_USE_MNMLSTC +// #define BSONCXX_POLY_USE_SYSTEM_MNMLSTC + +#include +#include #include -#include + +#include + + +#include "ntripSocket.hpp" +#include "acsConfig.hpp" + + +using std::chrono::system_clock; +using bsoncxx::builder::basic::kvp; namespace bp = boost::asio::placeholders; -//B_asio::ssl::context NtripSocket::ssl_context(ssl::context::sslv23_client); B_asio::io_service NtripSocket::io_service; @@ -24,24 +36,22 @@ void NtripSocket::logChunkError() message << numberErroredChunks; // message << ", ratio (error/total) : " << (double)numberErroredChunks /(double)(numberErroredChunks+numberValidChunks); + std::cout << message.str() << std::endl; messageChunkLog(message.str()); + + //todo aaron +// std::ofstream outStream(rtcmTraceFilename, std::ios::app); +// if (!outStream) +// { +// std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; +// return; +// } +// +// outStream << (GTime) timeGet(); +// outStream << " messageChunkLog" << message << std::endl; } -void NtripSocket::printChunkHex( - vector chunk) -{ - BOOST_LOG_TRIVIAL(debug) << "HTTP Chunk Data : "; - - for (int i = 0; i < chunk.size(); i++) - { - if (i % 10 == 0) - BOOST_LOG_TRIVIAL(debug) << std::endl; - - printf("%02x ",(unsigned char)chunk[i]); - } - BOOST_LOG_TRIVIAL(debug) << std::endl; -} void NtripSocket::start_read( @@ -117,154 +127,112 @@ void NtripSocket::read_handler_chunked( // If there is a problem with the chunking attempt is made to pass the message to the // RTCM parser. The RTCM parser has further error checking and may recover some messages. - vector chunk; - std::istream messStream(&downloadBuf); - unsigned int sz = downloadBuf.size(); + onChunkReceivedStatistics(); - char c_i; - char c_j; - unsigned int i = 0; +// std::istream messStream(&downloadBuf); +// unsigned int sz = downloadBuf.size(); + +// std::cout << " size" << downloadBuf.size() << std::endl; + int oldSize = receivedHttpData .size(); + int extraSize = downloadBuf .size(); - onChunkReceivedStatistics(); + receivedHttpData.resize(oldSize + extraSize); + auto destination = boost::asio::buffer(&receivedHttpData[oldSize], extraSize); + buffer_copy(destination, downloadBuf.data()); + downloadBuf.consume(extraSize); + int last = receivedHttpData.size(); + + int start = 0; + if (receivedHttpData.empty() == false) while (true) { - if (chunked_message_length == 0) + int endOfLength = 0; + int endOfHeader; + for (endOfHeader = start + 2; endOfHeader < last; endOfHeader++) { - chunk.clear(); - messStream.read(&c_i,1); - chunk.push_back(c_i); - for (i++; i < sz; i++) - { - messStream.read(&c_j,1); - chunk.push_back(c_j); - if ( c_i == '\r' - && c_j == '\n') - { - break; - } - c_i = c_j; - } - - if (i >= sz) - { - //BOOST_LOG_TRIVIAL(debug) << "\nEnd of Buffer Reached Searching for Message Header Chunk.\n"; - //BOOST_LOG_TRIVIAL(debug) << "downloadBuf.size() : " << downloadBuf.size() << std::endl; - //BOOST_LOG_TRIVIAL(debug) << "chunk.size() : " << chunk.size() << std::endl; - //printChunkHex(chunk); - std::ostream outStream(&downloadBuf); - outStream.write(&chunk[0],chunk.size()); - //BOOST_LOG_TRIVIAL(debug) << "messBuffer.size() : " << downloadBuf.size() << std::endl; - break; - } - - // Read the first chunk with the message length. + unsigned char c1 = receivedHttpData[endOfHeader - 1]; + unsigned char c2 = receivedHttpData[endOfHeader]; - // Put termination charater on string. - chunk.push_back(0); - string messStr(&chunk[0]); - messStr = messStr.substr(0, messStr.length()-2); - // NTRIP 2 allows for an extended header. - std::size_t ext = messStr.find(";"); - if (ext != string::npos) + if ( c1 == ';') { - //BOOST_LOG_TRIVIAL(debug) << "Found Extension in Message Length : " << messStr << std::endl; - messStr = messStr.substr(0,ext); + endOfLength = endOfHeader - 1; } - try + if ( c1 == '\r' + &&c2 == '\n') { - // Two is added for the termination charaters. - chunked_message_length = (unsigned int)std::stoi(messStr, 0, 16); - //BOOST_LOG_TRIVIAL(debug) << "\nValid Message Length Chunk Found.\n"; - //BOOST_LOG_TRIVIAL(debug) << "message chunk : " << messStr << std::endl; - //BOOST_LOG_TRIVIAL(debug) << "message_length : " << chunked_message_length << std::endl; - //BOOST_LOG_TRIVIAL(debug) << "chunk.size() : " << chunk.size() << std::endl; - //printChunkHex(chunk); - - - // Check if message is too long and set to zero. - if (chunked_message_length > 1000000) - { - //BOOST_LOG_TRIVIAL(warning) << "\nError Message Header, Body too Long.\n"; - //printChunkHex(chunk); - logChunkError(); - chunked_message_length = 0; - } - + break; } - catch (std::exception& e) - { - //BOOST_LOG_TRIVIAL(warning) << "\nError Message Header, string not an integer.\n"; - //BOOST_LOG_TRIVIAL(warning) << "chunk.size() : " << chunk.size() << std::endl; - //printChunkHex(chunk); - logChunkError(); - chunked_message_length = 0; - } } - else + + if (endOfHeader >= last) { - // Read the second chunk with the message. //todo aaron, roll into the first one and clean up - - // Buffer position for the end of the message body chunk. - int bodyPos = i+chunked_message_length+2; - - // There is not enough data to read the message body. - if (sz < bodyPos) - { - //BOOST_LOG_TRIVIAL(warning) << "\nBuffer sz : " << sz << std::endl; - //BOOST_LOG_TRIVIAL(warning) << "Message end pos : " << bodyPos << std::endl; - //BOOST_LOG_TRIVIAL(warning) << "Message buffer not large enough exiting.\n"; - break; - } - - // Copy message out of receive buffer. - chunk.clear(); - for (; i < bodyPos; i++) - { - messStream.read(&c_i,1); - chunk.push_back(c_i); - } - - // Check the last two characters are '\r' and '\n' to complete chunk. - if ( chunk[chunked_message_length] == '\r' - && chunk[chunked_message_length+1] == '\n') - { - // Remove the '\r\n' from the data vector. - chunk.pop_back(); - chunk.pop_back(); - - finishedReadingStream = dataChunkDownloaded(chunk); - if (finishedReadingStream) - { - disconnect(); - - return; - } - } - else - { - logChunkError(); - - /* - BOOST_LOG_TRIVIAL(warning) << "\nMissing Termination of Chunk Message.\n"; - BOOST_LOG_TRIVIAL(warning) << "message_length : " << message_length << std::endl; - BOOST_LOG_TRIVIAL(warning) << "chunk.size() : " << chunk.size() << std::endl; - printChunkHex(chunk); - BOOST_LOG_TRIVIAL(warning) << "chunk[message_length] : "; - printf("%02x\n",(unsigned char)chunk[message_length]); - BOOST_LOG_TRIVIAL(warning) << "chunk[message_length+1] : "; - printf("%02x\n",(unsigned char)chunk[message_length+1]); - */ - } - - //BOOST_LOG_TRIVIAL(debug) << "\nProcessed Chunk Body.\n"; - //BOOST_LOG_TRIVIAL(debug) << "chunk.size() : " << chunk.size() << std::endl; - chunked_message_length = 0; + break; } - } + + if (endOfLength == 0) + { + endOfLength = endOfHeader - 1; + } + + string hexLength(&receivedHttpData[start], &receivedHttpData[endOfLength]); +// std::cout << "\nhexLength: " << hexLength << "\n"; + + int messageLength; + try + { + messageLength = std::stoi(hexLength, 0, 16); + } + catch (std::exception& e) + { + BOOST_LOG_TRIVIAL(warning) << "\nError Message Header, string not an integer: " << hexLength; + logChunkError(); + start = endOfHeader; + continue; + } + + if (messageLength > 10000) + { + BOOST_LOG_TRIVIAL(warning) << "\nError Message Header, Body too Long: " << messageLength; + logChunkError(); + start = endOfHeader; + continue; + } + + if (endOfHeader + messageLength + 2 > receivedHttpData.size()) + { + //not enough data, continue from this start later + break; + } + + int startOfMessage = endOfHeader + 1; + int endOfMessage = startOfMessage + messageLength; + + char postAmble1 = receivedHttpData[endOfMessage]; + char postAmble2 = receivedHttpData[endOfMessage + 1]; + if ( postAmble1 != '\r' + ||postAmble2 != '\n') + { + BOOST_LOG_TRIVIAL(warning) << "\nMissing Termination of Chunk Message.\n"; + start = endOfHeader; + continue; + } +// printf("\npostamble: %02x %02x\n", postAmble1, postAmble2); + + vector chunk(&receivedHttpData[startOfMessage], &receivedHttpData[endOfMessage]); +// printHex(std::cout, chunk); + dataChunkDownloaded(chunk); + + start = endOfHeader + messageLength + 3; + } + if (start > 0) + { + receivedHttpData.erase(receivedHttpData.begin(), receivedHttpData.begin() + start - 1); + } + start_read(true); } @@ -311,11 +279,6 @@ void NtripSocket::delayed_reconnect() // If the network does not connect after 10 seconds print the HTTP request and receive. if (logHttpSentReceived == false) { -// auto curTime = boost::posix_time::from_time_t(system_clock::to_time_t(system_clock::now())); - -// boost::posix_time::time_duration totalTime = curTime - startTime; - -// if (totalTime.total_milliseconds() > (10.0*1000.0)) logHttpSentReceived = true; } } @@ -380,9 +343,9 @@ void NtripSocket::request_response_handler( if (logHttpSentReceived) { std::stringstream message; - message << "HTTP Sent :\n"; + message << "\nHTTP Sent : "; message << request_string; - message << "HTTP Received :\n"; + message << "\nHTTP Received : "; message << response_string; networkLog(message.str()); @@ -402,7 +365,6 @@ void NtripSocket::request_response_handler( //conneccted, turn the delay back down. reconnectDelay = 1; -// connectedTime = boost::posix_time::from_time_t(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); isConnected = true; if (disconnectionCount == 0) @@ -512,18 +474,14 @@ void NtripSocket::resolve_handler( //BOOST_LOG_TRIVIAL(debug) << "Resolve Completed.\n"; - // Attempt a connection to the first endpoint in the list. Each endpoint - // will be tried until we successfully establish a connection. + // Attempt a connection to the first endpoint in the list. Each endpoint will be tried until we successfully establish a connection. tcp::endpoint endpoint = *endpoint_iterator; socket_ptr->async_connect(endpoint, boost::bind(&NtripSocket::connect_handler, this, bp::error, ++endpoint_iterator)); } - void NtripSocket::connect() -{ - chunked_message_length = 0; - +{ // Pointers are required as objects may need to be destroyed to full recover // socket error. _socket = std::make_shared (io_service); @@ -560,9 +518,64 @@ void NtripSocket::disconnect() } - // Clear the buffers except receivedBuffer that could possibly retain - // valid RTCM messages. + // Clear the buffers except receivedBuffer that could possibly retain valid RTCM messages. request .consume(request .size()); downloadBuf .consume(downloadBuf.size()); } + +void NtripSocket::connectionError( + const boost::system::error_code& err, + string operation) +{ + if (acsConfig.output_ntrip_log == false) + return; + + std::ofstream logStream(networkTraceFilename, std::ofstream::app); + + if (!logStream) + { + BOOST_LOG_TRIVIAL(warning) << "Warning: Error opening log file.\n"; + return; + } + + GTime time = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("label", "connectionError")); + doc.append(kvp("Stream", url.path.substr(1,url.path.length()))); + doc.append(kvp("Time", time.to_string())); + doc.append(kvp("BoostSysErrCode", err.value())); + doc.append(kvp("BoostSysErrMess", err.message())); + doc.append(kvp("SocketOperation", operation)); + + logStream << bsoncxx::to_json(doc) << std::endl; +} + +void NtripSocket::serverResponse( + unsigned int status_code, + string http_version) +{ + if (acsConfig.output_ntrip_log == false) + return; + + std::ofstream logStream(networkTraceFilename, std::ofstream::app); + + if (!logStream) + { + BOOST_LOG_TRIVIAL(warning) << "Warning: Error opening log file.\n"; + return; + } + + GTime time = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("label", "serverResponse")); + doc.append(kvp("Stream", url.path.substr(1,url.path.length()))); + doc.append(kvp("Time", time.to_string())); + doc.append(kvp("ServerStatus", (int)status_code)); + doc.append(kvp("VersionHTTP", http_version)); + + logStream << bsoncxx::to_json(doc) << std::endl; +} + diff --git a/src/cpp/common/ntripSocket.hpp b/src/cpp/common/ntripSocket.hpp index 1dc996c73..11544faca 100644 --- a/src/cpp/common/ntripSocket.hpp +++ b/src/cpp/common/ntripSocket.hpp @@ -1,15 +1,12 @@ -#ifndef NTRIPSOCKET_H -#define NTRIPSOCKET_H + +#pragma once #include #include #include -#include using std::string; using std::vector; -using std::chrono::system_clock; -using std::chrono::time_point; #include #include @@ -50,13 +47,11 @@ using tcp = ip::tcp; using error_code = boost::system::error_code; using ssl_socket = ssl::stream; -using namespace boost::system; - #define ERROR_OUTPUT_RECONNECT_AND_RETURN \ { \ onErrorStatistics(err, __FUNCTION__); \ - BOOST_LOG_TRIVIAL(error) << "Error: " << err.message() << "\n in " << __FUNCTION__ << " for " << url.sanitised() << "\n"; \ + BOOST_LOG_TRIVIAL(error) << "Error: " << err.message() << " in " << __FUNCTION__ << " for " << url.sanitised() << "\n"; \ \ if (err != boost::asio::error::operation_aborted) \ delayed_reconnect(); \ @@ -198,6 +193,8 @@ struct NtripSocket : NetworkStatistics boost::asio::streambuf request; boost::asio::streambuf downloadBuf; + + vector receivedHttpData; public: URL url; @@ -206,9 +203,6 @@ struct NtripSocket : NetworkStatistics int disconnectionCount = 0; bool isConnected = false; - - bool finishedReadingStream = false; - unsigned int chunked_message_length = 0; int numberErroredChunks = 0; bool logHttpSentReceived = false; @@ -252,15 +246,13 @@ struct NtripSocket : NetworkStatistics void read_handler_chunked (const boost::system::error_code& err); public: - void logChunkError(); - void printChunkHex(vector chunk); + void logChunkError(); //content from a stream has been received - process it in virtual functions from other classes - virtual bool dataChunkDownloaded( - vector dataChunk) + virtual void dataChunkDownloaded( + vector& dataChunk) { - return false; } //content from a one-shot request has been received - process it in virtual functions from other classes @@ -288,18 +280,12 @@ struct NtripSocket : NetworkStatistics } virtual void connectionError( - const boost::system::error_code& err, - string operation) - { - - } + const boost::system::error_code& err, + string operation); virtual void serverResponse( - unsigned int status_code, - string http_version) - { - - } + unsigned int status_code, + string http_version); B_asio::ssl::context ssl_context; @@ -316,4 +302,3 @@ struct NtripSocket : NetworkStatistics } }; -#endif diff --git a/src/cpp/common/ntripTrace.cpp b/src/cpp/common/ntripTrace.cpp index 3a6f2c882..225a60647 100644 --- a/src/cpp/common/ntripTrace.cpp +++ b/src/cpp/common/ntripTrace.cpp @@ -1,15 +1,21 @@ +// #pragma GCC optimize ("O0") + #include #include using bsoncxx::builder::basic::kvp; +using bsoncxx::types::b_date; +#include #include +using std::chrono::system_clock; +using std::chrono::time_point; using std::string; -#include "acsStream.hpp" +#include "ntripTrace.hpp" #include "acsConfig.hpp" #include "common.hpp" @@ -33,12 +39,12 @@ void NetworkStatistics::onErrorStatistics( connectCount++; bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("StreamName", streamName )); - doc.append(kvp("MessageType", "Error" )); - doc.append(kvp("BoostSysErrCode", err.value() )); - doc.append(kvp("Error", err.message() )); - doc.append(kvp("SocketOperation", operation )); - doc.append(kvp("Time", bsoncxx::types::b_date {std::chrono::system_clock::now()} )); + doc.append(kvp("StreamName", streamName )); + doc.append(kvp("MessageType", "Error" )); + doc.append(kvp("BoostSysErrCode", err.value() )); + doc.append(kvp("Error", err.message() )); + doc.append(kvp("SocketOperation", operation )); + doc.append(kvp("Time", b_date {std::chrono::system_clock::now()} )); fout << bsoncxx::to_json(doc) << std::endl; } @@ -60,11 +66,11 @@ void NetworkStatistics::onConnectedStatistics() connectCount++; bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("StreamName", streamName )); - doc.append(kvp("MessageType", "Connected" )); - doc.append(kvp("Time", bsoncxx::types::b_date {std::chrono::system_clock::now()} )); - doc.append(kvp("ConnectCount", connectCount )); - doc.append(kvp("DisonnectCount", disconnectCount )); + doc.append(kvp("StreamName", streamName )); + doc.append(kvp("MessageType", "Connected" )); + doc.append(kvp("Time", b_date {std::chrono::system_clock::now()} )); + doc.append(kvp("ConnectCount", connectCount )); + doc.append(kvp("DisonnectCount", disconnectCount )); fout << bsoncxx::to_json(doc) << std::endl; } @@ -86,11 +92,11 @@ void NetworkStatistics::onDisconnectedStatistics() disconnectCount++; bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("StreamName", streamName )); - doc.append(kvp("MessageType", "Disconnected" )); - doc.append(kvp("Time", bsoncxx::types::b_date {std::chrono::system_clock::now()} )); - doc.append(kvp("ConnectCount", connectCount )); - doc.append(kvp("DisonnectCount", disconnectCount )); + doc.append(kvp("StreamName", streamName )); + doc.append(kvp("MessageType", "Disconnected" )); + doc.append(kvp("Time", b_date {std::chrono::system_clock::now()} )); + doc.append(kvp("ConnectCount", connectCount )); + doc.append(kvp("DisonnectCount", disconnectCount )); fout << bsoncxx::to_json(doc) << std::endl; } @@ -112,10 +118,10 @@ void NetworkStatistics::onChunkSentStatistics() chunksSent++; bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("StreamName", streamName )); - doc.append(kvp("MessageType", "ChunkSent" )); - doc.append(kvp("Time", bsoncxx::types::b_date {std::chrono::system_clock::now()} )); - doc.append(kvp("ChunksSent", chunksSent )); + doc.append(kvp("StreamName", streamName )); + doc.append(kvp("MessageType", "ChunkSent" )); + doc.append(kvp("Time", b_date {std::chrono::system_clock::now()} )); + doc.append(kvp("ChunksSent", chunksSent )); fout << bsoncxx::to_json(doc) << std::endl; } @@ -140,272 +146,10 @@ void NetworkStatistics::onChunkReceivedStatistics() chunksReceived++; bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("StreamName", streamName )); - doc.append(kvp("MessageType", "ChunkReceived" )); - doc.append(kvp("Time", bsoncxx::types::b_date {std::chrono::system_clock::now()} )); - doc.append(kvp("ChunksReceived", chunksReceived )); - - fout << bsoncxx::to_json(doc) << std::endl; -} - -void RtcmTrace::outputSsrEphToJson( - const SSREph& ssrEph, - const SatSys& Sat) -{ - if (rtcmTraceFilename.empty()) - { - return; - } - - std::ofstream fout(rtcmTraceFilename, std::ios::app); - if (!fout) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("MountPoint", rtcmMountPoint )); - doc.append(kvp("MessageType", "Orbit Correction" )); - doc.append(kvp("EpochTimeGreg", ssrEph.t0.to_string(1) )); - doc.append(kvp("EpochTime1s", ssrEph.ssrMeta.epochTime1s )); - doc.append(kvp("SSRUpdateIntervalInd", ssrEph.ssrMeta.ssrUpdateIntIndex )); - doc.append(kvp("SSRUpdateIntervalSec", ssrEph.udi )); - doc.append(kvp("MultipleMessageIndicator", ssrEph.ssrMeta.multipleMessage )); - doc.append(kvp("SatelliteReferenceDatum", (int) ssrEph.ssrMeta.referenceDatum )); // 0 = ITRF, 1 = Regional // bsoncxx doesn't like uints - doc.append(kvp("IODSSR", ssrEph.iod )); - doc.append(kvp("IODCRC", ssrEph.iodcrc )); - doc.append(kvp("SSRProviderID", (int) ssrEph.ssrMeta.provider )); - doc.append(kvp("SSRSolutionID", (int) ssrEph.ssrMeta.solution )); - doc.append(kvp("SatelliteID", Sat.id() )); - doc.append(kvp("IODE", ssrEph.iode )); - doc.append(kvp("DeltaRadial", ssrEph.deph[0] )); - doc.append(kvp("DeltaAlongTrack", ssrEph.deph[1] )); - doc.append(kvp("DeltaCrossTrack", ssrEph.deph[2] )); - doc.append(kvp("DotDeltaRadial", ssrEph.ddeph[0] )); - doc.append(kvp("DotDeltaAlongTrack", ssrEph.ddeph[1] )); - doc.append(kvp("DotDeltaCrossTrack", ssrEph.ddeph[2] )); - - fout << bsoncxx::to_json(doc) << std::endl; -} - - -void RtcmTrace::outputSsrClkToJson( - const SSRClk& ssrClk, - const SatSys& Sat) -{ - if (rtcmTraceFilename.empty()) - { - return; - } - - std::ofstream fout(rtcmTraceFilename, std::ios::app); - if (!fout) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("MountPoint", rtcmMountPoint )); - doc.append(kvp("MessageType", "Clock Correction" )); - doc.append(kvp("EpochTimeGreg", ssrClk.t0.to_string(1) )); - doc.append(kvp("EpochTime1s", ssrClk.ssrMeta.epochTime1s )); - doc.append(kvp("SSRUpdateIntervalInd", ssrClk.ssrMeta.ssrUpdateIntIndex )); - doc.append(kvp("SSRUpdateIntervalSec", ssrClk.udi )); - doc.append(kvp("MultipleMessageIndicator", ssrClk.ssrMeta.multipleMessage )); - doc.append(kvp("SatelliteReferenceDatum", (int) ssrClk.ssrMeta.referenceDatum )); // 0 = ITRF, 1 = Regional - doc.append(kvp("IODSSR", ssrClk.iod )); - doc.append(kvp("SSRProviderID", (int) ssrClk.ssrMeta.provider )); - doc.append(kvp("SSRSolutionID", (int) ssrClk.ssrMeta.solution )); - doc.append(kvp("SatelliteID", Sat.id() )); - doc.append(kvp("DeltaClockC0", ssrClk.dclk[0] )); - doc.append(kvp("DeltaClockC1", ssrClk.dclk[1] )); - doc.append(kvp("DeltaClockC2", ssrClk.dclk[2] )); - - fout << bsoncxx::to_json(doc) << std::endl; -} - - -void RtcmTrace::traceSsrCodeB( - SatSys Sat, - E_ObsCode code, - SSRBias& ssrBias) -{ - if (rtcmTraceFilename.empty()) - { - return; - } - - std::ofstream fout(rtcmTraceFilename, std::ios::app); - if (!fout) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - double ep[6]; - int yds[3]; - - time2epoch(ssrBias.t0, ep); - epoch2yds(ep, yds); - - bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("MountPoint", rtcmMountPoint )); - doc.append(kvp("MessageType", "CodeBias" )); - doc.append(kvp("Sat", Sat.id() )); - doc.append(kvp("Code", code._to_string() )); - doc.append(kvp("Year", yds[0] )); - doc.append(kvp("Day", yds[1] )); - doc.append(kvp("Second", yds[2] )); - doc.append(kvp("Bias", ssrBias.obsCodeBiasMap[code].bias )); - - fout << bsoncxx::to_json(doc) << std::endl; -} - -void RtcmTrace::traceSsrPhasB( - SatSys Sat, - E_ObsCode code, - SSRBias& ssrBias) -{ - if (rtcmTraceFilename.empty()) - { - return; - } - - std::ofstream fout(rtcmTraceFilename, std::ios::app); - if (!fout) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - double ep[6]; - int yds[3]; - - time2epoch(ssrBias.t0, ep); - epoch2yds(ep, yds); - - bsoncxx::builder::basic::document doc = {}; - doc.append(kvp("MountPoint", rtcmMountPoint )); - doc.append(kvp("MessageType", "PhaseBias" )); - doc.append(kvp("Sat", Sat.id() )); - doc.append(kvp("Code", code._to_string() )); - doc.append(kvp("Year", yds[0] )); - doc.append(kvp("Day", yds[1] )); - doc.append(kvp("Second", yds[2] )); - doc.append(kvp("Bias", ssrBias.obsCodeBiasMap[code].bias )); - - fout << bsoncxx::to_json(doc) << std::endl; -} - -void RtcmTrace::traceBroEph( - Eph& eph, - E_Sys sys) -{ - if (rtcmTraceFilename.empty()) - { - return; - } - - std::ofstream fout(rtcmTraceFilename, std::ios::app); - if (!fout) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - double ep[6]; - time2epoch(eph.toc, ep); - - bsoncxx::builder::basic::document doc = {}; - //Note the Satellite id is not set in rinex correctly as we a mixing GNSS systems. - doc.append(kvp("Sat", eph.Sat.id() )); - doc.append(kvp("ep[0]", (int)ep[0] )); - doc.append(kvp("ep[0]", (int)ep[0] )); - doc.append(kvp("ep[1]", (int)ep[1] )); - doc.append(kvp("ep[2]", (int)ep[2] )); - doc.append(kvp("ep[3]", (int)ep[3] )); - doc.append(kvp("ep[4]", (int)ep[4] )); - doc.append(kvp("ep[5]", (int)ep[5] )); - doc.append(kvp("f0", eph.f0 )); - doc.append(kvp("f1", eph.f1 )); - doc.append(kvp("f2", eph.f2 )); - - doc.append(kvp("", eph.iode )); - doc.append(kvp("", eph.crs )); - doc.append(kvp("", eph.deln )); - doc.append(kvp("", eph.M0 )); - doc.append(kvp("cuc", eph.cuc )); - doc.append(kvp("e", eph.e )); - doc.append(kvp("cus", eph.cus )); - doc.append(kvp("A", SQRT(eph.A) )); - doc.append(kvp("toes", eph.toes )); - doc.append(kvp("cic", eph.cic )); - doc.append(kvp("OMG0", eph.OMG0 )); - doc.append(kvp("cis", eph.cis )); - doc.append(kvp("i0", eph.i0 )); - doc.append(kvp("crc", eph.crc )); - doc.append(kvp("omg", eph.omg )); - doc.append(kvp("OMGd", eph.OMGd )); - doc.append(kvp("idot", eph.idot )); - doc.append(kvp("code", eph.code )); - doc.append(kvp("week", eph.week )); - doc.append(kvp("flag", eph.flag )); - - if (sys == +E_Sys::GPS ) - { - // https://cddis.nasa.gov/archive/gnss/data/daily/2021/102/21n/ - /* - GLOBAL POSITIONING SYSTEM - STANDARD POSITIONING SERVICE - SIGNAL SPECIFICATION - 2nd Ed, June 2,1995 - see section - 2.5.3 User Range Accuracy - */ - double ura = 0; - if (eph.sva <= 6) - { - ura = 10*pow(2, 1+((double)eph.sva/2.0)); - ura = round(ura)/10.0; - } - else if ( eph.sva != 15 ) - ura = pow(2,(double)eph.sva-2.0); - else - ura = -1; - - doc.append(kvp("ura", ura )); - doc.append(kvp("svh", eph.svh )); - doc.append(kvp("tgd[0]", eph.tgd[0] )); - doc.append(kvp("iodc", eph.iodc )); - doc.append(kvp("tow", time2gpst(eph.ttm,&eph.week))); - doc.append(kvp("fit", eph.fit )); - } - else if (sys == +E_Sys::GAL) - { - // https://cddis.nasa.gov/archive/gnss/data/daily/2021/102/21l/ - - /* - EUROPEAN GNSS (GALILEO) OPEN SERVICE - SIGNAL-IN-SPACE - INTERFACE CONTROL - DOCUMENT - Issue 2.0, January 2021 - See Section, 5.1.12. Signal – In – Space Accuracy (SISA) - */ - double SISA; - if ( eph.sva <= 49 ) SISA = 0.0+(eph.sva-0) * 0.01; - else if ( eph.sva <= 74 ) SISA = 0.5+(eph.sva-50) * 0.02; - else if ( eph.sva <= 99 ) SISA = 1.0+(eph.sva-75) * 0.04; - else if ( eph.sva <= 125 ) SISA = 2.0+(eph.sva-100)* 0.16; - else SISA = -1; - - doc.append(kvp("SISA", SISA )); - doc.append(kvp("svh", eph.svh )); - doc.append(kvp("tgd[0]", eph.tgd[0] )); - doc.append(kvp("tgd[1]", eph.tgd[1] )); - doc.append(kvp("tow", time2gpst(eph.ttm,&eph.week))); - } + doc.append(kvp("StreamName", streamName )); + doc.append(kvp("MessageType", "ChunkReceived" )); + doc.append(kvp("Time", b_date {std::chrono::system_clock::now()} )); + doc.append(kvp("ChunksReceived", chunksReceived )); fout << bsoncxx::to_json(doc) << std::endl; } @@ -425,8 +169,7 @@ string NetworkStatistics::getNetworkStatistics( doc.append(kvp("Network", acsConfig.analysis_agency)); doc.append(kvp("Downloading", true)); - auto timeNow = boost::posix_time::from_time_t(system_clock::to_time_t(system_clock::now())); - boost::posix_time::time_duration totalTime = timeNow - boost::posix_time::from_time_t(startTime.time); + double totalTime = ((GTime)timeGet() - startTime).to_double(); // double connRatio; // if (disconnectionCount == 0 @@ -470,9 +213,7 @@ string NetworkStatistics::getNetworkStatistics( // traceStr << "Start : " << std::put_time(std::localtime(&startTime.time), "%F %X") << std::endl; // traceStr << "Finish : " << std::put_time(std::localtime(&endTime.time), "%F %X") << std::endl; // -// auto timeNow = boost::posix_time::from_time_t(system_clock::to_time_t(system_clock::now())); -// boost::posix_time::time_duration totalTime = timeNow - boost::posix_time::from_time_t(startTime.time); -// +// double totalTime = (GTime)timeGet() - startTime; // // double connRatio; // if (disconnectionCount == 0 @@ -517,39 +258,4 @@ string NetworkStatistics::getNetworkStatistics( // tracepde(0, trace, (messLine + "\n").c_str()); // } -void RtcmStatistics::printRtcmStatistics( - Trace& trace) -{ - std::stringstream traceStr; -// traceStr << "Start : " << std::put_time(std::localtime(&startTime.time), "%F %X") << std::endl; -// traceStr << "Finish : " << std::put_time(std::localtime(&endTime.time), "%F %X") << std::endl; - -// auto timeNow = boost::posix_time::from_time_t(system_clock::to_time_t(system_clock::now())); -// boost::posix_time::time_duration totalTime = timeNow - boost::posix_time::from_time_t(startTime.time); - - - traceStr << "RtcmExtraBytes : " << numNonMessBytes << std::endl; - traceStr << "RtcmFailCrc : " << numFramesFailedCRC << std::endl; - traceStr << "RtcmPassedCrc : " << numFramesPassCRC << std::endl; - traceStr << "RtcmDecoded : " << numFramesDecoded << std::endl; - traceStr << "RtcmPreamble : " << numPreambleFound << std::endl; - - double FailedToPreambleRatio = 0; - if (numPreambleFound != 0) - FailedToPreambleRatio = (double)numFramesFailedCRC / (double)numPreambleFound; - traceStr << "RtcmFailedCrcToPreambleRatio : " << FailedToPreambleRatio << std::endl; - if (numMessagesLatency != 0) - { - double meanLatency = totalLatency / numMessagesLatency; - traceStr << "meanLatency : " << meanLatency << std::endl; - } - else - { - traceStr << "meanLatency : " << 0.0 << std::endl; - } - - string messLine; - while (std::getline(traceStr, messLine)) - tracepdeex(0, trace, (messLine + "\n").c_str()); -} diff --git a/src/cpp/common/ntripTrace.hpp b/src/cpp/common/ntripTrace.hpp index 22af785af..c8df70782 100644 --- a/src/cpp/common/ntripTrace.hpp +++ b/src/cpp/common/ntripTrace.hpp @@ -49,116 +49,5 @@ struct NetworkStatistics string operation); }; -struct RtcmStatistics -{ - long int numPreambleFound = 0; - long int numFramesFailedCRC = 0; - long int numFramesPassCRC = 0; - long int numFramesDecoded = 0; - long int numNonMessBytes = 0; - long int numMessagesLatency = 0; - double totalLatency = 0; - - void printRtcmStatistics( - Trace& trace); -}; - -struct RtcmTrace -{ - string rtcmTraceFilename = ""; - string rtcmMountPoint; - - RtcmTrace( - string mountpoint = "", - string filename = "") : rtcmTraceFilename{filename}, rtcmMountPoint{mountpoint} - { - } - - void networkLog( - string message) - { - std::ofstream outStream(rtcmTraceFilename, std::ios::app); - if (!outStream) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - outStream << boost::posix_time::from_time_t(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); - outStream << " networkLog" << message << std::endl; - } - - void messageChunkLog( - string message) - { - std::ofstream outStream(rtcmTraceFilename, std::ios::app); - if (!outStream) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - outStream << boost::posix_time::from_time_t(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); - outStream << " messageChunkLog" << message << std::endl; - } - - void messageRtcmLog( - string message) - { - std::ofstream outStream(rtcmTraceFilename, std::ios::app); - if (!outStream) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - outStream << boost::posix_time::from_time_t(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); - outStream << " messageRtcmLog" << message << std::endl; - } - - void messageRtcmByteLog( - string message) - { - std::ofstream outStream(rtcmTraceFilename, std::ios::app); - if (!outStream) - { - std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; - return; - } - - outStream << boost::posix_time::from_time_t(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); - outStream << " messageRtcmByteLog" << message << std::endl; - } - - void outputSsrEphToJson( - const SSREph& ssrEph, - const SatSys& Sat); - - void outputSsrClkToJson( - const SSRClk& ssrClk, - const SatSys& Sat); - - void traceSsrEph( - SatSys Sat, - SSREph& ssrEph); - - void traceSsrClk( - SatSys Sat, - SSRClk& ssrClk); - - void traceSsrCodeB( - SatSys Sat, - E_ObsCode mode, - SSRBias& ssrBias); - - void traceSsrPhasB( - SatSys Sat, - E_ObsCode mode, - SSRBias& ssrBias); - - void traceBroEph( - Eph& eph, - E_Sys sys); -}; #endif diff --git a/src/cpp/common/observations.hpp b/src/cpp/common/observations.hpp index b6e2b31a8..d171c9567 100644 --- a/src/cpp/common/observations.hpp +++ b/src/cpp/common/observations.hpp @@ -1,21 +1,47 @@ -#ifndef __OBSERVATIONS_HPP_ -#define __OBSERVATIONS_HPP_ +#pragma once + +#include #include #include #include #include +using std::make_shared; +using std::shared_ptr; using std::vector; using std::string; using std::list; using std::map; +#include "eigenIncluder.hpp" +#include "algebra.hpp" #include "satSys.hpp" #include "gTime.hpp" #include "enums.h" +#include "crd.h" + + -#include "eigenIncluder.hpp" + +struct GObs; +struct PObs; +struct FObs; +struct LObs; + +struct Observation +{ + GTime time = {}; ///> Receiver sampling time (GPST) + string mount = ""; ///< ID of the receiver that generated the observation + + virtual ~Observation() = default; + +protected: + GObs* gObs_ptr = nullptr; + PObs* pObs_ptr = nullptr; + FObs* fObs_ptr = nullptr; + LObs* lObs_ptr = nullptr; +}; /** Raw observation data from a receiver for a single frequency. Not to be modified by processing functions */ @@ -25,9 +51,11 @@ struct RawSig double L = 0; ///< Carrier phase (cycles) double P = 0; ///< Pseudorange (meters) double D = 0; ///< Doppler - unsigned char LLI = 0; ///< Loss of lock indicator - double snr = 0; ///< Signal to Noise ratio + bool LLI = false; ///< Loss of lock indicator + double snr = 0; ///< Signal to Noise ratio (dB-Hz) + bool invalid = false; + bool operator < (const RawSig& b) const { return (code < b.code); @@ -62,18 +90,14 @@ struct Sig : RawSig double biases[NUM_MEAS_TYPES] = {std::nan("")}; }; -/** Raw observation data from a receiver. Not to be modified by processing functions -*/ -struct RawObs -{ - GTime time = {}; ///> Receiver sampling time (GPST) - SatSys Sat = {}; ///> Satellite ID (system, prn) - map Sigs; ///> Map of signals available in this observation (one per frequency only) - map> SigsLists; ///> Map of all signals available in this observation (may include multiple per frequency, eg L1X, L1C) -}; -#define MAX_LAYER_NUM 4 +struct IonoPP +{ + double lat = 0; + double lon = 0; + double ang = 0; +}; struct IonoObs { @@ -86,11 +110,10 @@ struct IonoObs int STECtype; double STECsmth; double STECsmvr; + int STECcodeComb; - double latIPP[MAX_LAYER_NUM]; - double lonIPP[MAX_LAYER_NUM]; - double angIPP[MAX_LAYER_NUM]; - + map ippMap; + union { unsigned int ionExclude; @@ -108,40 +131,31 @@ struct IonoObs struct SatStat; struct SatNav; struct SatOrbit; +struct Station; + -/** Observation, and data derived from it. + +/** Observation metadata and data derived from it. * All processing relevant for a single rec:sat:epoch should be stored here. * For data that should persist across epochs: use SatStat. **/ -struct Obs : RawObs, IonoObs +struct GObsMeta : IonoObs { - Obs() : exclude(0) + GObsMeta() : exclude(0) { } - - Obs(RawObs raw) : RawObs(raw), exclude(0) - { - - } - - Vector3d rSat = Vector3d::Zero(); ///< ECEF based vector to satellite - Vector3d satVel = Vector3d::Zero(); ///< ECEF based vector of satellite velocity - double ephVar = 0; ///< Variance of ephemeris derived values - SatStat* satStat_ptr = 0; ///< Pointer to a status object for this satellite - SatNav* satNav_ptr = 0; ///< Pointer to a navigation object for this satellite + Station* rec_ptr = nullptr; - string mount = ""; ///< ID of the receiver that generated the observation - double dtSat[2] = {}; ///< Clock bias of the satellite - E_Svh svh = SVH_OK; ///< Satellite vehicle health - int iode = 0; ///< Issue of data ephemeris double rescode_v = 0; ///< Residuals of code - bool vsat = 0; ///< Valid satellite flag + double tropSlant = 0; ///< Troposphere slant delay + double tropSlantVar = 0; ///< Troposphere slant delay variance + union { - unsigned int exclude; + const unsigned int exclude = 0; struct { unsigned excludeElevation : 1; @@ -153,21 +167,286 @@ struct Obs : RawObs, IonoObs unsigned excludeBadSPP : 1; unsigned excludeConfig : 1; unsigned excludeSVH : 1; + unsigned excludeBadRange : 1; }; }; }; +/** Satellite position data - for determining and storing satellite positions/clocks +*/ +struct SatPos +{ + SatPos() : failure(0) + { + + } + + SatSys Sat = {}; ///> Satellite ID (system, prn) + SatNav* satNav_ptr = 0; ///< Pointer to a navigation object for this satellite + SatStat* satStat_ptr = 0; ///< Pointer to a status object for this satellite + + E_Source posSource = E_Source::NONE; + E_Source clkSource = E_Source::NONE; + + VectorEcef rSat; ///< ECEF based vector of satellite + VectorEcef satVel; ///< ECEF based vector of satellite velocity + VectorEci rSatEciDt; ///< ECI based vector of satellite at transmission time + VectorEci vSatEciDt; ///< ECI based vector of satellite velocity at transmission time + VectorEci rSatEci0; ///< ECI based vector of satellite at nominal epoch + VectorEci vSatEci0; ///< ECI based vector of satellite velocity at nominal epoch + + double posVar = 0; ///< Variance of ephemeris derived values + + double satClk = 0; + double satClkVel = 0; + double satClkVar = 0; + + int iodeClk = 0; ///< Issue of data ephemeris + int iodePos = 0; ///< Issue of data ephemeris + bool ephPosValid = false; + bool ephClkValid = false; + bool vsat = 0; ///< Valid satellite flag + + double tof = 0; ///< Estimated time of flight + + union + { + const unsigned int failure = 0; + struct + { + unsigned failureExclude : 1; + unsigned failureNoSatPos : 1; + unsigned failureNoSatClock : 1; + unsigned failureNoPseudorange : 1; + unsigned failureIodeConsistency : 1; + unsigned failureBroadcastEph : 1; + unsigned failureSeleph : 1; + unsigned failureSSRFail : 1; + unsigned failureSsrPosEmpty : 1; + unsigned failureSsrClkEmpty : 1; + unsigned failureSsrPosTime : 1; + unsigned failureSsrClkTime : 1; + unsigned failureSsrPosMag : 1; + unsigned failureSsrClkMag : 1; + unsigned failureSsrPosUdi : 1; + unsigned failureSsrClkUdi : 1; + unsigned failureGeodist : 1; + unsigned failureElevation : 1; + unsigned failureSatexclude : 1; + unsigned failurePrange : 1; + unsigned failureIonocorr : 1; + unsigned failureTropcorr : 1; + }; + }; +}; -struct PseudoObs +/** Raw observation data from a receiver. Not to be modified by processing functions +*/ +struct GObs : Observation, GObsMeta, SatPos +{ + map Sigs; ///> Map of signals available in this observation (one per frequency only) + map> SigsLists; ///> Map of all signals available in this observation (may include multiple per frequency, eg L1X, L1C) + + operator shared_ptr() + { + auto pointer = make_shared(*this); + + pointer->gObs_ptr = pointer.get(); + + return pointer; + } + + virtual ~GObs() = default; +}; + +struct PObs : Observation { - GTime time = {}; ///> Receiver sampling time (GPST) SatSys Sat = {}; ///> Satellite ID (system, prn) Vector3d pos = Vector3d::Zero(); Vector3d vel = Vector3d::Zero(); + + operator shared_ptr() + { + auto pointer = make_shared(*this); + + pointer->pObs_ptr = pointer.get(); + + return pointer; + } + + virtual ~PObs() = default; +}; + +struct FObs : Observation +{ + KFState obsState; + + operator shared_ptr() + { + auto pointer = make_shared(*this); + + pointer->fObs_ptr = pointer.get(); + + return pointer; + } + + virtual ~FObs() = default; +}; + + +typedef vector> ObsList; ///< List of observations for an epoch + + +//======================================================================================================== +/* +#Mission Name SP3c Code ILRS ID NORAD Altitude [km] Inclination [deg] Tracking Status +# (PRN) From To + GPS-MET L02 9501703 23547 740 740 69.900 Off +*/ +//======================================================================================================== +struct SatIdentity +{ + string satName; // Mission Name + string satId; // SP3c Code (PRN) + int ilrsId; // ILRS ID + int noradId; // NORAD + double altitude[2]; // [km], 0: min, 1: max + double inclination; // [deg] + bool tracking; // Tracking Status }; -typedef vector ObsList; ///< List of observations for an epoch -typedef vector PseudoObsList; ///< List of observations for an epoch +void readSatId(string filepath); + +extern map satIdMap;// index by ILRS ID + +/** SLR normal point data from a session within a CRD file +*/ +struct CrdSession +{ + CrdH1 h1; + CrdH2 h2; + CrdH3 h3; + CrdH4 h4; + CrdH5 h5; + CrdC0 c0; + CrdC1 c1; + CrdC2 c2; + CrdC3 c3; + CrdC4 c4; + CrdC5 c5; + CrdC6 c6; + CrdC7 c7; + vector d10; + vector d11; + vector d12; + vector d20; + vector d21; + vector d30; + vector d40; + vector d41; + vector d42; + vector d50; + vector d60; + vector d00; + + union + { + unsigned int read = 0; + struct + { + unsigned readH1 : 1; + unsigned readH2 : 1; + unsigned readH3 : 1; + unsigned readH4 : 1; + unsigned readH5 : 1; + unsigned readC0 : 1; + unsigned readC1 : 1; + unsigned readC2 : 1; + unsigned readC3 : 1; + unsigned readC4 : 1; + unsigned readC5 : 1; + unsigned readC6 : 1; + unsigned readC7 : 1; + }; + }; +}; + + +vector readCrdFile(string filepath); + +//forward declarations for pointers below +struct SatStat; +struct SatNav; + +struct LObsMeta +{ + // Rec data + string recName = {}; + int recCdpId = 0; + + // Sat data + string satName = {}; + int ilrsId = 0; + int noradId = 0; + string cosparId = {}; +}; + +struct LObs : Observation, LObsMeta, SatPos +{ + // Obs data + E_CrdEpochEvent epochEvent = E_CrdEpochEvent::NONE; + GTime timeTx = {}; + double twoWayTimeOfFlight = 0; + + union + { + const unsigned int exclude = 0; + struct + { + unsigned excludeElevation : 1; + unsigned excludeBias : 1; + unsigned excludeEccentricity : 1; + unsigned excludeSinexPos : 1; + unsigned excludeSinex : 1; + unsigned excludeTime : 1; + unsigned excludeMeta : 1; + unsigned excludeEphemeris : 1; + unsigned excludeBadFlags : 1; + unsigned excludeAlert : 1; + }; + }; + double pressure = 0; //hPa (mbar) + double temperature = 0; //K + double humidity = 0; //0.00-1.00 + double wavelength = 0; //nm + double ephVar = 0; + + operator shared_ptr() + { + auto pointer = make_shared(*this); + + pointer->lObs_ptr = pointer.get(); + + return pointer; + } + + virtual ~LObs() = default; +}; + +typedef map>> SlrSiteObsMap; // indexed by Station ID + +extern SlrSiteObsMap slrSiteObsMap; + +void readCrd( + string filepath); + +void outputSortedSlrObsPerRec( + string filepath, + ObsList& slrObsList); + +vector outputSortedSlrObs(); +int readSlrObs( + std::istream& inputStream, + ObsList& slrObsList); -#endif diff --git a/src/cpp/common/orbex.cpp b/src/cpp/common/orbex.cpp new file mode 100644 index 000000000..8f4d50309 --- /dev/null +++ b/src/cpp/common/orbex.cpp @@ -0,0 +1,369 @@ + +#include +#include + +using std::string; +using std::ifstream; +using std::ofstream; + +#include +#include + +#include "eigenIncluder.hpp" +#include "navigation.hpp" +#include "common.hpp" +#include "gTime.hpp" +#include "enums.h" + + +/** Satellite code to satellite system +*/ +E_Sys code2sys(char code); + +/** Read and check the two header lines from an orbex file +*/ +int readOrbexHeader( + ifstream& fileStream, ///< Stream to read content from + double& ver) ///< ORBEX version +{ + ver = 0; + + string line; + + // first header line + std::getline(fileStream, line); + + if (fileStream.eof()) + { + BOOST_LOG_TRIVIAL(error) << "Empty file" << std::endl; + return 1; + } + + // verify document type + if (line.substr(0, 7) != "%=ORBEX") + { + BOOST_LOG_TRIVIAL(error) << "Not an Orbex file" << std::endl; + return 2; + } + + char* buff = &line[0]; + ver = str2num(buff, 8, 5); + + // second header line + std::getline(fileStream, line); + + if (line.substr(0, 2) != "%%") + { + BOOST_LOG_TRIVIAL(error) << "Incorrect format" << std::endl; + return 3; + } + + return 0; +} + +/** Read necessary information, e.g. time system & frame type, from the FILE/DESCRIPTION block +*/ +bool readOrbexFileDesc( + ifstream& fileStream, ///< Stream to read content from + E_TimeSys& tsys, ///< Time system + E_ObxFrame& frame) ///< Frame type +{ + tsys = E_TimeSys::NONE; + frame = E_ObxFrame::OTHER; + + while (fileStream) + { + string line; + + getline(fileStream, line); + + if (line[0] == ' ') + { + if (line.substr(1, 11) == "TIME_SYSTEM") + { + string timeSysStr = line.substr(21, 3); + if (timeSysStr == "GPS") tsys = E_TimeSys::GPST; + else if (timeSysStr == "UTC") tsys = E_TimeSys::UTC; + else if (timeSysStr == "TAI") tsys = E_TimeSys::TAI; + else if (timeSysStr == "GAL") tsys = E_TimeSys::GST; + else if (timeSysStr == "GLO") tsys = E_TimeSys::GLONASST; + else if (timeSysStr == "TT ") tsys = E_TimeSys::TT; + else + { + BOOST_LOG_TRIVIAL(error) + << "Unknown Orbex time system: " << timeSysStr << std::endl; + return false; + } + + // currently only GPST and UTC are supported + if ( tsys != +E_TimeSys::GPST + &&tsys != +E_TimeSys::UTC) + { + BOOST_LOG_TRIVIAL(error) + << "Unsupported time system: " << timeSysStr << std::endl; + return false; + } + } + else if (line.substr(1, 10) == "FRAME_TYPE") + { + string frameTypeStr = line.substr(21, 20); + boost::trim(frameTypeStr); + + try + { + frame = E_ObxFrame::_from_string(frameTypeStr.c_str()); + } + catch (...) + { + BOOST_LOG_TRIVIAL(debug) + << "Unknown Orbex frame type: " << frameTypeStr << std::endl; + } + + if ( frame != +E_ObxFrame::ECEF + &&frame != +E_ObxFrame::ECI) + { + BOOST_LOG_TRIVIAL(error) + << "Unsupported Orbex frame type: " << frameTypeStr << std::endl; + return false; + } + } + } + else if (line[0] == '-') + { + // end of block + string closure = "-FILE/DESCRIPTION"; + if (line != closure) + { + BOOST_LOG_TRIVIAL(error) + << "Incorrect block closure line encountered: " + << line << " != " << closure << std::endl; + return false; + } + else + { + return true; + } + } + } + + return false; +} + +/** Read SATELLITE/ID_AND_DESCRIPTION block +*/ +bool readOrbexSatId( + ifstream& fileStream) ///< Stream to read content from +{ + while (fileStream) + { + string line; + + getline(fileStream, line); + + if (line[0] == '-') + { + // end of block + string closure = "-SATELLITE/ID_AND_DESCRIPTION"; + if (line != closure) + { + BOOST_LOG_TRIVIAL(error) + << "Incorrect block closure line encountered: " + << line << " != " << closure << std::endl; + return false; + } + else + { + return true; + } + } + } + + return false; +} + +/** Read EPHEMERIS/DATA block +*/ +bool readOrbexEph( + ifstream& fileStream, ///< Stream to read content from + Navigation& nav, ///< Navigation data + E_TimeSys tsys = E_TimeSys::GPST, ///< Time system + E_ObxFrame frame = E_ObxFrame::ECEF) ///< Frame type +{ + GTime time = {}; + int nsat = 0; + + static int index = 0; // keep track of file number + index++; + + while (fileStream) + { + string line; + + getline(fileStream, line); + + char* buff = &line[0]; + + if ( line[0] == '#' + &&line[1] == '#') + { + bool error = str2time(buff, 3, 32, time); + if (error) + { + BOOST_LOG_TRIVIAL(error) + << "Invalid epoch line in Orbex file: " << line << std::endl; + return false; + } + + if (tsys == +E_TimeSys::UTC) + { + UtcTime utcTime; + utcTime.bigTime = time.bigTime; + + time = utcTime; + } + + nsat = str2num(buff, 36, 3); + + index++; + } + else if (line[0] == ' ') + { + if (nsat == 0) + { + BOOST_LOG_TRIVIAL(error) + << "Epoch line invalid or not found before data records" << std::endl; + return false; + } + + string recType = line.substr(1,3); + if (recType == "ATT") + { + E_Sys sys = code2sys(buff[5]); + int prn = (int)str2num(buff, 6, 2); + + SatSys Sat(sys, prn); + if (!Sat) + continue; + + Att att = {}; + att.time = time; + att.index = index; + att.Sat = Sat; + att.frame = frame; + + int nRec = (int)str2num(buff, 22, 1); + if (nRec != 4) + { + BOOST_LOG_TRIVIAL(error) + << "Invalid number of data columns: " << nRec << std::endl; + return false; + } + + att.q.w() = str2num(buff, 24, 19); + att.q.x() = str2num(buff, 44, 19); + att.q.y() = str2num(buff, 64, 19); + att.q.z() = str2num(buff, 84, 19); + + att.q.normalize(); + if (Sat.sys == +E_Sys::GAL) + { + // rotate from original GAL frame to ANTEX frame (180deg around local Z+) (https://www.gsc-europa.eu/support-to-developers/galileo-satellite-metadata#3.2) + Eigen::Quaterniond rotZ(0, 0, 0, 1); + att.q = rotZ * att.q; + } + + nav.attMapMap[att.Sat][att.time] = att; + } + // other record types to be added here, e.g. + /* + else if (recType == "PCS") + { + ... + } + */ + else + { + BOOST_LOG_TRIVIAL(error) + << "Unsupported record type: " << recType << std::endl; + return false; + } + } + else if (line[0] == '-') + { + // end of block + string closure = "-EPHEMERIS/DATA"; + if (line != closure) + { + BOOST_LOG_TRIVIAL(error) + << "Incorrect block closure line encountered: " + << line << " != " << closure << std::endl; + return false; + } + else + { + return true; + } + } + } + + return false; +} + +/** Read an ORBEX file into navigation data struct +*/ +void readOrbex( + string filepath, ///< File path to output file + Navigation& nav) ///< Navigation data +{ + ifstream fileStream(filepath); + if (!fileStream) + { + BOOST_LOG_TRIVIAL(error) + << "Orbex file open error " << filepath << std::endl; + } + + // header lines - each ORBEX file must begin with the two header lines + double ver; + int failure = readOrbexHeader(fileStream, ver); + + if (failure) + { + BOOST_LOG_TRIVIAL(error) + << "Error reading Orbex header lines" << std::endl; + return; + } + + E_TimeSys tsys = E_TimeSys::NONE; + E_ObxFrame frame = E_ObxFrame::OTHER; + + while (fileStream) + { + string line; + getline(fileStream, line); + line = line.substr(0, line.find(' ')); + if (line.back() == '\r') + line.pop_back(); + bool pass = true; + + if (!fileStream) + { + // unexpected end of file + BOOST_LOG_TRIVIAL(error) + << "Closure line not found before end of Orbex file " << filepath << std::endl; + break; + } + else if (line == "+FILE/DESCRIPTION") pass = readOrbexFileDesc(fileStream, tsys, frame ); + else if (line == "+SATELLITE/ID_AND_DESCRIPTION") pass = readOrbexSatId (fileStream ); + else if (line == "+EPHEMERIS/DATA") pass = readOrbexEph (fileStream, nav, tsys, frame ); + else if (line == "%END_ORBEX") return; // end of file + + if (pass == false) + { + BOOST_LOG_TRIVIAL(error) + << "Error reading Orbex " << line << " block" << std::endl; + return; + } + } + + return; +} diff --git a/src/cpp/common/orbexWrite.cpp b/src/cpp/common/orbexWrite.cpp new file mode 100644 index 000000000..0a96a4049 --- /dev/null +++ b/src/cpp/common/orbexWrite.cpp @@ -0,0 +1,448 @@ + +// #pragma GCC optimize ("O0") + + +#include + + +#include "eigenIncluder.hpp" +#include "navigation.hpp" +#include "orbexWrite.hpp" +#include "ephemeris.hpp" +#include "acsConfig.hpp" +#include "enums.h" +#include "ppp.hpp" + +#define ORBEX_VER 0.09 +#define NO_PV_STD 99999.9 +#define NO_CLK 9999999.9999999 +#define NO_CLK_STD 9999999.999 + +/** ORBEX entry to write out +*/ +struct OrbexEntry +{ + SatSys Sat = {}; ///< Satellite ID + Vector3d pos = Vector3d::Zero(); ///< Satellite position (m) + Vector3d vel = Vector3d::Zero(); ///< Satellite velocity (m/s) + double clk = NO_CLK; ///< Satellite clock (microsecond) & clock-rate (nanosecond/s) + double clkVel = NO_CLK; + Vector3d posStd = Vector3d::Ones() * NO_PV_STD; ///< Satellite position std (mm) + Vector3d velStd = Vector3d::Ones() * NO_PV_STD; ///< Satellite velocity std (micrometer/s) + double clkStd = NO_CLK_STD; ///< Satellite clock (picosecond) + double clkVelStd = NO_CLK_STD; ///< Satellite clock-rate std (femtosecond/s) + Quaterniond q = {0, 0, 0, 0}; ///< Satellite attitude in quaternions + + // other record types, e.g. correlation coefficients, to be added in the future +}; + +typedef map OrbexSatList; ///< List of ORBEX data to print + +OrbexFileData orbexCombinedFileData; ///< Combined file editing information for ORBEX writing + +/** Write ORBEX header lines and header blocks including FILE/DESCRIPTION and SATELLITE/ID_AND_DESCRIPTION block +*/ +void writeOrbexHeader( + std::fstream& orbexStream, ///< Output stream + GTime time, ///< Epoch time (GPST) + map& outSys, ///< Systems to include in file + OrbexFileData& outFileDat) ///< File editing information for ORBEX writing +{ + GEpoch ep = time; + + tracepdeex(0, orbexStream, "%%=ORBEX %5.2f\n", ORBEX_VER); + tracepdeex(0, orbexStream, "%%%%\n"); + + tracepdeex(0, orbexStream, "+FILE/DESCRIPTION\n"); + tracepdeex(0, orbexStream, " DESCRIPTION %s\n", "Satellite attitude quaternions"); + tracepdeex(0, orbexStream, " CREATED_BY %s %s\n", acsConfig.analysis_agency.c_str(), acsConfig.analysis_program.c_str()); + tracepdeex(0, orbexStream, " CREATION_DATE %s\n", ((GTime)timeGet()).to_string(0).c_str()); + tracepdeex(0, orbexStream, " INPUT_DATA %s\n", ""); + tracepdeex(0, orbexStream, " CONTACT %s\n", "npi@ga.gov.au"); + tracepdeex(0, orbexStream, " TIME_SYSTEM %s\n", "GPS"); + tracepdeex(0, orbexStream, " START_TIME %4.0f %2.0f %2.0f %2.0f %2.0f %15.12f\n", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); + + outFileDat.headerTimePos = orbexStream.tellp(); + + tracepdeex(0, orbexStream, " END_TIME %4.0f %2.0f %2.0f %2.0f %2.0f %15.12f\n", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); + tracepdeex(0, orbexStream, " EPOCH_INTERVAL %9.3f\n", acsConfig.epoch_interval); + tracepdeex(0, orbexStream, " COORD_SYSTEM %s\n", "IGS14"); + tracepdeex(0, orbexStream, " FRAME_TYPE %s\n", "ECEF"); + tracepdeex(0, orbexStream, " ORBIT_TYPE %s\n", ""); + tracepdeex(0, orbexStream, " LIST_OF_REC_TYPES "); + for (auto& recType : acsConfig.orbex_record_types) + { + tracepdeex(0, orbexStream, " %s", recType); + } + tracepdeex(0, orbexStream, "\n"); + + tracepdeex(0, orbexStream, "-FILE/DESCRIPTION\n"); + + for (auto sys : {E_Sys::GPS, E_Sys::GLO, E_Sys::GAL, E_Sys::BDS}) + { + if (outSys[sys]) + for (auto Sat : getSysSats(sys)) + { + outFileDat.satList[Sat] = false; + } + } + + Block block(orbexStream, "SATELLITE/ID_AND_DESCRIPTION"); + + outFileDat.satListPos = orbexStream.tellp(); + + for (auto& [sat, dummy] : outFileDat.satList) + { + tracepdeex(0, orbexStream, "* \n"); // placeholders for satellite list + } + + // optional blocks to be added in the future (not yet available in existing ORBEX files) +} + +/** Write PCS or VCS records +*/ +bool writePVCS( + std::fstream& orbexStream, ///< Output stream + OrbexEntry& entry, ///< ORBEX entry to write out + string recType) ///< Record type +{ + Vector3d pv = Vector3d::Zero(); // satellite position or velocity + Vector3d pvStd = Vector3d::Zero(); // satellite position or velocity std + double clk = 0; // satellite clock or clock-rate + double clkStd = 0; // satellite clock or clock-rate std + + if (recType == "PCS") + { + pv = entry.pos; + pvStd = entry.posStd; + clk = entry.clk; + clkStd = entry.clkStd; + } + else if (recType == "VCS") + { + pv = entry.vel; + pvStd = entry.velStd; + clk = entry.clkVel; + clkStd = entry.clkVelStd; + } + else + { + return false; + } + + if (pv.isZero()) + return false; // skip if no position entries + + if (fabs(clk) >= NO_CLK) clk = NO_CLK; + if (pvStd.x() >= NO_PV_STD) pvStd.x() = NO_PV_STD; + if (pvStd.y() >= NO_PV_STD) pvStd.y() = NO_PV_STD; + if (pvStd.z() >= NO_PV_STD) pvStd.z() = NO_PV_STD; + if (clkStd >= NO_CLK_STD) clkStd = NO_CLK_STD; + + + // satellite flags not available at the moment + int nRec = 8; + tracepdeex(0, orbexStream, " %s %s %d %16.4f %16.4f %16.4f %16.7f %7.1f %7.1f %7.1f %11.3f\n", + recType, + entry.Sat.id().c_str(), + nRec, + pv.x(), + pv.y(), + pv.z(), + clk, + pvStd.x(), + pvStd.y(), + pvStd.z(), + clkStd); + + return true; +} + +/** Write POS or VEL records +*/ +bool writePV( + std::fstream& orbexStream, ///< Output stream + OrbexEntry& entry, ///< ORBEX entry to write out + string recType) ///< Record type +{ + Vector3d pv = Vector3d::Zero(); // satellite position or velocity + + if (recType == "POS") pv = entry.pos; + else if (recType == "VEL") pv = entry.vel; + else return false; + if (pv.isZero()) return false; // skip if no position entries + + int nRec = 3; + tracepdeex(0, orbexStream, " %s %s %d %16.4f %16.4f %16.4f\n", + recType, + entry.Sat.id().c_str(), + nRec, + pv.x(), + pv.y(), + pv.z()); + + return true; +} + +/** Write CLK or CRT records +*/ +bool writeClk( + std::fstream& orbexStream, ///< Output stream + OrbexEntry& entry, ///< ORBEX entry to write out + string recType) ///< Record type +{ + double clk = 0; // satellite clock or clock-rate + + if (recType == "CLK") clk = entry.clk; + else if (recType == "CRT") clk = entry.clkVel; + else return false; + + if (fabs(clk) > NO_CLK) + return false; + + int nRec = 1; + tracepdeex(0, orbexStream, " %s %s %d %16.7f\n", + recType, + entry.Sat.id().c_str(), + nRec, + clk); + + return true; +} + +/** Write ATT records +*/ +bool writeAtt( + std::fstream& orbexStream, ///< Output stream + OrbexEntry& entry, ///< ORBEX entry to write out + string recType) ///< Record type +{ + if (recType != "ATT") return false; + if (entry.q.norm() == 0) return false; + + int nRec = 4; + tracepdeex(0, orbexStream, " %s %s %d %19.16f %19.16f %19.16f %19.16f\n", + recType, + entry.Sat.id().c_str(), + nRec, + entry.q.w(), + entry.q.x(), + entry.q.y(), + entry.q.z()); + + return true; +} + +/** Write EPHEMERIS/DATA block and update END_TIME line +*/ +void updateOrbexBody( + string& filename, ///< File path to output file + OrbexSatList& entryList, ///< List of data to print + GTime time, ///< Epoch time (GPST) + map& outSys, ///< Systems to include in file + OrbexFileData& outFileDat) ///< Current file editing information +{ + GEpoch ep = time; + + // first create if non existing + { + std::fstream maker(filename, std::ios::app); + } + std::fstream orbexStream(filename); + + if (!orbexStream) + { + BOOST_LOG_TRIVIAL(error) << "Error opening " << filename << " for Orbex file."; + return; + } + + orbexStream.seekp(0, std::ios::end); + + long endFilePos = orbexStream.tellp(); + + if (endFilePos == 0) + { + writeOrbexHeader(orbexStream, time, outSys, outFileDat); + + tracepdeex(0, orbexStream, "+EPHEMERIS/DATA\n"); + tracepdeex(0, orbexStream, "*PCS ID_ FLAGS_ N __X______(m)____ ______Y__(m)____ ______Z___(m)___ _SVCLK___(usec)_ _STD_X_ _STD_Y_ _STD_Z_ ____STD_CLK\n"); + tracepdeex(0, orbexStream, "*VCS ID_ FLAGS_ N __VX_____(m/s)__ ______VY_(m/s)__ ______VZ__(m/s)_ _CLKRATE_(ns/s)_ _STD_VX _STD_VY _STD_VZ ____STD_CLK\n"); + tracepdeex(0, orbexStream, "*POS ID_ FLAGS_ N __X______(m)____ ______Y__(m)____ ______Z___(m)___\n"); + tracepdeex(0, orbexStream, "*VEL ID_ FLAGS_ N __VX_____(m/s)__ ______VY_(m/s)__ ______VZ__(m/s)_\n"); + tracepdeex(0, orbexStream, "*CLK ID_ FLAGS_ N __SVCLK__(usec)_\n"); + tracepdeex(0, orbexStream, "*CRT ID_ FLAGS_ N __SVCLKR_(ns/s)_\n"); + tracepdeex(0, orbexStream, "*ATT ID_ FLAGS_ N __q0_______________ ___q1______________ ____q2_____________ ____q3_____________\n"); + tracepdeex(0, orbexStream, "*ATT RECORDS: TRANSFORMATION FROM TERRESTRIAL FRAME COORDINATES (T) TO SAT. BODY FRAME ONES (B) SUCH AS\n"); + tracepdeex(0, orbexStream, "* (0,B) = q.(0,T).trans(q)\n"); + + //tracepdeex(0, orbexStream, "*CPC ID_ FLAGS_ N ______xy_corr____ ______xz_corr____ ______xc_corr____ ______yz_corr____ ______yc_corr____ ______zc_corr____\n"); + //tracepdeex(0, orbexStream, "*CVC ID_ FLAGS_ N ____vxvy_corr____ ____vxvz_corr____ ____vxvc_corr____ ____vyvz_corr____ ____vyvc_corr____ ____vzvc_corr____\n"); + } + else + { + orbexStream.seekp(outFileDat.headerTimePos); + + tracepdeex(0, orbexStream, " END_TIME %4.0f %2.0f %2.0f %2.0f %2.0f %15.12f\n", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); + + orbexStream.seekp(outFileDat.endDataPos); + } + + tracepdeex(0, orbexStream, "## %4.0f %2.0f %2.0f %2.0f %2.0f %15.12f", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); + + long numSatPos = orbexStream.tellp(); + + int nsat = 0; + tracepdeex(0, orbexStream, " %3d\n", nsat); + + for (auto& [sat, isIncluded] : outFileDat.satList) + { + auto it = entryList.find(sat); + if (it == entryList.end()) + continue; + + auto& [key, entry] = *it; + isIncluded = false; + for (auto& recType : acsConfig.orbex_record_types) + { + if ( recType == "PCS" + ||recType == "VCS") + { + isIncluded |= writePVCS(orbexStream, entry, recType); + } + else if ( recType == "CPC" + ||recType == "CVC") + { + // to be added if needed in the future + } + else if ( recType == "POS" + ||recType == "VEL") + { + isIncluded |= writePV (orbexStream, entry, recType); + } + else if ( recType == "CLK" + ||recType == "CRT") + { + isIncluded |= writeClk(orbexStream, entry, recType); + } + else if (recType == "ATT") + { + isIncluded |= writeAtt(orbexStream, entry, recType); + } + } + + if (isIncluded) + { + nsat++; + } + } + + outFileDat.endDataPos = orbexStream.tellp(); + + tracepdeex(0, orbexStream, "-EPHEMERIS/DATA\n"); + tracepdeex(0, orbexStream, "%%END_ORBEX\n"); + + orbexStream.seekp(numSatPos); + + tracepdeex(0, orbexStream, " %3d\n", nsat); + + orbexStream.seekp(outFileDat.satListPos); + + for (auto& [sat, isIncluded] : outFileDat.satList) + { + if (isIncluded) + { + tracepdeex(0, orbexStream, " %3s\n", sat.id().c_str()); + } + } +} + +/** Retrieve satellite orbits, clocks and attitudes for all included systems and write out to an ORBEX file +*/ +void writeSysSetOrbex( + string filename, ///< File path to output file + GTime time, ///< Epoch time (GPST) + map& outSys, ///< Systems to include in file + OrbexFileData& outFileDat, ///< Current file editing information + vector orbDataSrcs, ///< Data source for satellite positions & velocities + vector clkDataSrcs, ///< Data source for satellite clocks + vector attDataSrcs, ///< Data source for satellite attitudes + KFState* kfState_ptr) ///< Pointer to a kalman filter to take values from +{ + OrbexSatList entryList; + + for (auto& [Sat, satNav] : nav.satNavMap) + { + if (outSys[Sat.sys] == false) + continue; + + OrbexEntry entry; + entry.Sat = Sat; + + // Create a dummy observation + GObs obs; + obs.Sat = Sat; + obs.time = time; + obs.satNav_ptr = &nav.satNavMap[Sat]; + + GTime teph = time; + + // satellite orbit - position and velocity + satellite clock (for PCS and VCS record only) + bool orbPass = true; + orbPass &= satclk(nullStream, time, time, obs, clkDataSrcs, nav, kfState_ptr); + orbPass &= satpos(nullStream, time, time, obs, orbDataSrcs, E_OffsetType::COM, nav, kfState_ptr); + + if (orbPass) + { + entry.pos = obs.rSat; + entry.vel = obs.satVel; + entry.clk = obs.satClk * 1E6; // microsecond + entry.clkVel = obs.satClkVel * 1E9; // nanosecond + } + + // satellite attitude + bool attPass = false; + Quaterniond quat; + if (orbPass) + { + attPass = satQuat(obs, attDataSrcs, quat, true); + } + + if (attPass) + { + if (quat.w() < 0) // convention to have +ve w + { + quat.w() *= -1; + quat.x() *= -1; + quat.y() *= -1; + quat.z() *= -1; + } + + entry.q = quat.conjugate(); // satAtt() returns transformation from body to ECEF, but Orbex req's ECEF to body - i.e. quat.conjugate() + } + + if ( orbPass + ||attPass) + { + entryList[Sat] = entry; + } + } + + updateOrbexBody(filename, entryList, time, outSys, outFileDat); +} + +/** Output ORBEX files +*/ +void outputOrbex( + GTime time, ///< Epoch time (GPST) + vector orbDataSrcs, ///< Data source for satellite positions & velocities + vector clkDataSrcs, ///< Data source for satellite clocks + vector attDataSrcs, ///< Data source for satellite attitudes + KFState* kfState_ptr) ///< Pointer to a kalman filter to take values from +{ + auto sysFilenames = getSysOutputFilenames(acsConfig.orbex_filename, time); + + for (auto [filename, sysMap] : sysFilenames) + { + writeSysSetOrbex(filename, time, sysMap, orbexCombinedFileData, orbDataSrcs, clkDataSrcs, attDataSrcs, kfState_ptr); + } +} diff --git a/src/cpp/common/orbexWrite.hpp b/src/cpp/common/orbexWrite.hpp new file mode 100644 index 000000000..629294c68 --- /dev/null +++ b/src/cpp/common/orbexWrite.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +using std::string; +using std::map; + +#include "rinexObsWrite.hpp" + +struct GTime; +class E_Source; +struct KFState; + +/** File editing information for ORBEX writing +*/ +struct OrbexFileData +{ + map satList; ///< List of satellites included in the ORBEX file + long headerTimePos = 0; ///< Position of put pointer for END_TIME line + long satListPos = 0; ///< Position of put pointer for beginning of satellite list + long endDataPos = 0; ///< Position of put pointer for end of EPHEMERIS/DATA block +}; + +void writeSysSetOrbex( + string filename, + GTime time, + map& outSys, + OrbexFileData& outFileDat, + vector orbDataSrcs, + vector clkDataSrcs, + vector attDataSrcs, + KFState* kfState_ptr = nullptr); + +void outputOrbex( + GTime time, + vector orbDataSrcs, + vector clkDataSrcs, + vector attDataSrcs, + KFState* kfState_ptr = nullptr); + diff --git a/src/cpp/common/orbits.cpp b/src/cpp/common/orbits.cpp index 15242037d..094cec42e 100644 --- a/src/cpp/common/orbits.cpp +++ b/src/cpp/common/orbits.cpp @@ -13,21 +13,21 @@ using std::chrono::system_clock; using std::chrono::time_point; using std::string; + #include "peaCommitVersion.h" -#include "streamTrace.hpp" +#include "eigenIncluder.hpp" +#include "coordinates.hpp" #include "navigation.hpp" +#include "ephPrecise.hpp" #include "acsConfig.hpp" #include "constants.hpp" -#include "ephemeris.hpp" #include "algebra.hpp" #include "orbits.hpp" #include "satSys.hpp" #include "common.hpp" +#include "trace.hpp" #include "enums.h" -#include "eigenIncluder.hpp" - - /* split a string data into data ----------------------------------------------- * args : char *p I string pointer @@ -205,7 +205,8 @@ int readorbit( || buff[0] == 'R' || buff[0] == 'C' || buff[0] == 'E' - || buff[0] == 'J') + || buff[0] == 'J' + || buff[0] == 'L') { SatSys Sat = SatSys(buff); auto& satOrbit = nav.satNavMap[Sat].satOrbit; @@ -223,17 +224,19 @@ int readorbit( orbitInfo.ti[0] += orbitInfo.ti[1] / 24 / 3600; double ep[6]; - jd2ymdhms(orbitInfo.ti[0] + JD2MJD, ep); + jd2ymdhms(orbitInfo.ti[0] + JD2MJD, ep); //todo aaron, remove this and the function orbitInfo.time = epoch2time(ep); orbitInfo.partials.resize(satOrbit.numUnknowns, 3); - for (int j = 0; j < 6; j++) + for (int j = 0; j < 3; j++) { /* pos, vel and their partials */ - orbitInfo.xcrf[j] = data[j + 2]; - orbitInfo.xtrf[j] = data[j + 8]; + orbitInfo.posEci [j] = data[j + 2]; + orbitInfo.velEci [j] = data[j + 2 + 3]; + orbitInfo.posEcef[j] = data[j + 8]; + orbitInfo.velEcef[j] = data[j + 8 + 3]; } int k = 0; @@ -271,15 +274,12 @@ void outputOrbit( return; } - double ep[6]; - time2epoch(kfState.time, ep); - double jd = ymdhms2jd(ep); - double mjd = jd - JD2MJD; + MjDateTT mjd = kfState.time; - std::time_t end_time = system_clock::to_time_t(system_clock::now()); + GTime endTime = timeGet(); tracepdeex(0, orbitFile, "#INFO Orbit estimated by PEA\n"); - tracepdeex(0, orbitFile, "#INFO Generated from: PEA (v%s) at %s\n", GINAN_COMMIT_VERSION, std::ctime(&end_time)); + tracepdeex(0, orbitFile, "#INFO Generated from: PEA (v%s) at %s\n", GINAN_COMMIT_VERSION, endTime.to_string().c_str()); for (auto& str : nav.podInfoList) { @@ -291,21 +291,21 @@ void outputOrbit( double eopVariances[3] = {}; bool pass = true; - int i = 0; - for (string type : {xp_str, yp_str, ut1_str}) + for (short i = 0; i < 3; i++) { - KFKey eopKey = {KF::EOP, {}, type}; + KFKey eopKey; + eopKey.type = KF::EOP; + eopKey.num = i; pass &= kfState.getKFValue(eopKey, eopAdjustments[i], &eopVariances[i]); - i++; } tracepdeex(0, orbitFile, "#ERP_d0 MJD XP(arcsec) YP(arcsec) UT1-UTC(sec): "); if (pass == false) { tracepdeex(0, orbitFile, " ----> UNESTIMATED <---- \n"); } - else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd, eopAdjustments[0] / 1000, eopAdjustments[1] / 1000, eopAdjustments[2] / 1000); } + else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd.to_double(), eopAdjustments[0] / 1000, eopAdjustments[1] / 1000, eopAdjustments[2] / 1000); } tracepdeex(0, orbitFile, "#ERP_sigma MJD XP(arcsec) YP(arcsec) UT1-UTC(sec): "); if (pass == false) { tracepdeex(0, orbitFile, " ----> UNESTIMATED <---- \n"); } - else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd, sqrt(eopVariances[0]) / 1000, sqrt(eopVariances[1]) / 1000, sqrt(eopVariances[2]) / 1000); } + else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd.to_double(), sqrt(eopVariances[0]) / 1000, sqrt(eopVariances[1]) / 1000, sqrt(eopVariances[2]) / 1000); } } { @@ -313,30 +313,27 @@ void outputOrbit( double eopRateVariances[3] = {}; bool pass = true; - int i = 0; - for (string type : {xp_str, yp_str, ut1_str}) + for (int i = 0; i < 3; i++) { - KFKey eopKey = {KF::EOP_RATE, {}, type}; + KFKey eopKey; + eopKey.type = KF::EOP_RATE; + eopKey.num = i; pass &= kfState.getKFValue(eopKey, eopRateAdjustments[i], &eopRateVariances[i]); - i++; } tracepdeex(0, orbitFile, "#ERP_RATE_d0 MJD XP(arcsec/day) YP(arcsec/day) UT1-UTC(sec/day):"); if (pass == false) { tracepdeex(0, orbitFile, " ----> UNESTIMATED <---- \n"); } - else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd, eopRateAdjustments[0] / 1000, eopRateAdjustments[1] / 1000, eopRateAdjustments[2] / 1000); } + else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd.to_double(), eopRateAdjustments[0] / 1000, eopRateAdjustments[1] / 1000, eopRateAdjustments[2] / 1000); } tracepdeex(0, orbitFile, "#ERP_RATE_sigma MJD XP(arcsec/day) YP(arcsec/day) UT1-UTC(sec/day):"); if (pass == false) { tracepdeex(0, orbitFile, " ----> UNESTIMATED <---- \n"); } - else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd, sqrt(eopRateVariances[0]) / 1000, sqrt(eopRateVariances[1]) / 1000, sqrt(eopRateVariances[2]) / 1000); } + else { tracepdeex(0, orbitFile, " %.6f %26.16e %26.16e %26.16e\n", mjd.to_double(), sqrt(eopRateVariances[0]) / 1000, sqrt(eopRateVariances[1]) / 1000, sqrt(eopRateVariances[2]) / 1000); } } tracepdeex(0, orbitFile, "#INFO Satellite ICS:\n"); - for (auto& [SatId, satNav] : nav.satNavMap) + for (auto& [Sat, satNav] : nav.satNavMap) { - SatSys Sat; - Sat.fromHash(SatId); - auto& satOrbit = satNav.satOrbit; if (acsConfig.process_sys[Sat.sys] == false) @@ -350,12 +347,12 @@ void outputOrbit( vector adjustments(satOrbit.numUnknowns, 0); bool pass = true; - for (int i = 0; i < satOrbit.numUnknowns; i++) + for (short i = 0; i < satOrbit.numUnknowns; i++) { //get relevant states from kfState string name = satOrbit.parameterNames[i]; - KFKey kfKey = {KF::ORBIT_PTS, Sat, std::to_string(100 + i).substr(1) + "_" + name}; + KFKey kfKey = {.type = KF::ORBIT_PTS, .Sat = Sat, .num = i, .comment = name}; pass &= kfState.getKFValue(kfKey, adjustments[i]); } @@ -485,77 +482,38 @@ int orbPartials( { OrbitInfo& orbit = orbit_it->second; - t[i] = orbit.time - time; + t[i] = (orbit.time - time).to_double(); p[i] = orbit.partials(row, col); } - interpPartials(row, col) = interppol(t, p, INTERPCOUNT); + interpPartials(row, col) = interpolate(t, p, INTERPCOUNT); } return 1; } -void readegm( - string strEGMCoeFile, - EGMCoef& egmCoe) -{ - // ifstream egmCoeFile; - int j = 0, n = 360; - double val = 0; - MatrixXd smn = MatrixXd::Zero(361, 361); - MatrixXd cmn = MatrixXd::Zero(361, 361); - - boost::filesystem::ifstream fileHandler(strEGMCoeFile); - - if (!fileHandler) - { - BOOST_LOG_TRIVIAL(error) << "Error: opening " << strEGMCoeFile << " failed"; - return; - } - - double tmp; - while (j <= n){ - for (int i = 0; i <= j; i++){ - fileHandler >> tmp; - fileHandler >> tmp; - fileHandler >> tmp; - cmn(j,i) = tmp; - // std::cout << std::setw(4) << j << std::setw(4) << i << std::setw(10) << cmn(j,i); - fileHandler >> tmp; - smn(j,i) = tmp; - fileHandler >> tmp; - fileHandler >> tmp; - // std::cout << std::setw(10) << smn(j,i) << std::endl; - } - j++; - } - egmCoe.smn = smn; - egmCoe.cmn = cmn; +#define RTOL_KEPLER 1E-14 ///< relative tolerance for Kepler equation +#define MAX_ITER_KEPLER 30 ///< max number of iteration of Kelpler -} -void inertial2Keplers( +bool inertial2Keplers( Trace& trace, - const Vector3d& r, - const Vector3d& v, - VectorXd& keplers) -{ -// std::cout << "\nIN: " << r.transpose() << " " << v.transpose(); - keplers = VectorXd::Zero(KEPLER::NUM); - + const VectorEci& r, + const VectorEci& v, + Vector6d& keplers) +{ Vector3d e_r = r.normalized(); //Calculate orbital momentum vector (perpendicular to both position and velocity) Vector3d L = r.cross(v); //Obtain the eccentricity vector - Vector3d e = v.cross(L) / MU_GPS - e_r; + Vector3d e = v.cross(L) / MU - e_r; -// std::cout << e.transpose() << std::endl; double L_x = L(0); double L_y = L(1); double L_z = L(2); @@ -571,14 +529,11 @@ void inertial2Keplers( } n0.normalize(); - //get another handy vector Vector3d n1 = L.cross(n0).normalized(); - double e_X = e.dot(n0); double e_Y = e.dot(n1); - //Determine the orbit eccentricity, which is simply the magnitude of the eccentricity vector e, double e_ = e.norm(); @@ -590,7 +545,6 @@ void inertial2Keplers( trace << "\n fixingBBB"; } e.normalize(); - //Determine the true anomaly (angle between e and r) double nu; @@ -605,52 +559,39 @@ void inertial2Keplers( //Compute the mean anomaly with help of Kepler’s Equation from the eccentric anomaly E and the eccentricity e double M = E - e_ * sin(E); -// if (isnan(nu)) -// { -// -// std::cout << "\n " << e.transpose() << " " << e_r.transpose() << "\n"; -// std::cout << "nu is nan\n"; -// } -// if (isnan(e_)) -// { -// std::cout << "e_ is nan\n"; -// } -// if (isnan(E)) -// { -// std::cout << "E is nan\n"; -// } -// if (isnan(M)) -// { -// std::cout << "M is nan\n"; -// } - - keplers(KEPLER::LX) = L_x / MOMENTUM_SCALE; - keplers(KEPLER::LY) = L_y / MOMENTUM_SCALE; - keplers(KEPLER::LZ) = L_z / MOMENTUM_SCALE; +// std::cout << std::endl << "n0 " << n0.transpose(); +// std::cout << "\te " << e.transpose(); +// std::cout << "\tn1 " << n1.transpose(); +// std::cout << "\tnu " << nu; +// std::cout << "\tE " << E; +// std::cout << "\tM " << M; + + if (isnan(nu)) { std::cout << "nu is nan\n"; return false; } + if (isnan(e_)) { std::cout << "e_ is nan\n"; return false; } + if (isnan(E)) { std::cout << "E is nan\n"; return false; } + if (isnan(M)) { std::cout << "M is nan\n"; return false; } + + keplers(KEPLER::LX) = L_x; + keplers(KEPLER::LY) = L_y; + keplers(KEPLER::LZ) = L_z; keplers(KEPLER::EU) = e_X; keplers(KEPLER::EV) = e_Y; keplers(KEPLER::M ) = M; + + return true; } - - -#define RTOL_KEPLER 1E-14 ///< relative tolerance for Kepler equation -#define MAX_ITER_KEPLER 30 ///< max number of iteration of Kelpler - -void keplers2inertial( - VectorXd& keplers0, - Vector3d& pos, - double& dM) -{ - Trace& trace = std::cout; - +VectorEci keplers2Inertial( + Trace& trace, + const Vector6d& keplers0) +{ Vector3d L = Vector3d::Zero(); Vector2d eee = Vector2d::Zero(); - L[0] = keplers0[KEPLER::LX] * MOMENTUM_SCALE; - L[1] = keplers0[KEPLER::LY] * MOMENTUM_SCALE; - L[2] = keplers0[KEPLER::LZ] * MOMENTUM_SCALE; + L[0] = keplers0[KEPLER::LX]; + L[1] = keplers0[KEPLER::LY]; + L[2] = keplers0[KEPLER::LZ]; eee[0] = keplers0[KEPLER::EU]; eee[1] = keplers0[KEPLER::EV]; double M = keplers0[KEPLER::M ]; @@ -664,7 +605,7 @@ void keplers2inertial( int n; for (n = 0; n < MAX_ITER_KEPLER; n++) { - std::cout << "\nE: " << n << " " << E << " " << Eprev; +// std::cout << "\nE: " << n << " " << E << " " << Eprev; Eprev = E; E -= (E - e_ * sin(E) - M) / (1 - e_ * cos(E)); @@ -677,26 +618,15 @@ void keplers2inertial( if (n >= MAX_ITER_KEPLER) { std::cout << "iteratios"; - return; + + return VectorEci(); } double nu = 2 * atan2( sqrt(1 + e_) * sin(E/2), sqrt(1 - e_) * cos(E/2)); - - if (isnan(nu)) - { - std::cout << "nu is NAN\n"; - } - double r = L.squaredNorm() / MU_GPS / (1 + e_ * cos(nu)); - - - - if (isnan(r)) - { - std::cout << "r is NAN\n"; - } + double r = L.squaredNorm() / MU / (1 + e_ * cos(nu)); L.normalize(); @@ -708,11 +638,13 @@ void keplers2inertial( n0 = Vector3d(1,0,0); } n0.normalize(); + //get another handy vector Vector3d n1 = L.cross(n0).normalized(); - Vector3d e = eee[0] * n0 + eee[1] * n1; + Vector3d e = eee[0] * n0 + + eee[1] * n1; if (e.norm() < 0.000001) { @@ -724,45 +656,62 @@ void keplers2inertial( double x = r * cos(nu); double y = r * sin(nu); - - + double cos_w = n0.dot(e); double cos_i = L(2); + double cos_W = n0(0); + double sin_W = n0(1); //dont unify, needs sign + if (cos_w > +1) cos_w = +1; else if (cos_w < -1) cos_w = -1; if (cos_i > +1) cos_i = +1; else if (cos_i < -1) cos_i = -1; - if (cos_W > +1) cos_W = +1; - else if (cos_W < -1) cos_W = -1; double sin_w = sqrt(1 - SQR(cos_w)); double sin_i = sqrt(1 - SQR(cos_i)); - double sin_W = sqrt(1 - SQR(cos_W)); - if (isnan(sin_w)) - { - std::cout << "sin_w is NAN\n"; - } - if (isnan(sin_i)) - { - std::cout << "sin_i is NAN\n"; - } - if (isnan(sin_W)) + if (n0.dot(e.cross(L)) < 0) { - std::cout << "sin_W is NAN\n"; + sin_w *= -1; } - pos[0] = x * (cos_w * cos_W - sin_w * cos_i * sin_W ) - y * (cos_w * cos_i * sin_W + sin_w * cos_W); - pos[1] = x * (cos_w * sin_W + sin_w * cos_i * cos_W ) + y * (cos_w * cos_i * cos_W - sin_w * sin_W); - pos[2] = x * ( + sin_w * sin_i ) + y * (cos_w * sin_i); - double A = r / (1 - e_ * cos(E)); - - dM = sqrt(MU_GPS /A/A/A); +// std::cout << "\tcosw " << cos_w; +// std::cout << "\tcosi " << cos_i; +// std::cout << "\tcosW " << cos_W; +// std::cout << "\tsinw " << sin_w; +// std::cout << "\tsini " << sin_i; +// std::cout << "\tsinW " << sin_W; + + if (isnan(nu)) { std::cout << "nu is NAN\n"; } + if (isnan(r)) { std::cout << "r is NAN\n"; } + if (isnan(sin_w)) { std::cout << "sin_w is NAN\n"; } + if (isnan(sin_i)) { std::cout << "sin_i is NAN\n"; } + if (isnan(sin_W)) { std::cout << "sin_W is NAN\n"; } + + VectorEci rSat; + rSat.x() = x * (cos_w * cos_W - sin_w * cos_i * sin_W ) - y * (cos_w * cos_i * sin_W + sin_w * cos_W); + rSat.y() = x * (cos_w * sin_W + sin_w * cos_i * cos_W ) + y * (cos_w * cos_i * cos_W - sin_w * sin_W); + rSat.z() = x * ( + sin_w * sin_i ) + y * (cos_w * sin_i); + + return rSat; +// std::cout << "\te " << e.transpose(); +// std::cout << std::endl << "n0 " << n0.transpose(); +// std::cout << "\tn1 " << n1.transpose(); + +// std::cout << "\tnu " << nu; + +// std::cout << "\tE " << E; +// std::cout << "\tM " << M; + +// double A = r / (1 - e_ * cos(E)); +// +// dM = sqrt(MU_GPS /A/A/A); } void getKeplerPartials( + Trace& trace, VectorXd& keplers0, MatrixXd& partials) { @@ -774,9 +723,7 @@ void getKeplerPartials( }; //get base position - Vector3d pos0; - double dummy; - keplers2inertial(keplers0, pos0, dummy); + VectorEci pos0 = keplers2Inertial(trace, keplers0); for (int i = 0; i < 6; i++) { @@ -784,9 +731,7 @@ void getKeplerPartials( keplers1[i] += deltas[i]; - - Vector3d pos1; - keplers2inertial(keplers1, pos1, dummy); + VectorEci pos1 = keplers2Inertial(trace, keplers1); partials.col(i) = (pos1 - pos0) / deltas[i]; } @@ -794,8 +739,9 @@ void getKeplerPartials( void getKeplerInversePartials( - Vector3d& pos, - Vector3d& vel, + Trace& trace, + VectorEci& pos, + VectorEci& vel, MatrixXd& partials) { double deltas[6] = @@ -806,24 +752,83 @@ void getKeplerInversePartials( partials = MatrixXd::Zero(6, 6); //get base keplers - VectorXd keplers0; - inertial2Keplers(std::cout, pos, vel, keplers0); + Vector6d keplers0; + bool pass = inertial2Keplers(std::cout, pos, vel, keplers0); for (int i = 0; i < 6; i++) { - Vector3d pos1 = pos; - Vector3d vel1 = vel; + VectorEci pos1 = pos; + VectorEci vel1 = vel; if (i < 3) pos1[i] += deltas[i]; else vel1[i-3] += deltas[i]; - VectorXd keplers1; - - inertial2Keplers(std::cout, pos1, vel1, keplers1); + Vector6d keplers1; + pass = inertial2Keplers(std::cout, pos1, vel1, keplers1); partials.col(i) = (keplers1 - keplers0) / deltas[i]; } } - +VectorEci propagateEllipse( + Trace& trace, + GTime time, + double dt, + VectorEci& rSat, + VectorEci& vSat, + VectorEcef& ecef) +{ + ERPValues erpv = geterp(nav.erp, time); + + FrameSwapper frameSwapper(time + dt, erpv); + + if (dt == 0) + { + ecef = frameSwapper(rSat); + + return rSat; + } + + Vector6d keplers0; + + bool pass = inertial2Keplers(trace, rSat, vSat, keplers0); + + if (pass == false) + { + VectorEci newPos = rSat + + vSat * dt; + + ecef = frameSwapper(newPos); + + return newPos; + } + + + Vector3d L = Vector3d( + keplers0[KEPLER::LX], + keplers0[KEPLER::LY], + keplers0[KEPLER::LZ] + ); + + double h = L.norm(); + + Vector2d E = Vector2d( + keplers0[KEPLER::EU], + keplers0[KEPLER::EV] + ); + + double e = E.norm(); + + double T = 2 * PI / SQR(MU_GPS) * pow(h / sqrt(1 - SQR(e)), 3); //2.82 + + keplers0[KEPLER::M] += 2 * PI * dt / T; + + VectorEci newPos = keplers2Inertial(trace, keplers0); + +// std::cout << "\nrSatInertial: " << newPos.transpose(); + + ecef = frameSwapper(newPos); + + return newPos; +} diff --git a/src/cpp/common/orbits.hpp b/src/cpp/common/orbits.hpp index 151d2b905..69910a6b5 100644 --- a/src/cpp/common/orbits.hpp +++ b/src/cpp/common/orbits.hpp @@ -1,18 +1,10 @@ -#ifndef __ORBIT_HPP__ -#define __ORBIT_HPP__ - - -#include -#include - -using std::unordered_map; -using std::list; +#pragma once #include "eigenIncluder.hpp" -#include "satSys.hpp" #include "station.hpp" +#include "satSys.hpp" ///< initial orbit state info @@ -26,28 +18,27 @@ struct InitialOrbit struct OrbitInfo { // orbit info for one sat on the ith epoch - GTime time; ///< Time of the orbit epoch - double ti[2]; ///< the ith epoch [MJD][sod] + GTime time; ///< Time of the orbit epoch + double ti[2]; ///< the ith epoch [MJD][sod] - Vector xcrf; ///< icrf pos(m) and vel(m/s) - Vector xtrf; ///< itrf pos(m) and vel(m/s) + VectorEci posEci; + VectorEci velEci; + VectorEcef posEcef; + VectorEcef velEcef; - MatrixXd partials; ///< partial wrt initial state + MatrixXd partials; ///< partial wrt initial state }; struct SatOrbit { InitialOrbit initialOrbit; map> orbitInfoMap; - int numUnknowns; ///< number of unknowns + int numUnknowns; vector parameterNames; string srpModel[2]; double mass; }; -void readegm( - string file, - EGMCoef& egm); int orbPartials( @@ -62,29 +53,22 @@ int readorbit( struct KFState; void outputOrbit( - KFState& kfState); - - -void keplers2inertial( - VectorXd& keplers0, - Vector3d& pos, - double& dM); + KFState& kfState); +VectorEci keplers2Inertial( + Trace& trace, + const Vector6d& keplers0); -void inertial2Keplers( +bool inertial2Keplers( Trace& trace, - const Vector3d& r, - const Vector3d& v, - VectorXd& keplers); - -void getKeplerPartials( - VectorXd& keplers0, - MatrixXd& partials); - -void getKeplerInversePartials( - Vector3d& pos, - Vector3d& vel, - MatrixXd& partials); - -#endif + const VectorEci& r, + const VectorEci& v, + Vector6d& keplers); +VectorEci propagateEllipse( + Trace& trace, + GTime time, + double dt, + VectorEci& rSat, + VectorEci& vSat, + VectorEcef& ecef); diff --git a/src/cpp/common/packetStatistics.hpp b/src/cpp/common/packetStatistics.hpp new file mode 100644 index 000000000..31634d1a4 --- /dev/null +++ b/src/cpp/common/packetStatistics.hpp @@ -0,0 +1,109 @@ + +#pragma once + +#include "trace.hpp" + +struct PacketStatistics +{ + long int numPreambleFound = 0; + long int numFramesFailedCRC = 0; + long int numFramesPassCRC = 0; + long int numFramesDecoded = 0; + long int numNonMessBytes = 0; + long int numMessagesLatency = 0; + double totalLatency = 0; + + void printPacketStatistics( + Trace& trace) + { + std::stringstream traceStr; + // traceStr << "Start : " << std::put_time(std::localtime(&startTime.time), "%F %X") << std::endl; + // traceStr << "Finish : " << std::put_time(std::localtime(&endTime.time), "%F %X") << std::endl; + +// double totalTime = (GTime)timeGet() - startTime; + + traceStr << "ExtraBytes : " << numNonMessBytes << std::endl; + traceStr << "FailCrc : " << numFramesFailedCRC << std::endl; + traceStr << "PassedCrc : " << numFramesPassCRC << std::endl; + traceStr << "Decoded : " << numFramesDecoded << std::endl; + traceStr << "Preamble : " << numPreambleFound << std::endl; + + double FailedToPreambleRatio = 0; + if (numPreambleFound != 0) + FailedToPreambleRatio = (double)numFramesFailedCRC / (double)numPreambleFound; + traceStr << "FailedCrcToPreambleRatio : " << FailedToPreambleRatio << std::endl; + + if (numMessagesLatency != 0) + { + double meanLatency = totalLatency / numMessagesLatency; + traceStr << "meanLatency : " << meanLatency << std::endl; + } + else + { + traceStr << "meanLatency : " << 0.0 << std::endl; + } + + string messLine; + while (std::getline(traceStr, messLine)) + tracepdeex(0, trace, (messLine + "\n").c_str()); + } + + void checksumFailure( + string id = "") + { + numFramesFailedCRC++; + + std::stringstream message; + message << "\n CRC Failure - " << id; + message << "\n Number Fail CRC : " << numFramesFailedCRC; + message << "\n Number Passed CRC : " << numFramesPassCRC; + message << "\n Number Decoded : " << numFramesDecoded; + message << "\n Number Preamble : " << numPreambleFound; + message << "\n"; + + std::cout << message.str(); +// messageRtcmLog(message.str()); //todo aaron + } + + +// bool trigger = false; + void checksumSuccess() + { +// std::cout << "Pass\n"; + numFramesPassCRC++; + + } + + void nonFrameByteFound( + unsigned char c) + { +// printf(".%02x", c); + + numNonMessBytes++; +// trigger = true; + } + + void preambleFound() + { +// if (trigger) +// { +// std::cout << std::endl << "premable"; +// trigger = false; +// } + numPreambleFound++; + + if (numNonMessBytes) + { + std::stringstream message; + message << "Extra Bytes, size : " << numNonMessBytes; +// messageRtcmLog(message.str());//todo aaron + } + + numNonMessBytes = 0; + } + + void frameDecoded() + { + numFramesDecoded++; + } +}; diff --git a/src/cpp/common/position3d.hpp b/src/cpp/common/position3d.hpp deleted file mode 100644 index 4cd341890..000000000 --- a/src/cpp/common/position3d.hpp +++ /dev/null @@ -1,51 +0,0 @@ - -#ifndef __POSITION3D_HPP__ -#define __POSITION3D_HPP__ - - -#include "eigenIncluder.hpp" -#include "common.hpp" - - -struct Position3D -{ - Vector3d R; - Vector3d llhvec; - - Position3D() - { - - } - - Position3D(Vector3d& ecef) - { - R = ecef; - } - - Position3D(double* ecef) - { - for (int i = 0; i < 3; i++) - { - R(i) = ecef[i]; - } - } - - operator Vector3d&() - { - return R; - } - - operator Vector3d() const - { - return R; - } - - double* llh() - { - ecef2pos(R.data(), llhvec.data()); - return llhvec.data(); - } -}; - - -#endif diff --git a/src/cpp/common/preceph.cpp b/src/cpp/common/preceph.cpp deleted file mode 100644 index d912f1c30..000000000 --- a/src/cpp/common/preceph.cpp +++ /dev/null @@ -1,818 +0,0 @@ - -// #pragma GCC optimize ("O0") - -#include -#include -#include -#include -#include - -using std::string; -using std::array; -using std::map; - -#include - - -#include "eigenIncluder.hpp" -#include "streamTrace.hpp" -#include "corrections.hpp" -#include "navigation.hpp" -#include "biasSINEX.hpp" -#include "constants.hpp" -#include "ephemeris.hpp" -#include "preceph.hpp" -#include "station.hpp" -#include "algebra.hpp" -#include "common.hpp" -#include "tides.hpp" -#include "gTime.hpp" -#include "enums.h" - -#define NMAX 10 /* order of polynomial interpolation */ -#define MAXDTE 900.0 /* max time difference to ephem time (s) */ -#define EXTERR_CLK 1E-3 /* extrapolation error for clock (m/s) */ -#define EXTERR_EPH 5E-7 /* extrapolation error for ephem (m/s^2) */ - -/* read satellite antenna parameters ------------------------------------------- -* read satellite antenna parameters -* args : char *file I antenna parameter file -* gtime_t time I time -* nav_t *nav IO navigation data -* return : status (1:ok,0:error) -* notes : only support antex format for the antenna parameter file -*-----------------------------------------------------------------------------*/ -/* int readsap(char *file, gtime_t time, nav_t *nav) -{ - pcvs_t pcvs={0}; - pcv_t pcv0={0},*pcv; - int i; - - trace(3,"readsap : file=%s time=%s\n",file,time.to_string(0).c_str()); - - if (!readpcv(file,&pcvs)) return 0; - - for (i=0;ipcvs[i]=pcv?*pcv:pcv0; - } - free(pcvs.pcv); - return 1; -}*/ - -/* read dcb parameters file --------------------------------------------------*/ -int readdcb( - string file) -{ - std::ifstream inputStream(file); - if (!inputStream) - { -// trace(2,"dcb parameters file open error: %s\n",file); - return 0; - } - - double cbias,rms; - char str1[32],str2[32]=""; - E_DCBPair type = E_DCBPair::NONE; - SinexBias entry; -// trace(3,"readdcbf: file=%s\n",file); - - entry.tini.sec = 3; - entry.measType = CODE; - entry.source = "dcb"; - - string line; - while (std::getline(inputStream, line)) - { - char* buff = &line[0]; - - if (strstr(buff,"DIFFERENTIAL (P1-P2) CODE BIASES")) type = E_DCBPair::P1_P2; - else if (strstr(buff,"DIFFERENTIAL (P1-C1) CODE BIASES")) type = E_DCBPair::P1_C1; - else if (strstr(buff,"DIFFERENTIAL (P2-C2) CODE BIASES")) type = E_DCBPair::P2_C2; - - if ( !type - ||sscanf(buff,"%s %s",str1,str2) < 1) - continue; - - if ((cbias = str2num(buff,26,9)) == 0) //todo: bias value may possibly be 0 - continue; - - rms = str2num(buff,38,9); - - entry.bias = cbias * 1E-9 * CLIGHT; /* ns -> m */ //todo aaron, this looks like it had issues to begin with - entry.var = SQR(rms * 1E-9 * CLIGHT); - - SatSys Sat(str1); - - if (Sat.sys == +E_Sys::GPS) - { - if (type == +E_DCBPair::P1_P2) { entry.cod1 = E_ObsCode::L1W; entry.cod2 = E_ObsCode::L2W; } - else if (type == +E_DCBPair::P1_C1) { entry.cod1 = E_ObsCode::L1W; entry.cod2 = E_ObsCode::L1C; } - else if (type == +E_DCBPair::P2_C2) { entry.cod1 = E_ObsCode::L2W; entry.cod2 = E_ObsCode::L2D; } - } - else if (Sat.sys == +E_Sys::GLO) - { - if (type == +E_DCBPair::P1_P2) { entry.cod1 = E_ObsCode::L1P; entry.cod2 = E_ObsCode::L2P; } - else if (type == +E_DCBPair::P1_C1) { entry.cod1 = E_ObsCode::L1P; entry.cod2 = E_ObsCode::L1C; } - else if (type == +E_DCBPair::P2_C2) { entry.cod1 = E_ObsCode::L2P; entry.cod2 = E_ObsCode::L2C; } - } - - string id; - if ( !strcmp(str1,"G") - ||!strcmp(str1,"R")) - { - /* receiver dcb */ - entry.Sat = Sat; - entry.name = str2; - id = str2; - } - else if (Sat) - { - /* satellite dcb */ - entry.Sat = Sat; - entry.name = ""; - id = str1; - } - - if ( Sat.sys == +E_Sys::GLO - &&Sat.prn == 0) - { - // this seems to be a receiver - // for ambiguous GLO receiver bias id (i.e. PRN not specified), duplicate bias entry for each satellite - for (int prn = MINPRNGLO; prn <= MAXPRNGLO; prn++) - { - Sat.prn = prn; - id = entry.name + ":" + Sat.id(); - // entry.Sat = Sat; - pushBiasSinex(id, entry); - } - } - else if ( Sat.sys == +E_Sys::GLO - &&Sat.prn != 0) - { - // this can be a receiver or satellite - id = id + ":" + Sat.id(); - pushBiasSinex(id, entry); - } - else - { - // this can be a receiver or satellite - id = id + ":" + Sat.sysChar(); - pushBiasSinex(id, entry); - } - - // //decompose P1-P2 DCB into OSBs - // SinexBias OSB1, OSB2; - // bool pass = decomposeDSBBias(entry, OSB1, OSB2); //todo , check this - // if (pass) - // { - // pushBiasSinex(id, OSB1); - // pushBiasSinex(id, OSB2); - // } - } - - return 1; -} - -/* add satellite fcb ---------------------------------------------------------*/ -// int addfcb(nav_t *nav, gtime_t ts, gtime_t te, int sat, -// const double *bias, const double *std) //todo aaron, is this broken? -// { -// fcbd_t *nav_fcb; -// int i,j; -// -// if (nav->nf>0&&fabs(timediff(ts,nav->fcb[nav->nf-1].ts))<=1e-3) { -// for (i=0;i<3;i++) { -// nav->fcb[nav->nf-1].bias[sat-1][i]=bias[i]; -// nav->fcb[nav->nf-1].std [sat-1][i]=std [i]; -// } -// return 1; -// } -// if (nav->nf>=nav->nfmax) { -// nav->nfmax=nav->nfmax<=0?2048:nav->nfmax*2; -// if (!(nav_fcb=(fcbd_t *)realloc(nav->fcb,sizeof(fcbd_t)*nav->nfmax))) { -// free(nav->fcb); nav->nf=nav->nfmax=0; -// return 0; -// } -// nav->fcb=nav_fcb; -// } -// for (i=0;ifcb[nav->nf].bias[i][j]=nav->fcb[nav->nf].std[i][j]=0.0; -// } -// for (i=0;i<3;i++) { -// nav->fcb[nav->nf].bias[sat-1][i]=bias[i]; -// nav->fcb[nav->nf].std [sat-1][i]=std [i]; -// } -// nav->fcb[nav->nf ].ts=ts; -// nav->fcb[nav->nf++].te=te; -// return 1; -// } -/* read satellite fcb file ---------------------------------------------------*/ -// int readfcbf(const char *file, nav_t *nav) -// { -// FILE *fp; -// gtime_t ts,te; -// double ep1[6],ep2[6],bias[3]={0},std[3]={0}; -// char buff[1024],str[32],*p; -// int sat; -// -// // trace(3,"readfcbf: file=%s\n",file); -// -// if (!(fp=fopen(file,"r"))) { -// // trace(2,"fcb parameters file open error: %s\n",file); -// return 0; -// } -// while (fgets(buff,sizeof(buff),fp)) { -// if ((p=strchr(buff,'#'))) *p='\0'; -// if (sscanf(buff,"%lf/%lf/%lf %lf:%lf:%lf %lf/%lf/%lf %lf:%lf:%lf %s" -// "%lf %lf %lf %lf %lf %lf",ep1,ep1+1,ep1+2,ep1+3,ep1+4,ep1+5, -// ep2,ep2+1,ep2+2,ep2+3,ep2+4,ep2+5,str,bias,std,bias+1,std+1, -// bias+2,std+2)<17) continue; -// if (!(sat=SatSys(str))) continue; -// ts=epoch2time(ep1); -// te=epoch2time(ep2); -// if (!addfcb(nav,ts,te,sat,bias,std)) return 0; -// } -// fclose(fp); -// return 1; -// } -/* compare satellite fcb -----------------------------------------------------*/ -// bool cmpfcb(fcbd_t&p1, fcbd_t&p2) -// { -// fcbd_t *q1=&p1,*q2=&p2; -// double tt=timediff(q1->ts,q2->ts); -// return tt<-1E-3?-1:(tt>1E-3?1:0); -// } -/* read satellite fcb data ----------------------------------------------------- -* read satellite fractional cycle bias (dcb) parameters -* args : char *file I fcb parameters file (wild-card * expanded) -* nav_t *nav IO navigation data -* return : status (1:ok,0:error) -* notes : fcb data appended to navigation data -*-----------------------------------------------------------------------------*/ -// int readfcb(string& file, nav_t *nav) -// { -// readfcbf(file.c_str(), nav); -// // nav->fcbList.sort(cmpfcb); -// return 1; -// } - -/* polynomial interpolation by Neville's algorithm ---------------------------*/ -double interppol(const double *x, double *y, int n) -{ - for (int j=1; j < n; j++) - for (int i=0; i < n - j; i++) - { - y[i] = (x[i+j] * y[i] - x[i] * y[i+1]) / (x[i+j] - x[i]); - } - - return y[0]; -} - -double interpolate( - double* t, - double* x, - int n) -{ - KFState kfState; - -// kfState.output_residuals = true; - - KFMeasEntryList kfMeasEntryList; - - for (int i = 0; i < n; i++) - { - double T = t[i]; - - KFMeasEntry kfMeasEntry(&kfState); - - double tt = 1; - - for (short int j = 0; j < n; j++) - { - kfMeasEntry.addDsgnEntry({.num = j}, tt); - - tt *= T; - } - - kfMeasEntry.setValue(x[i]); - kfMeasEntry.setNoise(10 ); - - kfMeasEntryList.push_back(kfMeasEntry); - } - - //use state transition to initialise states - kfState.stateTransition(std::cout, GTime::noTime()); - -// kfState.outputStates(std::cout); - - //combine the measurement list into a single matrix - KFMeas combinedMeas = kfState.combineKFMeasList(kfMeasEntryList); - - kfState.leastSquareInitStates(std::cout, combinedMeas, false); - - double value; - kfState.getKFValue({}, value); - - return value; -} - -/* satellite position by precise ephemeris -----------------------------------*/ -int pephpos( - GTime time, - SatSys Sat, - Navigation& nav, - Vector3d& rSat, - double& dtSat, - double* vare = nullptr, - double* varc = nullptr) -{ - double t[NMAX+1]; - double p[3][NMAX+1]; - double c[2]; - double s[3]; - - char id[4]; - Sat.getId(id); -// trace(4,"%s : time=%s sat=%s\n",__FUNCTION__, time.to_string(3).c_str(),id); - - rSat = Vector3d::Zero(); - dtSat = 0; - - if (nav.pephMap.empty()) - { - tracepdeex(3, std::cout, "\nLooking for precise position, but no precise ephemerides found for %s", Sat.id().c_str()); - return 0; - } - - auto it = nav.pephMap.find(Sat); - if (it == nav.pephMap.end()) - { - return 0; - } - - PephList& pephList = nav.pephMap[Sat]; - - if ( (pephList.size() < NMAX + 1) - ||(time < pephList.begin() ->first - MAXDTE) - ||(time > pephList.rbegin() ->first + MAXDTE)) - { - tracepdeex(3, std::cout, "\nno prec ephem %s sat=%s",time.to_string(0).c_str(),id); - return 0; - } - -// //search for the ephemeris in the list - - auto peph_it = pephList.lower_bound(time); - if (peph_it == pephList.end()) - { - peph_it--; - } - - auto middle0 = peph_it; - - //go forward a few steps to make sure we're far from the end of the list. - for (int i = 0; i < NMAX/2; i++) - { - peph_it++; - if (peph_it == pephList.end()) - { - break; - } - } - - //go backward a few steps to make sure we're far from the beginning of the list - for (int i = 0; i <= NMAX; i++) - { - peph_it--; - if (peph_it == pephList.begin()) - { - break; - } - } - - auto begin = peph_it; - - //get interpolation parameters and check all ephemerides have values. - peph_it = begin; - for (int i = 0; i <= NMAX; i++, peph_it++) - { - Peph& peph = peph_it->second; - if (peph.Pos.norm() <= 0) - { -// trace(3,"prec ephem outage %s sat=%s\n",time.to_string(0).c_str(), id); - return 0; - } - - t[i] = peph.time - time; - auto& pos = peph.Pos; -#if 0 - p[0][i]=pos[0]; - p[1][i]=pos[1]; -#else - /* correciton for earh rotation ver.2.4.0 */ //todo aaron change to vector - double sinl = sin(OMGE * t[i]); - double cosl = cos(OMGE * t[i]); - p[0][i] = cosl * pos[0] - sinl * pos[1]; - p[1][i] = sinl * pos[0] + cosl * pos[1]; -#endif - p[2][i] = pos[2]; - } - -// Vector3d rSat2; - - for (int i = 0; i < 3; i++) - { -// rSat2 [i] = interpolate (t, p[i], NMAX + 1); - rSat [i] = interppol (t, p[i], NMAX + 1); - } - -// rSat = rSat2; -// std::cout << std::endl << "diff " << (rSat2 - rSat).transpose(); - - if (vare) - { - for (int i = 0; i < 3; i++) - s[i] = middle0->second.PosStd[i]; - double std = norm(s, 3); - - /* extrapolation error for orbit */ - if (t[0 ] > 0) std += EXTERR_EPH * SQR(t[0 ]) / 2; //todo aaron, needs straigtening as below? - else if (t[NMAX] < 0) std += EXTERR_EPH * SQR(t[NMAX]) / 2; - - *vare = SQR(std); - } - - /* linear interpolation for clock */ - auto middle1 = middle0; - if (middle0 != pephList.begin()) - { - middle0--; - } - t[0] = time - middle0->second.time; - t[1] = time - middle1->second.time; - c[0] = middle0->second.Clk; - c[1] = middle1->second.Clk; - - double std = 0; - if (t[0] <= 0) - { - dtSat = c[0]; - - if (dtSat != 0) - std = middle0->second.ClkStd * CLIGHT + EXTERR_CLK * fabs(t[0]); - } - else if (t[1] >= 0) - { - dtSat = c[1]; - - if (dtSat != 0) - std = middle1->second.ClkStd * CLIGHT + EXTERR_CLK * fabs(t[1]); - } - else if ( c[0] != 0 - &&c[1] != 0) - { - dtSat = (c[1] * t[0] - c[0] * t[1]) / (t[0] - t[1]); - - double inv0 = 1 / middle0->second.ClkStd * CLIGHT + EXTERR_CLK * fabs(t[0]); - double inv1 = 1 / middle1->second.ClkStd * CLIGHT + EXTERR_CLK * fabs(t[1]); - std = 1 / (inv0 + inv1); - } - else - { - dtSat = 0; - } - - if (varc) - *varc = SQR(std); - - return 1; -} - -/* satellite clock by precise clock ------------------------------------------*/ -int pephclk( - GTime time, - string id, - Navigation& nav, - double& dtSat, - double* varc) -{ -// BOOST_LOG_TRIVIAL(debug) -// << "pephclk : time=" << time.to_string(3) -// << " id=" << id; - - auto it = nav.pclkMap.find(id); - if (it == nav.pclkMap.end()) - { - return -1; - } - - auto& [key, pclkList] = *it; - - if ( (pclkList.size() < 2) - ||(time < pclkList.front(). time - MAXDTE) - ||(time > pclkList.back(). time + MAXDTE)) - { - BOOST_LOG_TRIVIAL(debug) - << "no prec clock " << time.to_string(0) - << " id=" << id; - - return -1; //non zero for pass, negative for no result - } - - //search for the ephemeris in the list - auto pclk_it = pclkList.begin(); - while (pclk_it->time < time) - { - pclk_it++; - if (pclk_it == pclkList.end()) - { - pclk_it--; - break; - } - } - auto middle1 = pclk_it; - auto middle0 = middle1; - if (middle0 != pclkList.begin()) - { - middle0--; - } - - /* linear interpolation for clock */ - double t[2]; - double c[2]; - t[0] = time - middle0->time; - t[1] = time - middle1->time; - c[0] = middle0->clk; - c[1] = middle1->clk; - - double std = 0; - - if (t[0] <= 0) - { - dtSat = c[0]; - - if (dtSat == 0) - return 0; - - std = middle0->std * CLIGHT + EXTERR_CLK * fabs(t[0]); - } - else if (t[1] >= 0) - { - dtSat = c[1]; - - if (dtSat == 0) - return 0; - - std = middle1->std * CLIGHT + EXTERR_CLK * fabs(t[1]); - } - else if ( c[0] != 0 - &&c[1] != 0) - { - dtSat = (c[1] * t[0] - c[0] * t[1]) / (t[0] - t[1]); - - double inv0 = 1 / middle0->std * CLIGHT + EXTERR_CLK * fabs(t[0]); - double inv1 = 1 / middle1->std * CLIGHT + EXTERR_CLK * fabs(t[1]); - std = 1 / (inv0 + inv1); - } - else - { - BOOST_LOG_TRIVIAL(debug) - << "prec clock outage " << time.to_string(0) - << " sat=" << id; - - return 0; - } - - if (varc) - *varc = SQR(std); - - return 1; -} - -/* satellite antenna phase center offset --------------------------------------- -* compute satellite antenna phase center offset in ecef -* args : gtime_t time I time (gpst) -* double *rs I satellite position and velocity (ecef) -* {x,y,z,vx,vy,vz} (m|m/s) -* double *dant I satellite antenna phase center offset (ecef) -* {dx,dy,dz} (m) (iono-free LC value) -*-----------------------------------------------------------------------------*/ -void satAntOff( - Trace& trace, - GTime time, - Vector3d& rSat, - SatSys& Sat, - map& lamMap, - Vector3d& dAnt, - SatStat* satStat_ptr) -{ - ERPValues erpv; - E_FType j = F1; - E_FType k = F2; - tracepdeex(4, trace, "%s: time=%s sat=%2d\n", __FUNCTION__, time.to_string(3).c_str() ,Sat); - - /* sun position in ecef */ - Vector3d rsun; - sunmoonpos(gpst2utc(time), erpv, &rsun); - - /* unit vectors of satellite fixed coordinates */ - Vector3d z = -rSat; Vector3d ez = z.normalized(); //todo aaron, this is probably everywhere - Vector3d s = rsun - rSat; Vector3d es = s.normalized(); - Vector3d y = ez.cross(es); Vector3d ey = y.normalized(); - Vector3d ex = ey.cross(ez); - - if (satStat_ptr) - { - auto& satStat = *satStat_ptr; - - satStat.sunDotSat = -es.dot(ez); - satStat.sunCrossSat = es.dot(ex); - } - - int sys = Sat.sys; - if ( sys == E_Sys::GAL - ||sys == E_Sys::SBS) - { - k = F5; - } - - /* WARNING: In principle there should be a - - if (sys == E_Sys::GPS && acsConfig.ionoOpts.iflc_freqs == +E_LinearCombo::L1L5_ONLY) k = F5; - - here, but (as of Nov. 2021) ANTEX files do not have the L5 antenna parameters for GPS */ - - if ( lamMap[j] == 0 - ||lamMap[k] == 0) - { - return; - } - - double gamma = SQR(lamMap[k]) / SQR(lamMap[j]); - double C1 = gamma / (gamma - 1); - double C2 = -1 / (gamma - 1); - - /* iono-free LC */ - Vector3d pcoJ = antPco(Sat.id(), Sat.sys, j, time); - Vector3d pcoK = antPco(Sat.id(), Sat.sys, k, time); - - for (int i = 0; i < 3; i++) - { - /* ENU to NEU */ - double dant1 = pcoJ[1] * ex(i) - + pcoJ[0] * ey(i) - + pcoJ[2] * ez(i); //todo aaron, matrix - - double dant2 = pcoK[1] * ex(i) - + pcoK[0] * ey(i) - + pcoK[2] * ez(i); - - dAnt(i) = C1 * dant1 - + C2 * dant2; - } -} - -Vector3d satAntOff( - Trace& trace, - GTime time, - Vector3d& rSat, - SatSys& Sat, - E_FType ft, - SatStat* satStat_ptr) -{ - tracepdeex(4, trace, "%s: time=%s\n", __FUNCTION__, time.to_string(3).c_str()); - - /* sun position in ecef */ - Vector3d rsun; - ERPValues erpv; - sunmoonpos(gpst2utc(time), erpv, &rsun); - - /* unit vectors of satellite fixed coordinates */ - Vector3d z = -rSat; Vector3d ez = z.normalized(); //todo aaron, this is probably everywhere - Vector3d s = rsun - rSat; Vector3d es = s.normalized(); - Vector3d y = ez.cross(es); Vector3d ey = y.normalized(); - Vector3d ex = ey.cross(ez); - - if (satStat_ptr) - { - auto& satStat = *satStat_ptr; - - satStat.sunDotSat = -es.dot(ez); - satStat.sunCrossSat = es.dot(ex); - } - - /* iono-free LC */ - Vector3d pco = antPco(Sat.id(), Sat.sys, ft, time); - - Vector3d dAnt; - - for (int i = 0; i < 3; i++) - { - /* ENU to NEU */ - dAnt(i) = pco[1] * ex(i) - + pco[0] * ey(i) - + pco[2] * ez(i); //todo aaron, matrix - } - - return dAnt; -} - -/* satellite position/clock by precise ephemeris/clock ------------------------- -* compute satellite position/clock with precise ephemeris/clock -* args : gtime_t time I time (gpst) -* int sat I satellite number -* nav_t *nav I navigation data -* int opt I sat postion option -* (0: center of mass, 1: antenna phase center) -* double *rs O sat position and velocity (ecef) -* {x,y,z,vx,vy,vz} (m|m/s) -* double *dts O sat clock {bias,drift} (s|s/s) -* double *var IO sat position and clock error variance (m) -* (nullptr: no output) -* return : pass */ -bool peph2pos( - Trace& trace, - GTime time, - SatSys& Sat, - Vector3d& rSat, - Vector3d& satVel, - double* dtSat, - double& ephVar, - E_Svh& svh, - Navigation& nav, - bool applyRelativity) -{ - double dtss1 = 0; - double dtss2 = 0; - double varPos = 0; - double varClk = 0; - - tracepdeex(4, trace, "%s: time=%s sat=%s\n", __FUNCTION__, time.to_string(3).c_str(), Sat.id().c_str()); - - svh = SVH_UNHEALTHY; - - /* satellite position and clock bias */ - if ( !pephpos(time, Sat, nav, rSat, dtss1, &varPos, &varClk) - ||!pephclk(time, Sat, nav, dtss2, &varClk)) - { - return false; - } - - if (dtss2 != 0) - { - double delta = dtss1 - dtss2; - dtss1 = dtss2; - } - - double tt = 1E-3; - time = time + tt; - - double dtst = 0; - Vector3d rSat2 = Vector3d::Zero(); - if ( !pephpos(time, Sat, nav, rSat2, dtst) - ||!pephclk(time, Sat, nav, dtst)) - { - return false; - } - - satVel = (rSat2 - rSat) / tt; - - if (dtss1 != 0) - { - double deltaDt = dtst - dtss1; - - dtSat[0] = dtss1; - dtSat[1] = deltaDt / tt; - - if (applyRelativity) - { - dtSat[0] -= relativity1(rSat, satVel); - } - } - else - { - /* no precise clock */ - dtSat[0] = 0; - dtSat[1] = 0; - } - - ephVar = varPos - + varClk; - -// printf("%14.6f %14.6f %14.6f\n", vare, varc, obs.var); - svh = SVH_OK; - return true; -} - -bool peph2pos( - Trace& trace, - GTime time, - SatSys& Sat, - Obs& obs, - Navigation& nav, - bool applyRelativity) -{ - return peph2pos(trace, time, Sat, obs.rSat, obs.satVel, obs.dtSat, obs.ephVar, obs.svh, nav, applyRelativity); -} - diff --git a/src/cpp/rtklib/rinex.cpp b/src/cpp/common/rinex.cpp similarity index 58% rename from src/cpp/rtklib/rinex.cpp rename to src/cpp/common/rinex.cpp index 985d7a7a2..b7b4bc82b 100644 --- a/src/cpp/rtklib/rinex.cpp +++ b/src/cpp/common/rinex.cpp @@ -1,4 +1,6 @@ +// #pragma GCC optimize ("O0") + #include @@ -8,7 +10,6 @@ using std::string; #include "rinexNavWrite.hpp" -#include "streamTrace.hpp" #include "navigation.hpp" #include "biasSINEX.hpp" #include "constants.hpp" @@ -16,6 +17,7 @@ using std::string; #include "common.hpp" #include "gTime.hpp" #include "rinex.hpp" +#include "trace.hpp" #include "enum.h" #define MAXRNXLEN (16*MAXOBSTYPE+4) ///< max rinex record length @@ -23,12 +25,6 @@ using std::string; #define MINFREQ_GLO -7 ///< min frequency number glonass #define MAXFREQ_GLO 13 ///< max frequency number glonass -const double ura_eph[]= -{ - ///< ura values (ref [3] 20.3.3.3.1.1) - 2.4, 3.4, 4.85, 6.85, 9.65, 13.65, 24, 48, 96, 192, 384, 768, 1536, 3072, 6144, 0 -}; - BETTER_ENUM(E_EphType, short int, NONE, ///< NONE for unknown EPH, ///< GPS/QZS LNAV, GAL IFNV, BDS D1D2 Ephemeris @@ -63,233 +59,78 @@ void setstr(char *dst, const char *src, int n) while (p>=dst&&*p==' ') *p--='\0'; } -/** Adjust time considering week handover -*/ -GTime adjweek(GTime t, GTime t0) -{ - double tt = t - t0; - if (tt < -302400) return t + 604800.0; - if (tt > +302400) return t - 604800.0; - return t; -} - -/** Adjust time considering day handover -*/ -GTime adjday(GTime t, GTime t0) -{ - double tt = t - t0; - if (tt < -43200.0) return t + 86400.0; - if (tt > +43200.0) return t - 86400.0; - return t; -} - -/** URA value (m) to ura index -*/ -int uraindex(double value) -{ - int index; - for (index = 0; index < 15; index++) - if (ura_eph[index] >= value) - break; - return index; -} - - - -/** Convert rinex obs type ver.2 -> ver.3 -*/ -void convcode( - double ver, - int sys, - const char* str, - char* type) -{ - strcpy(type," "); - - if (!strcmp(str,"P1")) - { - // ver.2.11 GPS L1PY,GLO L2P - if (sys==+E_Sys::GPS) sprintf(type,"%c1W",'C'); - else if (sys==+E_Sys::GLO) sprintf(type,"%c1P",'C'); - } - else if (!strcmp(str,"P2")) - { - // ver.2.11 GPS L2PY,GLO L2P - if (sys==+E_Sys::GPS) sprintf(type,"%c2W",'C'); - else if (sys==+E_Sys::GLO) sprintf(type,"%c2P",'C'); - } - else if (!strcmp(str,"C1")) - { - // ver.2.11 GPS L1C,GLO L1C/A - if (ver>=2.12) ; // reject C1 for 2.12 - else if (sys==+E_Sys::GPS) sprintf(type,"%c1C",'C'); - else if (sys==+E_Sys::GLO) sprintf(type,"%c1C",'C'); - else if (sys==+E_Sys::GAL) sprintf(type,"%c1X",'C'); // ver.2.12 - else if (sys==+E_Sys::QZS) sprintf(type,"%c1C",'C'); - else if (sys==+E_Sys::SBS) sprintf(type,"%c1C",'C'); - } - else if (!strcmp(str,"C2")) - { - if (sys==+E_Sys::GPS) - { - if (ver>=2.12) sprintf(type,"%c2W",'C'); // L2P(Y) - else sprintf(type,"%c2X",'C'); // L2C - } - else if (sys==+E_Sys::GLO) sprintf(type,"%c2C",'C'); - else if (sys==+E_Sys::QZS) sprintf(type,"%c2X",'C'); - else if (sys==+E_Sys::BDS) sprintf(type,"%c1X",'C'); // ver.2.12 B1 - } - else if (ver>=2.12&&str[1]=='A') - { - // ver.2.12 L1C/A - if (sys==+E_Sys::GPS) sprintf(type,"%c1C",str[0]); - else if (sys==+E_Sys::GLO) sprintf(type,"%c1C",str[0]); - else if (sys==+E_Sys::QZS) sprintf(type,"%c1C",str[0]); - else if (sys==+E_Sys::SBS) sprintf(type,"%c1C",str[0]); - } - else if (ver>=2.12&&str[1]=='B') - { - // ver.2.12 GPS L1C - if (sys==+E_Sys::GPS) sprintf(type,"%c1X",str[0]); - else if (sys==+E_Sys::QZS) sprintf(type,"%c1X",str[0]); - } - else if (ver>=2.12&&str[1]=='C') - { - // ver.2.12 GPS L2C - if (sys==+E_Sys::GPS) sprintf(type,"%c2X",str[0]); - else if (sys==+E_Sys::QZS) sprintf(type,"%c2X",str[0]); - } - else if (ver>=2.12&&str[1]=='D') - { - // ver.2.12 GLO L2C/A - if (sys==+E_Sys::GLO) sprintf(type,"%c2C",str[0]); - } - else if (ver>=2.12&&str[1]=='1') - { - // ver.2.12 GPS L1PY,GLO L1P - if (sys==+E_Sys::GPS) sprintf(type,"%c1W",str[0]); - else if (sys==+E_Sys::GLO) sprintf(type,"%c1P",str[0]); - else if (sys==+E_Sys::GAL) sprintf(type,"%c1X",str[0]); // tentative - else if (sys==+E_Sys::BDS) sprintf(type,"%c1X",str[0]); // extension - } - else if (ver<2.12&&str[1]=='1') - { - if (sys==+E_Sys::GPS) sprintf(type,"%c1C",str[0]); - else if (sys==+E_Sys::GLO) sprintf(type,"%c1C",str[0]); - else if (sys==+E_Sys::GAL) sprintf(type,"%c1X",str[0]); // tentative - else if (sys==+E_Sys::QZS) sprintf(type,"%c1C",str[0]); - else if (sys==+E_Sys::SBS) sprintf(type,"%c1C",str[0]); - } - else if (str[1]=='2') - { - if (sys==+E_Sys::GPS) sprintf(type,"%c2W",str[0]); - else if (sys==+E_Sys::GLO) sprintf(type,"%c2P",str[0]); - else if (sys==+E_Sys::QZS) sprintf(type,"%c2X",str[0]); - else if (sys==+E_Sys::BDS) sprintf(type,"%c1X",str[0]); // ver.2.12 B1 - } - else if (str[1]=='5') - { - if (sys==+E_Sys::GPS) sprintf(type,"%c5X",str[0]); - else if (sys==+E_Sys::GAL) sprintf(type,"%c5X",str[0]); - else if (sys==+E_Sys::QZS) sprintf(type,"%c5X",str[0]); - else if (sys==+E_Sys::SBS) sprintf(type,"%c5X",str[0]); - } - else if (str[1]=='6') - { - if (sys==+E_Sys::GAL) sprintf(type,"%c6X",str[0]); - else if (sys==+E_Sys::QZS) sprintf(type,"%c6X",str[0]); - else if (sys==+E_Sys::BDS) sprintf(type,"%c6X",str[0]); // ver.2.12 B3 - } - else if (str[1]=='7') - { - if (sys==+E_Sys::GAL) sprintf(type,"%c7X",str[0]); - else if (sys==+E_Sys::BDS) sprintf(type,"%c7X",str[0]); // ver.2.12 B2 - } - else if (str[1]=='8') - { - if (sys==+E_Sys::GAL) sprintf(type,"%c8X",str[0]); - } - - BOOST_LOG_TRIVIAL(debug) - << "convcode: ver=" << ver - << " sys=" << sys - << " type= " << str - << " -> " << type; -} - - /** Decode obs header */ -void decodeObsh( +void decodeObsH( std::istream& inputStream, string& line, double ver, - int& tsys, - map>& sysCodeTypes, + E_TimeSys& tsys, + map>& sysCodeTypes, Navigation& nav, - RinexStation* sta) + RinexStation* rec) { double del[3]; - int n,prn,fcn; + int prn,fcn; const char *p; char* buff = &line[0]; char* label = buff+60; - -// BOOST_LOG_TRIVIAL(debug) -// << "decodeObsh: ver=" << ver; + auto& recOpts = acsConfig.getRecOpts(rec->id); + +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ver=" << ver; if (strstr(label,"MARKER NAME" )) { - if (sta) + if (rec) { - sta->id .assign(buff, 60); + rec->id .assign(buff, 60); } } else if (strstr(label,"MARKER NUMBER" )) { - if (sta) + if (rec) { - sta->marker .assign(buff, 20); + rec->marker .assign(buff, 20); } } // else if (strstr(label,"MARKER TYPE" )) ; // ver.3 // else if (strstr(label,"OBSERVER / AGENCY" )) ; else if (strstr(label,"REC # / TYPE / VERS" )) { - if (sta) + if (rec) { - sta->recSerial .assign(buff, 20); - sta->recType .assign(buff+20, 20); - sta->recFWVersion .assign(buff+40, 20); + rec->recSerial .assign(buff, 20); + rec->recType .assign(buff+20, 20); + rec->recFWVersion .assign(buff+40, 20); } } else if (strstr(label,"ANT # / TYPE" )) { - if (sta) + if (rec) { - sta->antSerial .assign(buff, 20); - sta->antDesc .assign(buff+20, 20); + rec->antSerial .assign(buff, 20); + rec->antDesc .assign(buff+20, 20); } } else if (strstr(label,"APPROX POSITION XYZ" )) { - if (sta) + if (rec) { for (int i = 0, j = 0; i<3 ; i++, j += 14) - sta->pos[i] = str2num(buff,j,14); + rec->pos[i] = str2num(buff,j,14); } } else if (strstr(label,"ANTENNA: DELTA H/E/N")) { - if (sta) + if (rec) { for (int i = 0, j = 0; i < 3; i++, j += 14) del[i] = str2num(buff,j,14); - sta->del[2] = del[0]; // h - sta->del[0] = del[1]; // e - sta->del[1] = del[2]; // n + rec->del[2] = del[0]; // h + rec->del[0] = del[1]; // e + rec->del[1] = del[2]; // n } } // else if (strstr(label,"ANTENNA: DELTA X/Y/Z")) ; // opt ver.3 @@ -315,7 +156,7 @@ void decodeObsh( return; } - n = (int) str2num(buff, 3, 3); + int n = (int) str2num(buff, 3, 3); for (int j = 0, k = 7; j < n; j++, k += 4) { @@ -337,10 +178,11 @@ void decodeObsh( code[1] = buff[k+1]; code[2] = buff[k+2]; if ( (Sat.sys == +E_Sys::BDS) - &&(code[1] == '2')) + &&(code[1] == '1') + &&(ver == 3.02)) { // change beidou B1 code: 3.02 draft -> 3.02 - code[1] = '1'; + code[1] = '2'; } try { @@ -352,7 +194,7 @@ void decodeObsh( << "invalid obs code: " << code; } - sysCodeTypes[Sat.sys].push_back(codeType); + sysCodeTypes[Sat.sys][j] = codeType; } // if unknown code in ver.3, set default code @@ -382,44 +224,71 @@ void decodeObsh( // } } // else if (strstr(label,"WAVELENGTH FACT L1/2")) ; // opt ver.2 -// else if (strstr(label,"# / TYPES OF OBSERV" )) -// { // ver.2 -// n=(int)str2num(buff,0,6); -// for (i=nt=0,j=10;i58) -// { -// if (!fgets(buff,MAXRNXLEN,fp)) -// break; -// j=10; -// } -// -// if (nt>=MAXOBSTYPE-1) -// continue; -// -// if (ver<=2.99) -// { -// setstr(str,buff+j,2); -// convcode(ver,E_Sys::GPS,str,tobs[0][nt]); -// convcode(ver,E_Sys::GLO,str,tobs[1][nt]); -// convcode(ver,E_Sys::GAL,str,tobs[2][nt]); -// convcode(ver,E_Sys::QZS,str,tobs[3][nt]); -// convcode(ver,E_Sys::SBS,str,tobs[4][nt]); -// convcode(ver,E_Sys::BDS,str,tobs[5][nt]); -// } -// nt++; -// } -// *tobs[0][nt]='\0'; -// } + else if (strstr(label,"# / TYPES OF OBSERV" )) + { + // ver.2 + + int n = (int)str2num(buff,0,6); + + for (int i = 0, j = 10; i < n; i++, j+=6) + { + if (j > 58) + { + //go onto new line + if (!std::getline(inputStream, line)) + break; + + buff = (char*) line.c_str(); + + j = 10; + } + + if (ver <= 2.99) + { + char obsCode2str[3] = {}; + setstr(obsCode2str, buff + j, 2); + + //save the type char before cleaning the string + char typeChar = obsCode2str[0]; + + for (E_Sys sys : E_Sys::_values()) + { + map* conversionMap_ptr; + if ( typeChar != 'C' + &&typeChar != 'P') + { + obsCode2str[0] = 'L'; + conversionMap_ptr = &recOpts.rinex23Conv.phasConv[sys]; // ie use Phase Conversions for phase, doppler etc. + } + else + { + conversionMap_ptr = &recOpts.rinex23Conv.codeConv[sys]; + } + + auto& conversionMap = *conversionMap_ptr; + + CodeType codeType; + E_ObsCode2 obsCode2 = E_ObsCode2::_from_string(obsCode2str); + E_ObsCode obsCode = conversionMap[obsCode2]; + + codeType.code = obsCode; + codeType.type = typeChar; + + sysCodeTypes[sys][i] = codeType; + } + } + } + //*tobs[0][nt]='\0'; + } // else if (strstr(label,"SIGNAL STRENGTH UNIT")) ; // opt ver.3 // else if (strstr(label,"INTERVAL" )) ; // opt else if (strstr(label,"TIME OF FIRST OBS" )) { - if (!strncmp(buff+48,"GPS",3)) tsys=TSYS_GPS; - else if (!strncmp(buff+48,"GLO",3)) tsys=TSYS_UTC; - else if (!strncmp(buff+48,"GAL",3)) tsys=TSYS_GAL; - else if (!strncmp(buff+48,"QZS",3)) tsys=TSYS_QZS; // ver.3.02 - else if (!strncmp(buff+48,"BDT",3)) tsys=TSYS_CMP; // ver.3.02 + if (!strncmp(buff+48, "GPS", 3)) tsys = E_TimeSys::GPST; + else if (!strncmp(buff+48, "GLO", 3)) tsys = E_TimeSys::UTC; + else if (!strncmp(buff+48, "GAL", 3)) tsys = E_TimeSys::GST; + else if (!strncmp(buff+48, "QZS", 3)) tsys = E_TimeSys::QZSST; // ver.3.02 + else if (!strncmp(buff+48, "BDT", 3)) tsys = E_TimeSys::BDT; // ver.3.02 } // else if (strstr(label,"TIME OF LAST OBS" )) ; // opt // else if (strstr(label,"RCV CLOCK OFFS APPL" )) ; // opt @@ -433,11 +302,11 @@ void decodeObsh( p = buff + 4; for (int i = 0; i < 8; i++, p += 8) { - if (sscanf(p,"R%2d %2d",&prn,&fcn)<2) + if (sscanf(p,"R%2d %2d", &prn, &fcn) < 2) continue; if (1 <= prn - &&prn <= MAXPRNGLO) + &&prn <= NSATGLO) { nav.glo_fcn[prn-1] = fcn+8; } @@ -458,7 +327,7 @@ void decodeObsh( } else if (strstr(label,"LEAP SECONDS" )) { - // opt + // This would be GPS-UTC, and NOT optional as of RINEX 4 nav.leaps=(int)str2num(buff,0,6); } // else if (strstr(label,"# OF SALTELLITES" )) ; // opt @@ -467,7 +336,7 @@ void decodeObsh( /** Decode nav header */ -void decodeNavh( +void decodeNavH( string& line, ///< Line to decode E_Sys sys, ///< GNSS system Navigation& nav) ///< Navigation data @@ -475,10 +344,9 @@ void decodeNavh( char* buff = &line[0]; char* label = buff + 60; - BOOST_LOG_TRIVIAL(debug) - << "decodeNavh:"; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__; - if (strstr(label,"ION ALPHA" )) + if (strstr(label,"ION ALPHA" )) { // opt ver.2 E_NavMsgType type = defNavMsgType[sys]; @@ -520,9 +388,9 @@ void decodeNavh( case E_Sys::GAL: code = E_StoCode::GAUT; break; } - double sec = str2num(buff,31,9); - double week = str2num(buff,40,9); - GTime time = gpst2time(week, sec); + GTow tow = str2num(buff,31,9); + GWeek week = (int) str2num(buff,40,9); + GTime time(week, tow); STO& stoEntry = nav.stoMap[code][type][time]; @@ -595,8 +463,8 @@ void decodeNavh( double sec = str2num(buff,38, 7); double week = str2num(buff,45, 5); GTime time = {}; - if (Sat.sys == +E_Sys::BDS) { time = bdt2gpst( bdt2time(week, sec)); } - else { time = gpst2time(week, sec); } + if (Sat.sys != +E_Sys::BDS) { time = GTime(GWeek(week), GTow(sec)); } + else { time = GTime(BWeek(week), BTow(sec)); } STO& stoEntry = nav.stoMap[code][type][time]; @@ -618,15 +486,14 @@ void decodeNavh( } /** Decode gnav header */ -void decodeGnavh( +void decodeGnavH( string& line, Navigation& nav) { char* buff = &line[0]; char* label = buff + 60; - BOOST_LOG_TRIVIAL(debug) - << "decodeGnavh:"; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__; if (strstr(label,"CORR TO SYTEM TIME" )) ; // opt else if (strstr(label,"LEAP SECONDS" )) @@ -638,15 +505,14 @@ void decodeGnavh( /** Decode geo nav header */ -void decodeHnavh( +void decodeHnavH( string& line, Navigation& nav) { char* buff = &line[0]; char* label = buff + 60; - BOOST_LOG_TRIVIAL(debug) - << "decodeHnavh:"; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__; if (strstr(label, "CORR TO SYTEM TIME" )) ; // opt else if (strstr(label, "D-UTC A0,A1,T,W,S,U" )) ; // opt @@ -659,31 +525,30 @@ void decodeHnavh( /** Read rinex header */ -int readrnxh( +int readRnxH( std::istream& inputStream, double& ver, char& type, E_Sys& sys, - int& tsys, - map>& sysCodeTypes, + E_TimeSys& tsys, + map>& sysCodeTypes, Navigation& nav, - RinexStation* sta) + RinexStation* rec) { string line; int i = 0; int block = 0; -// BOOST_LOG_TRIVIAL(debug) -// << "readrnxh:"; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__; ver = 2.10; type = ' '; sys = E_Sys::GPS; - tsys = TSYS_GPS; + tsys = E_TimeSys::GPST; char sysChar = '\0'; - int typeOffset = 20; - int sysCharOffset = 40; + int typeOffset = 20; + int sysCharOffset = 40; while (std::getline(inputStream, line)) { @@ -691,7 +556,9 @@ int readrnxh( char* label = buff + 60; if (line.length() <= 60) + { continue; + } else if (strstr(label,"RINEX VERSION / TYPE")) { ver = str2num(buff,0,9); @@ -708,20 +575,19 @@ int readrnxh( type = buff[typeOffset]; sysChar = buff[sysCharOffset]; - } // satellite system switch (sysChar) { case ' ': - case 'G': sys = E_Sys::GPS; tsys = TSYS_GPS; break; - case 'R': sys = E_Sys::GLO; tsys = TSYS_UTC; break; - case 'E': sys = E_Sys::GAL; tsys = TSYS_GAL; break; // v.2.12 - case 'S': sys = E_Sys::SBS; tsys = TSYS_GPS; break; - case 'J': sys = E_Sys::QZS; tsys = TSYS_QZS; break; // v.3.02 - case 'C': sys = E_Sys::BDS; tsys = TSYS_CMP; break; // v.2.12 - case 'M': sys = E_Sys::NONE; tsys = TSYS_GPS; break; // mixed + case 'G': sys = E_Sys::GPS; tsys = E_TimeSys::GPST; break; + case 'R': sys = E_Sys::GLO; tsys = E_TimeSys::UTC; break; + case 'E': sys = E_Sys::GAL; tsys = E_TimeSys::GST; break; // v.2.12 + case 'S': sys = E_Sys::SBS; tsys = E_TimeSys::GPST; break; + case 'J': sys = E_Sys::QZS; tsys = E_TimeSys::QZSST; break; // v.3.02 + case 'C': sys = E_Sys::BDS; tsys = E_TimeSys::BDT; break; // v.2.12 + case 'M': sys = E_Sys::NONE; tsys = E_TimeSys::GPST; break; // mixed default : BOOST_LOG_TRIVIAL(debug) << "unsupported satellite system: " << sysChar; @@ -733,27 +599,65 @@ int readrnxh( else if (strstr(label,"PGM / RUN BY / DATE")) continue; else if (strstr(label,"COMMENT")) - { // opt - + { // read cnes wl satellite fractional bias if ( strstr(buff,"WIDELANE SATELLITE FRACTIONAL BIASES") ||strstr(buff,"WIDELANE SATELLITE FRACTIONNAL BIASES")) { block=1; } + if (strstr(buff,"->")) + { + //may be a conversion line, test + + char sysChar; + char r3[4] = {}; + char r2[3] = {}; + char comment[81]; + int num = sscanf(buff, " %c %3c -> %2c %80s", &sysChar, r3, r2, comment); + + + if ( num == 4 + &&(string)comment == "COMMENT") + { + try + { + E_Sys sys = SatSys::sysFromChar(sysChar); + + char code = r3[0]; + r3[0] = 'L'; + auto obs2 = E_ObsCode2 ::_from_string_nocase(r2); + auto obs3 = E_ObsCode ::_from_string_nocase(r3); + + auto& recOpts = acsConfig.getRecOpts(rec->id); + + auto& codeMap = recOpts.rinex23Conv.codeConv[sys]; + auto& phasMap = recOpts.rinex23Conv.phasConv[sys]; + + if (r2[0] == 'C' || r2[0] == 'P') codeMap[obs2] = obs3; + else phasMap[obs2] = obs3; + } + catch (...) + { + + } + } + } else if (block) { double bias; SatSys Sat; // cnes/cls grg clock - if (!strncmp(buff,"WL",2)&&(Sat=SatSys(buff+3), Sat)&& - sscanf(buff+40,"%lf",&bias)==1) + if ( !strncmp(buff,"WL",2) + &&(Sat = SatSys(buff+3), Sat) + && sscanf(buff+40,"%lf", &bias) == 1) { nav.satNavMap[Sat].wlbias = bias; } // cnes ppp-wizard clock - else if ((Sat=SatSys(buff+1), Sat)&&sscanf(buff+6,"%lf",&bias)==1) + else if ((Sat = SatSys(buff+1), Sat) + &&sscanf(buff+6,"%lf",&bias) == 1) { nav.satNavMap[Sat].wlbias = bias; } @@ -763,13 +667,13 @@ int readrnxh( // file type switch (type) { - case 'O': decodeObsh(inputStream, line, ver, tsys, sysCodeTypes, nav, sta); break; - case 'N': decodeNavh ( line, sys, nav); break; // GPS (ver.2) or mixed (ver.3) - case 'G': decodeGnavh ( line, nav); break; - case 'H': decodeHnavh ( line, nav); break; - case 'J': decodeNavh ( line, E_Sys::QZS, nav); break; // extension - case 'E': - case 'L': decodeNavh ( line, E_Sys::GAL, nav); break; // extension + case 'O': decodeObsH(inputStream, line, ver, tsys, sysCodeTypes, nav, rec); break; + case 'N': decodeNavH ( line, sys, nav); break; // GPS (ver.2) or mixed (ver.3) + case 'G': decodeGnavH ( line, nav); break; + case 'H': decodeHnavH ( line, nav); break; + case 'J': decodeNavH ( line, E_Sys::QZS, nav); break; // extension + case 'E': //fallthrough + case 'L': decodeNavH ( line, E_Sys::GAL, nav); break; // extension } if (strstr(label,"END OF HEADER")) return 1; @@ -784,21 +688,18 @@ int readrnxh( } /** Decode obs epoch */ -int decodeObsepoch( +int decodeObsEpoch( std::istream& inputStream, string& line, double ver, GTime& time, int& flag, vector& sats) - { - int n; - char* buff = &line[0]; + int n = 0; + char* buff = &line[0]; - -// BOOST_LOG_TRIVIAL(debug) -// << "decodeObsepoch: ver=" << ver; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ver=" << ver; if (ver <= 2.99) { @@ -816,10 +717,12 @@ int decodeObsepoch( return n; } - if (str2time(buff, 0, 26, time)) + bool error = str2time(buff, 0, 26, time); + if (error) { BOOST_LOG_TRIVIAL(debug) << "rinex obs invalid epoch: epoch=" << buff; + return 0; } @@ -835,8 +738,10 @@ int decodeObsepoch( j = 32; } - - sats.push_back(SatSys(buff + j)); + + char id[4] = {}; + strncpy(id, buff + j, 3); + sats.push_back(SatSys(id)); } } else @@ -864,7 +769,7 @@ int decodeObsepoch( } // BOOST_LOG_TRIVIAL(debug) -// << "decodeObsepoch: time=" << time.to_string(3) +// << "__FUNCTION__: time=" << time.to_string(3) // << " flag=" << flag; return n; @@ -872,21 +777,19 @@ int decodeObsepoch( /** Decode obs data */ -int decodeObsdata( +int decodeObsData( std::istream& inputStream, string& line, double ver, - map>& sysCodeTypes, - RawObs& obs, - SatSys& v2SatSys_ptr) + map>& sysCodeTypes, + GObs& obs, + SatSys& v2SatSys) { char satid[8] = ""; int stat = 1; char* buff = &line[0]; - -// BOOST_LOG_TRIVIAL(debug) -// << "decodeObsdata: ver=" << ver; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ver=" << ver; if (ver > 2.99) { @@ -896,7 +799,7 @@ int decodeObsdata( } else { - obs.Sat = v2SatSys_ptr; + obs.Sat = v2SatSys; } if (!obs.Sat) @@ -907,7 +810,7 @@ int decodeObsdata( stat = 0; } - vector& codeTypes = sysCodeTypes[obs.Sat.sys]; + auto& codeTypes = sysCodeTypes[obs.Sat.sys]; int j; if (ver <= 2.99) j = 0; @@ -916,22 +819,23 @@ int decodeObsdata( if (!stat) return 0; - for (auto& codeType : codeTypes) + for (auto& [index, codeType] : codeTypes) { -// if ( ver <= 2.99 -// &&j >= 80) -// { -// // ver.2 -// if (!fgets(buff,MAXRNXLEN,fp)) -// break; -// j = 0; -// } + if ( ver <= 2.99 + &&j >= 80) + { + // ver.2 + if (!std::getline(inputStream, line)) + break; + buff = &line[0]; + j = 0; + } - E_FType ft = ftypes[codeType.code]; + E_FType ft = code2Freq[obs.Sat.sys][codeType.code]; RawSig* rawSig = nullptr; - list& sigList = obs.SigsLists[ft]; - + auto& sigList = obs.SigsLists[ft]; + for (auto& sig : sigList) { if (sig.code == codeType.code) @@ -940,6 +844,7 @@ int decodeObsdata( break; } } + if (rawSig == nullptr) { RawSig raw; @@ -949,26 +854,26 @@ int decodeObsdata( rawSig = &sigList.back(); } - double val = str2num(buff, j, 14); double lli = str2num(buff, j+14, 1); lli = (unsigned char) lli & 0x03; - -// val += shift;// todo aaron, phase shift needed + RawSig& sig = *rawSig; + if (val) switch (codeType.type) { + case 'P': //fallthrough case 'C': sig.P = val; break; case 'L': sig.L = val; sig.LLI = lli; break; case 'D': sig.D = val; break; - case 'S': sig.snr = val * 4 + 0.5; break; + case 'S': sig.snr = val; break; } j += 16; } // BOOST_LOG_TRIVIAL(debug) -// << "decodeObsdata: time=" << obs.time.to_string(0) +// << "decodeObsdata: time=" << obs.time.to_string() // << " sat=" << obs.Sat.id(); return 1; @@ -976,48 +881,57 @@ int decodeObsdata( /** Read rinex obs data body */ -int readrnxobsb( +int readRnxObsB( std::istream& inputStream, double ver, - map>& sysCodeTypes, + map>& sysCodeTypes, int& flag, ObsList& obsList) { - GTime time = {}; - string line; + GTime time = {}; int i = 0; + int nSats = 0; //cant replace with sats.size() vector sats; - int nSats = 0; //cant replace with sats.size() // read record - while (std::getline(inputStream, line)) + string line; + std::streampos pos; + while (pos = inputStream.tellg(), std::getline(inputStream, line)) { // decode obs epoch if (i == 0) { - nSats = decodeObsepoch(inputStream, line, ver, time, flag, sats); + nSats = decodeObsEpoch(inputStream, line, ver, time, flag, sats); if (nSats <= 0) { continue; } } + else if (line[0] == '>') + { + BOOST_LOG_TRIVIAL(warning) << "Warning: unexpected end of epoch in rinex file at " << time; + inputStream.seekg(pos); + return obsList.size(); + } else if ( flag <= 2 ||flag == 6) { - RawObs rawObs = {}; + GObs rawObs = {}; rawObs.time = time; // decode obs data - bool pass = decodeObsdata(inputStream, line, ver, sysCodeTypes, rawObs, sats[i]); + bool pass = decodeObsData(inputStream, line, ver, sysCodeTypes, rawObs, sats[i-1]); if (pass) { // save obs data - obsList.push_back(rawObs); + obsList.push_back((shared_ptr)rawObs); } } - if (++i > nSats) + i++; + + if (i > nSats) return obsList.size(); } @@ -1026,53 +940,50 @@ int readrnxobsb( /** Read rinex obs */ -int readrnxobs( +int readRnxObs( std::istream& inputStream, double ver, - int tsys, - map>& sysCodeTypes, - ObsList& obsList) + E_TimeSys tsys, + map>& sysCodeTypes, + ObsList& obsList, + RinexStation* sta) { int flag = 0; int stat = 0; -// BOOST_LOG_TRIVIAL(debug) -// << "readrnxobs: ver=" << ver << " tsys=" << tsys; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ver=" << ver << " tsys=" << tsys; // read rinex obs data body - int n = readrnxobsb(inputStream, ver, sysCodeTypes, flag, obsList); + int n = readRnxObsB(inputStream, ver, sysCodeTypes, flag, obsList); if ( n >= 0 &&stat >= 0) { - for (auto& obs : obsList) + if (tsys == +E_TimeSys::UTC) + for (auto& obs : only(obsList)) { - // utc -> gpst - if (tsys == TSYS_UTC) - obs.time = utc2gpst(obs.time); + UtcTime utcTime; + utcTime.bigTime = obs.time.bigTime; + + obs.time = utcTime; } stat = 1; } -// BOOST_LOG_TRIVIAL(debug) -// << "readrnxobs: nobs=" << obsList.size() -// << " stat=" << stat; - return stat; } /** Decode ephemeris */ int decodeEph( - double ver, - SatSys Sat, - GTime toc, - double* data, - Eph& eph) + double ver, + SatSys Sat, + GTime toc, + vector& data, + Eph& eph) { -// BOOST_LOG_TRIVIAL(debug) -// << "decodeEph: ver=" << ver << " sat=" << Sat.id(); +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ver=" << ver << " sat=" << Sat.id(); int sys = Sat.sys; @@ -1086,9 +997,10 @@ int decodeEph( return 0; } - eph.type=defNavMsgType[Sat.sys]; - eph.Sat=Sat; - eph.toc=toc; + + eph.type = defNavMsgType[Sat.sys]; + eph.Sat = Sat; + eph.toc = toc; eph.f0 = data[0]; eph.f1 = data[1]; @@ -1112,33 +1024,35 @@ int decodeEph( if ( sys == +E_Sys::GPS ||sys == +E_Sys::QZS) { - eph.iode=(int)data[ 3]; // IODE - eph.iodc=(int)data[26]; // IODC - eph.toes= data[11]; // toe (s) in gps week - eph.week=(int)data[21]; // gps week - eph.toe=adjweek(gpst2time(eph.week,data[11]),eph.toc); - eph.ttm=adjweek(gpst2time(eph.week,data[27]),eph.toc); + eph.iode =(int)data[ 3]; // IODE + eph.iodc =(int)data[26]; // IODC + eph.toes = data[11]; // toe (s) in gps week + eph.week =(int)data[21]; // gps week + eph.toe = GTime((GTow)GTime(GWeek(eph.week), GTow(data[11])), eph.toc); + eph.ttm = GTime((GTow)GTime(GWeek(eph.week), GTow(data[27])), eph.toc); - eph.code=(int)data[20]; // GPS: codes on L2 ch - eph.svh =(E_Svh)data[24]; // sv health - eph.sva=uraindex(data[23]); // ura (m->index) - eph.flag=(int)data[22]; // GPS: L2 P data flag + eph.code =(int) data[20]; // GPS: codes on L2 ch + eph.svh =(E_Svh) data[24]; // sv health + eph.sva =uraToSva( data[23]); // ura (m->index) + eph.flag =(int) data[22]; // GPS: L2 P data flag - eph.tgd[0]= data[25]; // TGD - eph.fit = data[28]; // fit interval + eph.tgd[0] = data[25]; // TGD + + if (sys == +E_Sys::GPS) { eph.fit = data[28]; } // fit interval in hours for GPS + else if (sys == +E_Sys::QZS) { eph.fitFlag = data[28]; eph.fit = eph.fitFlag?0.0:2.0; } // fit interval flag for QZS decomposeTGDBias(Sat, eph.tgd[0]); } else if (sys==+E_Sys::GAL) { // GAL ver.3 - eph.iode=(int)data[ 3]; // IODnav - eph.toes= data[11]; // toe (s) in galileo week - eph.week=(int)data[21]; // gal week = gps week - eph.toe=adjweek(gpst2time(eph.week,data[11]),eph.toc); - eph.ttm=adjweek(gpst2time(eph.week,data[27]),eph.toc); + eph.iode =(int)data[ 3]; // IODnav + eph.toes = data[11]; // toe (s) in galileo week + eph.week =(int)data[21]; // gal week = gps week + eph.toe = GTime((GTow)GTime(GWeek(eph.week), GTow(data[11])), eph.toc); + eph.ttm = GTime((GTow)GTime(GWeek(eph.week), GTow(data[27])), eph.toc); - eph.code=(int)data[20]; // data sources + eph.code=(int)data[20]; // data sources // bit 0 set: I/NAV E1-B // bit 1 set: F/NAV E5a-I // bit 2 set: I/NAV E5b-I @@ -1146,10 +1060,10 @@ int decodeEph( // bit 9 set: af0-af2 toc are for E5b.E1 unsigned short iNavMask = 0x0005; unsigned short fNavMask = 0x0002; - if (eph.code & iNavMask) eph.type=E_NavMsgType::INAV; - else if (eph.code & fNavMask) eph.type=E_NavMsgType::FNAV; + if (eph.code & iNavMask) eph.type = E_NavMsgType::INAV; + else if (eph.code & fNavMask) eph.type = E_NavMsgType::FNAV; - eph.svh =(E_Svh)data[24]; // sv health + eph.svh =(E_Svh)data[24]; // sv health // bit 0: E1B DVS // bit 1-2: E1B HS // bit 3: E5a DVS @@ -1157,43 +1071,44 @@ int decodeEph( // bit 6: E5b DVS // bit 7-8: E5b HS eph.sva = sisaToSva(data[23]); - //eph.sva =uraindex(data[23]); // ura (m->index) - - eph.tgd[0]= data[25]; // BGD E5a/E1 - eph.tgd[1]= data[26]; // BGD E5b/E1 + + eph.tgd[0]= data[25]; // BGD E5a/E1 + eph.tgd[1]= data[26]; // BGD E5b/E1 decomposeBGDBias(Sat, eph.tgd[0], eph.tgd[1]); } else if (sys==+E_Sys::BDS) { // BeiDou v.3.02 - if (Sat.prn>5&&Sat.prn<59) eph.type=E_NavMsgType::D1; // MEO/IGSO - else eph.type=E_NavMsgType::D2; // GEO, prn range may change in the future*/ - - eph.toc=bdt2gpst(eph.toc); // bdt -> gpst - eph.iode=(int)data[ 3]; // AODE - eph.iodc=(int)data[28]; // AODC - eph.toes= data[11]; // toe (s) in bdt week - eph.week=(int)data[21]; // bdt week - eph.toe=bdt2gpst(bdt2time(eph.week,data[11])); // bdt -> gpst - eph.ttm=bdt2gpst(bdt2time(eph.week,data[27])); // bdt -> gpst - eph.toe=adjweek(eph.toe,eph.toc); - eph.ttm=adjweek(eph.ttm,eph.toc); - - eph.svh =(E_Svh)data[24]; // satH1 - eph.sva=uraindex(data[23]); // ura (m->index) - - eph.tgd[0]= data[25]; // TGD1 B1/B3 - eph.tgd[1]= data[26]; // TGD2 B2/B3 + if (Sat.prn>5&&Sat.prn<59) eph.type = E_NavMsgType::D1; // MEO/IGSO + else eph.type = E_NavMsgType::D2; // GEO, prn range may change in the future*/ + + // eph.toc = bdt2gpst(eph.toc); // bdt -> gpst + eph.aode =(int)data[ 3]; // AODE + eph.aodc =(int)data[28]; // AODC + eph.toes = data[11]; // toe (s) in bdt week + eph.week =(int)data[21]; // bdt week + eph.iode = int(eph.tocs / 720) % 240; + eph.iodc = eph.iode + 256 * int(eph.tocs / 172800) % 4; + eph.toe = GTime(BWeek(eph.week), BTow(data[11])); + eph.ttm = GTime(BWeek(eph.week), BTow(data[27])); + + eph.svh =(E_Svh)data[24]; // satH1 + eph.sva =uraToSva(data[23]); // ura (m->index) + + eph.tgd[0] = data[25]; // TGD1 B1/B3 + eph.tgd[1] = data[26]; // TGD2 B2/B3 } - if (eph.iode<0||10231023) { BOOST_LOG_TRIVIAL(debug) << "rinex nav invalid: sat=" << Sat.id() << " iode=" << eph.iode; } - if (eph.iodc<0||10231023) { BOOST_LOG_TRIVIAL(debug) << "rinex nav invalid: sat=" << Sat.id() << " iodc=" << eph.iodc; @@ -1204,11 +1119,11 @@ int decodeEph( /** Decode glonass ephemeris */ int decodeGeph( - double ver, ///< RINEX version - SatSys Sat, ///< Satellite ID - GTime toc, ///< Time of clock - double* data, ///< Data to decode - Geph& geph) ///< Glonass ephemeris + double ver, ///< RINEX version + SatSys Sat, ///< Satellite ID + GTime toc, ///< Time of clock + vector& data, ///< Data to decode + Geph& geph) ///< Glonass ephemeris { GTime tof; double tow,tod; @@ -1228,32 +1143,33 @@ int decodeGeph( geph.type=defNavMsgType[Sat.sys]; geph.Sat=Sat; - // toc rounded by 15 min in utc - tow=time2gpst(toc,&week); - toc=gpst2time(week,floor((tow+450.0)/900.0)*900); - dow=(int)floor(tow/86400.0); - - // time of frame in utc - tod=ver<=2.99?data[2]:fmod(data[2],86400.0); // tod (v.2), tow (v.3) in utc - tof=gpst2time(week,tod+dow*86400.0); - tof=adjday(tof,toc); + // time of day in utc + if (ver <= 2.99) tod = data[2]; + else tod = fmod( data[2], 86400); // tod (v.2), tow (v.3) in utc - geph.toe=utc2gpst(toc); // toc (gpst) - geph.tof=utc2gpst(tof); // tof (gpst) + tow = GTow(toc); + toc = (toc+450.0).floorTime(900); + tof = toc.floorTime(86400.0) + tod; + + geph.toe = utc2gpst(toc); // toc (gpst) // Eugene to fix + geph.tof = utc2gpst(tof); // tof (gpst) // Eugene to fix // iode = tb (7bit), tb =index of UTC+3H within current day - geph.iode=(int)(fmod(tow+10800.0,86400.0)/900.0+0.5); + geph.iode = (int) (fmod(tow+10800.0,86400.0)/900.0+0.5); - geph.taun= data[0]; // taun - geph.gamn= data[1]; // +gamman + geph.taun = -data[0]; // -taun -> +taun + geph.gammaN = data[1]; // +gamman - geph.pos[0]=data[3]*1E3; geph.pos[1]=data[7]*1E3; geph.pos[2]=data[11]*1E3; - geph.vel[0]=data[4]*1E3; geph.vel[1]=data[8]*1E3; geph.vel[2]=data[12]*1E3; - geph.acc[0]=data[5]*1E3; geph.acc[1]=data[9]*1E3; geph.acc[2]=data[13]*1E3; - - geph.svh=(E_Svh)data[ 6]; - geph.frq=(int)data[10]; - geph.age=(int)data[14]; + for (int i = 0; i < 3; i++) + { + geph.pos[i] = data[3 + i*4] * 1E3; + geph.vel[i] = data[4 + i*4] * 1E3; + geph.acc[i] = data[5 + i*4] * 1E3; + } + + geph.svh = (E_Svh) data[6]; + geph.frq = (int) data[10]; + geph.age = (int) data[14]; // some receiver output >128 for minus frequency number if (geph.frq > 128) @@ -1270,11 +1186,11 @@ int decodeGeph( /** Decode geo ephemeris */ int decodeSeph( - double ver, - SatSys Sat, - GTime toc, - double* data, - Seph& seph) + double ver, + SatSys Sat, + GTime toc, + vector& data, + Seph& seph) { int week; @@ -1293,8 +1209,8 @@ int decodeSeph( seph.Sat=Sat; seph.t0 =toc; - time2gpst(seph.t0,&week); - seph.tof=adjweek(gpst2time(week,data[2]),seph.t0); + // time2gpst(seph.t0,&week); + seph.tof = GTime(GTow(data[2]),seph.t0); seph.af0=data[0]; seph.af1=data[1]; @@ -1304,7 +1220,7 @@ int decodeSeph( seph.acc[0]=data[5]*1E3; seph.acc[1]=data[9]*1E3; seph.acc[2]=data[13]*1E3; seph.svh=(E_Svh)data[6]; - seph.sva=uraindex(data[10]); + seph.sva=uraToSva(data[10]); return 1; } @@ -1316,7 +1232,7 @@ int decodeCeph( SatSys Sat, ///< Satellite ID E_NavMsgType type, ///< Navigation message type GTime toc, ///< Time of clock - double* data, ///< Data to decode + vector& data, ///< Data to decode Ceph& ceph) ///< CNVX ephemeris { // BOOST_LOG_TRIVIAL(debug) @@ -1357,13 +1273,13 @@ int decodeCeph( ceph.type = type; ceph.toc = toc; - ceph.f0 = data[0]; - ceph.f1 = data[1]; - ceph.f2 = data[2]; + ceph.f0 = data[0]; + ceph.f1 = data[1]; + ceph.f2 = data[2]; ceph.Adot = data[3]; ceph.crs = data[4]; ceph.deln = data[5]; - ceph.M0 = data[6]; + ceph.M0 = data[6]; ceph.cuc = data[7]; ceph.e = data[8]; ceph.cus = data[9]; @@ -1371,7 +1287,7 @@ int decodeCeph( ceph.cic = data[12]; ceph.OMG0 = data[13]; ceph.cis = data[14]; - ceph.i0 = data[15]; + ceph.i0 = data[15]; ceph.crc = data[16]; ceph.omg = data[17]; ceph.OMGd = data[18]; @@ -1380,16 +1296,17 @@ int decodeCeph( if (sys==+E_Sys::GPS||sys==+E_Sys::QZS) { - int week; + int week = GWeek(ceph.toc); ceph.toe = ceph.toc; - ceph.toes = time2gpst(ceph.toe,&week); + // ceph.toes = time2gpst(ceph.toe,&week); + ceph.toes = GTow(ceph.toe); ceph.ura[0] = data[21]; ceph.ura[1] = data[22]; ceph.ura[2] = data[26]; ceph.ura[3] = data[23]; - ceph.svh = (E_Svh)data[24]; // sv health + ceph.svh = (E_Svh)data[24]; // sv health ceph.tgd[0] = data[25]; // TGD @@ -1398,30 +1315,31 @@ int decodeCeph( ceph.isc[2] = data[29]; ceph.isc[3] = data[30]; - if (type==+E_NavMsgType::CNAV) + if (type == +E_NavMsgType::CNAV) { - ceph.ttm = adjweek(gpst2time(week,data[31]),ceph.toc); - ceph.wnop = (int)data[32]; + ceph.ttm = GTime((GTow)GTime(GWeek(week), GTow(data[31])), ceph.toc); + ceph.wnop = (int)data[32]; } - else if (type==+E_NavMsgType::CNV2) + else if (type == +E_NavMsgType::CNV2) { ceph.isc[4] = data[31]; ceph.isc[5] = data[32]; - ceph.ttm = adjweek(gpst2time(week,data[35]),ceph.toc); + ceph.ttm = GTime((GTow)GTime(GWeek(week), GTow(data[35])), ceph.toc); ceph.wnop = (int)data[36]; } - ceph.tops = data[11]; // top (s) in seconds - ceph.top = adjweek(gpst2time(ceph.wnop,data[11]),ceph.toc); + ceph.tops = data[11]; // top (s) in seconds + ceph.top = GTime((GTow)GTime(GWeek(ceph.wnop), GTow(ceph.tops)), ceph.toc); } else if (sys==+E_Sys::BDS) { // BeiDou v.4.00 int week; + time2bdt(ceph.toc,&week); - ceph.toc = bdt2gpst(ceph.toc); // bdt -> gpst +// ceph.toc = bdt2gpst(ceph.toc); // bdt -> gpst ceph.orb = E_SatType::_from_integral(data[21]); @@ -1446,26 +1364,22 @@ int decodeCeph( ceph.iodc = (int)data[34]; // IODC ceph.iode = (int)data[37]; // IODE - ceph.ttm = bdt2gpst(bdt2time(week,data[35])); // bdt -> gpst - ceph.ttm = adjweek(ceph.ttm,ceph.toc); +// ceph.ttm = bdt2gpst(bdt2time(week,data[35])); adjweek(ceph.ttm,ceph.toc);// bdt -> gpst } else if (type==+E_NavMsgType::CNV3) { ceph.sis[4] = data[27]; - ceph.svh = (E_Svh)data[28]; // sv health - ceph.flag = (int)data[29]; // integrity flag + ceph.svh = (E_Svh)data[28]; // sv health + ceph.flag = (int)data[29]; // integrity flag ceph.tgd[2] = data[30]; // TGD_B2ap - ceph.ttm = bdt2gpst(bdt2time(week,data[31])); // bdt -> gpst - ceph.ttm = adjweek(ceph.ttm,ceph.toc); +// ceph.ttm = bdt2gpst(bdt2time(week,data[31])); adjweek(ceph.ttm,ceph.toc);// bdt -> gpst } ceph.toes = data[11]; // top (s) in seconds ceph.tops = data[22]; // top (s) in seconds - ceph.toe = bdt2gpst(bdt2time(week,data[11])); // bdt -> gpst - ceph.top = bdt2gpst(bdt2time(week,data[22])); // bdt -> gpst - ceph.toe = adjweek(ceph.toe,ceph.toc); - ceph.top = adjweek(ceph.top,ceph.toc); +// ceph.toe = bdt2gpst(bdt2time(week,data[11])); adjweek(ceph.toe,ceph.toc);// bdt -> gpst +// ceph.top = bdt2gpst(bdt2time(week,data[22])); adjweek(ceph.top,ceph.toc);// bdt -> gpst } if (ceph.iode<0||1023& data, STO& sto) { if (ver < 4.0) @@ -1503,21 +1417,20 @@ int decodeSto( int sys = Sat.sys; - sto.Sat=Sat; - sto.type=type; - sto.tot=toc; + sto.Sat = Sat; + sto.type = type; + sto.tot = toc; - sto.code=E_StoCode::_from_integral(data[0]); - sto.sid =E_SbasId::_from_integral(data[1]); - sto.uid =E_UtcId::_from_integral(data[2]); + sto.code = E_StoCode ::_from_integral(data[0]); + sto.sid = E_SbasId ::_from_integral(data[1]); + sto.uid = E_UtcId ::_from_integral(data[2]); - sto.A0=data[4]; - sto.A1=data[5]; - sto.A2=data[6]; + sto.A0 = data[4]; + sto.A1 = data[5]; + sto.A2 = data[6]; - int week; - if (sys != +E_Sys::BDS) {time2gpst(sto.tot,&week); sto.ttm= gpst2time(week,data[3]); } - else {time2bdt (sto.tot,&week); sto.ttm=bdt2gpst( bdt2time(week,data[3])); sto.tot=bdt2gpst(sto.tot); } + if (sys != +E_Sys::BDS) {GWeek week = sto.tot; sto.ttm = gpst2time(week,data[3]); } +// else {time2bdt (sto.tot,&week); sto.ttm=bdt2gpst( bdt2time(week,data[3])); sto.tot=bdt2gpst(sto.tot); } return 1; } @@ -1529,7 +1442,7 @@ int decodeEop( SatSys Sat, E_NavMsgType type, GTime toc, - double* data, + vector& data, EOP& eop) { if (ver < 4.0) @@ -1542,23 +1455,22 @@ int decodeEop( int sys = Sat.sys; - eop.Sat=Sat; - eop.type=type; - eop.teop=toc; + eop.Sat = Sat; + eop.type = type; + eop.teop = toc; - eop.xp =data[0] * AS2R; - eop.xpr =data[1] * AS2R; - eop.xprr=data[2] * AS2R; - eop.yp =data[4] * AS2R; - eop.ypr =data[5] * AS2R; - eop.yprr=data[6] * AS2R; - eop.dut1=data[8]; - eop.dur =data[9]; - eop.durr=data[10]; + eop.xp = data[0] * AS2R; + eop.xpr = data[1] * AS2R; + eop.xprr = data[2] * AS2R; + eop.yp = data[4] * AS2R; + eop.ypr = data[5] * AS2R; + eop.yprr = data[6] * AS2R; + eop.dut1 = data[8]; + eop.dur = data[9]; + eop.durr = data[10]; - int week; - if (sys != +E_Sys::BDS) {time2gpst(eop.teop,&week); eop.ttm= gpst2time(week,data[7]); } - else {time2bdt (eop.teop,&week); eop.ttm=bdt2gpst( bdt2time(week,data[7])); eop.teop=bdt2gpst(eop.teop); } + if (sys != +E_Sys::BDS) { eop.ttm = GTime(GTow(data[7]), eop.teop);} + else { eop.ttm = GTime(BTow(data[7]), eop.teop);} return 1; } @@ -1570,7 +1482,7 @@ int decodeIon( SatSys Sat, E_NavMsgType type, GTime toc, - double* data, + vector& data, ION& ion) { if (ver < 4.0) @@ -1583,11 +1495,12 @@ int decodeIon( int sys = Sat.sys; - ion.Sat=Sat; - ion.type=type; - ion.ttm=toc; - if (sys == +E_Sys::BDS) - ion.ttm=bdt2gpst(ion.ttm); + ion.Sat = Sat; + ion.type = type; + ion.ttm = toc; + +// if (sys == +E_Sys::BDS) +// ion.ttm=bdt2gpst(ion.ttm); if ( sys==+E_Sys::GAL &&type==+E_NavMsgType::IFNV) @@ -1635,7 +1548,7 @@ int decodeIon( /** Read rinex navigation data body */ -int readrnxnavb( +int readRnxNavB( std::istream& inputStream, ///< Input stream to read double ver, ///< RINEX version E_Sys sys, ///< Satellite system @@ -1649,15 +1562,13 @@ int readrnxnavb( ION& ion) ///< Ionosphere data { GTime toc; - double data[64]; - int i=0,prn,sp=3; + vector data; + int sp=3; string line; char id[8]=""; char *p; - -// BOOST_LOG_TRIVIAL(debug) -// << "readrnxnavb: ver=" << ver << " sys=" << sys; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ver=" << ver << " sys=" << sys; SatSys Sat = {}; E_NavRecType recType = E_NavRecType::NONE; @@ -1667,7 +1578,7 @@ int readrnxnavb( { char* buff = &line[0]; - if (i == 0) + if (data.empty()) { // decode message type field if ( ver >= 4.0 @@ -1706,13 +1617,27 @@ int readrnxnavb( } else { - prn = (int)str2num(buff,0,2); Sat.sys = sys; - Sat.prn = prn; + Sat.prn = str2num(buff,0,2); } // decode toc field - if (str2time(buff+sp,0,19,toc)) + GTime tempTime; + bool error = str2time(buff+sp, 0, 19, tempTime); + if (error == false) + { + if (sys == +E_Sys::BDS) { toc.bigTime = tempTime.bigTime + (double) GPS_SUB_UTC_2006; } + else { toc = tempTime; } + + // if (sys == +E_Sys::GLO) // todo Eugene: UEpoch + // { + // UtcTime utcTime; + // utcTime.bigTime = tempTime.bigTime; + + // toc = utcTime; + // } + } + else { // BOOST_LOG_TRIVIAL(debug) // << "rinex nav toc error: " << buff; @@ -1726,18 +1651,18 @@ int readrnxnavb( char code[19] = ""; strncpy(code,buff+24,18); std::replace(code, code+18, ' ', '\0'); - data[i++] = +E_StoCode::_from_string(code); + data.push_back(E_StoCode::_from_string(code)); strncpy(code,buff+43,18); std::replace(code, code+18, '-', '_' ); std::replace(code, code+18, ' ', '\0'); - data[i++] = *(E_SbasId::_from_string_nothrow(code)); //code may be empty + data.push_back(*(E_SbasId::_from_string_nothrow(code))); //code may be empty strncpy(code,buff+62,18); std::replace(code, code+18, '(', '_' ); std::replace(code, code+18, ')', '\0'); std::replace(code, code+18, ' ', '\0'); - data[i++] = *(E_UtcId::_from_string_nothrow(code)); //code may be empty + data.push_back(*(E_UtcId::_from_string_nothrow(code))); //code may be empty } else { @@ -1745,7 +1670,7 @@ int readrnxnavb( p = buff+sp+19; for (int j = 0; j < 3; j++, p += 19) { - data[i++]=str2num(p,0,19); + data.push_back(str2num(p,0,19)); } } @@ -1758,36 +1683,30 @@ int readrnxnavb( p = buff+sp; for (int j = 0; j < 4; j++, p += 19) { - data[i++]=str2num(p,0,19); + data.push_back(str2num(p,0,19)); } // decode ephemeris if (recType == +E_NavRecType::EPH) { switch (msgType) { - case E_NavMsgType::CNAV : - case E_NavMsgType::CNV3 : if (i>=35) { type = E_EphType::CEPH; return decodeCeph(ver,Sat,msgType,toc,data,ceph); } break; - case E_NavMsgType::CNV1 : - case E_NavMsgType::CNV2 : if (i>=39) { type = E_EphType::CEPH; return decodeCeph(ver,Sat,msgType,toc,data,ceph); } break; - case E_NavMsgType::FDMA : if (i>=15) { type = E_EphType::GEPH; return decodeGeph(ver,Sat, toc,data,geph); } break; - case E_NavMsgType::SBAS : if (i>=15) { type = E_EphType::SEPH; return decodeSeph(ver,Sat, toc,data,seph); } break; - default : if (i>=31) { type = E_EphType:: EPH; return decodeEph (ver,Sat, toc,data, eph); } break; + case E_NavMsgType::CNAV: //fallthrough + case E_NavMsgType::CNV3: { if (data.size() >= 35) { type = E_EphType::CEPH; return decodeCeph(ver,Sat,msgType, toc,data,ceph); } break; } + case E_NavMsgType::CNV1: //fallthrough + case E_NavMsgType::CNV2: { if (data.size() >= 39) { type = E_EphType::CEPH; return decodeCeph(ver,Sat,msgType, toc,data,ceph); } break; } + case E_NavMsgType::FDMA: { if (data.size() >= 15) { type = E_EphType::GEPH; return decodeGeph(ver,Sat, toc,data,geph); } break; } + case E_NavMsgType::SBAS: { if (data.size() >= 15) { type = E_EphType::SEPH; return decodeSeph(ver,Sat, toc,data,seph); } break; } + default: { if (data.size() >= 31) { type = E_EphType:: EPH; return decodeEph (ver,Sat, toc,data, eph); } break; } } } - else if (recType == +E_NavRecType::STO) - { - if (i>= 7) { type = E_EphType:: STO; return decodeSto (ver,Sat,msgType,toc,data, sto); } - } - else if (recType == +E_NavRecType::EOP) - { - if (i>=11) { type = E_EphType:: EOP; return decodeEop (ver,Sat,msgType,toc,data, eop); } - } + else if (recType == +E_NavRecType::STO) { if (data.size() >= 7) { type = E_EphType:: STO; return decodeSto (ver,Sat,msgType, toc,data, sto); } } + else if (recType == +E_NavRecType::EOP) { if (data.size() >= 11) { type = E_EphType:: EOP; return decodeEop (ver,Sat,msgType, toc,data, eop); } } else if (recType == +E_NavRecType::ION) { switch (sys) { - case E_Sys::GAL : if (i>= 7) { type = E_EphType:: ION; return decodeIon (ver,Sat,msgType,toc,data, ion); } break; - default : if (i>=11) { type = E_EphType:: ION; return decodeIon (ver,Sat,msgType,toc,data, ion); } break; + case E_Sys::GAL: { if (data.size() >= 7) { type = E_EphType:: ION; return decodeIon (ver,Sat,msgType, toc,data, ion); } break; } + default: { if (data.size() >= 11) { type = E_EphType:: ION; return decodeIon (ver,Sat,msgType, toc,data, ion); } break; } } } else @@ -1799,7 +1718,7 @@ int readrnxnavb( /** Read rinex nav/gnav/geo nav */ -int readrnxnav( +int readRnxNav( std::istream& inputStream, ///< Input stream to read double ver, ///< RINEX version E_Sys sys, ///< Satellite system @@ -1815,40 +1734,39 @@ int readrnxnav( int stat = {}; E_EphType type = {}; -// BOOST_LOG_TRIVIAL(debug) -// << "readrnxnav: ver=" << ver << " sys=" << sys; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": ver=" << ver << " sys=" << sys; // read rinex navigation data body - while ((stat = readrnxnavb(inputStream, ver, sys, type, eph, geph, seph, ceph, sto, eop, ion)) >= 0) + while ((stat = readRnxNavB(inputStream, ver, sys, type, eph, geph, seph, ceph, sto, eop, ion)) >= 0) { // add ephemeris to navigation data if (stat) { switch (type) { - case E_EphType::EPH: nav.ephMap [eph.Sat] [eph.toe] = eph; break; - case E_EphType::GEPH: nav.gephMap [geph.Sat] [geph.toe] = geph; break; - case E_EphType::SEPH: nav.sephMap [seph.Sat] [seph.t0] = seph; break; - case E_EphType::CEPH: nav.cephMap [ceph.Sat] [ceph.type] [ceph.toe] = ceph; break; - case E_EphType::STO: nav.stoMap [sto.code] [sto.type] [sto.tot ] = sto; break; - case E_EphType::EOP: nav.eopMap [eop.Sat.sys] [eop.type] [eop.teop] = eop; break; - case E_EphType::ION: nav.ionMap [ion.Sat.sys] [ion.type] [ion.ttm ] = ion; break; + case E_EphType::EPH: nav.ephMap [eph.Sat] [eph.type] [eph.toe] = eph; break; + case E_EphType::GEPH: nav.gephMap [geph.Sat] [E_NavMsgType::FDMA] [geph.toe] = geph; break; + case E_EphType::SEPH: nav.sephMap [seph.Sat] [E_NavMsgType::SBAS] [seph.t0] = seph; break; + case E_EphType::CEPH: nav.cephMap [ceph.Sat] [ceph.type] [ceph.toe] = ceph; break; + case E_EphType::STO: nav.stoMap [sto.code] [sto.type] [sto.tot ] = sto; break; + case E_EphType::EOP: nav.eopMap [eop.Sat.sys] [eop.type] [eop.teop] = eop; break; + case E_EphType::ION: nav.ionMap [ion.Sat.sys] [ion.type] [ion.ttm ] = ion; break; default: continue; } } } - return ( nav. ephMap.size() > 0 - ||nav.gephMap.size() > 0 - ||nav.sephMap.size() > 0 - ||nav.cephMap.size() > 0 - ||nav. stoMap.size() > 0 - ||nav. eopMap.size() > 0 - ||nav. ionMap.size() > 0); + return ( nav. ephMap.empty() == false + ||nav.gephMap.empty() == false + ||nav.sephMap.empty() == false + ||nav.cephMap.empty() == false + ||nav. stoMap.empty() == false + ||nav. eopMap.empty() == false + ||nav. ionMap.empty() == false); } /** Read rinex clock */ -int readrnxclk( +int readRnxClk( std::istream& inputStream, double ver, Navigation& nav) @@ -1902,12 +1820,11 @@ int readrnxclk( Pclk preciseClock = {}; - preciseClock.clk = str2num(buff, clk.offset, clk.length); - preciseClock.std = str2num(buff, std.offset, std.length); - preciseClock.time = time; - preciseClock.index = index; + preciseClock.clk = str2num(buff, clk.offset, clk.length); + preciseClock.clkStd = str2num(buff, std.offset, std.length); + preciseClock.clkIndex = index; - nav.pclkMap[idString].push_back(preciseClock); + nav.pclkMap[idString][time] = preciseClock; } return nav.pclkMap.size() > 0; @@ -1915,7 +1832,7 @@ int readrnxclk( /** Read rinex file */ -int readrnx( +int readRnx( std::istream& inputStream, char& type, ObsList& obsList, @@ -1923,31 +1840,27 @@ int readrnx( RinexStation* sta, double& ver, E_Sys& sys, - int& tsys, - map>& sysCodeTypes) + E_TimeSys& tsys, + map>& sysCodeTypes) { -// BOOST_LOG_TRIVIAL(debug) -// << "readrnxfp: flag=" << flag -// << " index=" << index; +// BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ": flag=" << flag << " index=" << index; // read rinex header if at beginning of file if (inputStream.tellg() == 0) { - bool pass = readrnxh(inputStream, ver, type, sys, tsys, sysCodeTypes, nav, sta); - - return pass; + readRnxH(inputStream, ver, type, sys, tsys, sysCodeTypes, nav, sta); } // read rinex body switch (type) { - case 'O': return readrnxobs(inputStream, ver, tsys, sysCodeTypes, obsList); - case 'N': return readrnxnav(inputStream, ver, sys , nav); - case 'G': return readrnxnav(inputStream, ver, E_Sys::GLO, nav); - case 'H': return readrnxnav(inputStream, ver, E_Sys::SBS, nav); - case 'J': return readrnxnav(inputStream, ver, E_Sys::QZS, nav); // extension - case 'L': return readrnxnav(inputStream, ver, E_Sys::GAL, nav); // extension - case 'C': return readrnxclk(inputStream, ver, nav); + case 'O': return readRnxObs(inputStream, ver, tsys, sysCodeTypes, obsList, sta); + case 'N': return readRnxNav(inputStream, ver, sys , nav); + case 'G': return readRnxNav(inputStream, ver, E_Sys::GLO, nav); + case 'H': return readRnxNav(inputStream, ver, E_Sys::SBS, nav); + case 'J': return readRnxNav(inputStream, ver, E_Sys::QZS, nav); // extension + case 'L': return readRnxNav(inputStream, ver, E_Sys::GAL, nav); // extension + case 'C': return readRnxClk(inputStream, ver, nav); } BOOST_LOG_TRIVIAL(debug) diff --git a/src/cpp/rtklib/rinex.hpp b/src/cpp/common/rinex.hpp similarity index 73% rename from src/cpp/rtklib/rinex.hpp rename to src/cpp/common/rinex.hpp index 82a329860..8cb58b00b 100644 --- a/src/cpp/rtklib/rinex.hpp +++ b/src/cpp/common/rinex.hpp @@ -1,5 +1,5 @@ -#ifndef __RINEX__HPP__ -#define __RINEX__HPP__ + +#pragma once #include @@ -12,11 +12,11 @@ struct Navigation; struct CodeType { - char type; + char type = 0; E_ObsCode code = E_ObsCode::NONE; }; -int readrnx( +int readRnx( std::istream& inputStream, char& type, ObsList& obsList, @@ -24,12 +24,10 @@ int readrnx( RinexStation* sta, double& ver, E_Sys& sys, - int& tsys, - map>& sysCodeTypes); + E_TimeSys& tsys, + map>& sysCodeTypes); string rinexSysDesc( E_Sys sys); - -#endif diff --git a/src/cpp/common/rinexClkWrite.cpp b/src/cpp/common/rinexClkWrite.cpp index 6a893e975..e794e63f8 100644 --- a/src/cpp/common/rinexClkWrite.cpp +++ b/src/cpp/common/rinexClkWrite.cpp @@ -11,6 +11,7 @@ using std::map; #include "rinexNavWrite.hpp" #include "rinexObsWrite.hpp" #include "rinexClkWrite.hpp" +#include "ephPrecise.hpp" #include "GNSSambres.hpp" #include "navigation.hpp" #include "acsConfig.hpp" @@ -18,7 +19,6 @@ using std::map; #include "constants.hpp" #include "station.hpp" #include "algebra.hpp" -#include "preceph.hpp" #include "rinex.hpp" #include "enums.h" @@ -35,16 +35,13 @@ struct ClockEntry bool isRec = true; // If true is receiver clock data. }; -typedef std::list ClockList; +typedef std::vector ClockList; void outputRinexClocksBody( string& filename, ///< Path to output file. ClockList& clkList, ///< List of data to print. GTime& time) ///< Epoch time. { - double ep[6] = {}; - time2epoch(time, ep); - std::ofstream clockFile(filename, std::ofstream::app); if (!clockFile) @@ -52,6 +49,8 @@ void outputRinexClocksBody( BOOST_LOG_TRIVIAL(error) << "Error opening " << filename << " for RINEX clock file."; return; } + + GEpoch ep = time; for (auto& clkVal : clkList) { @@ -76,7 +75,7 @@ void outputRinexClocksBody( void getKalmanSatClks( ClockList& clkValList, - OutSys& outSys, + map& outSys, KFState& kfState) { for (auto& [key,index] : kfState.kfIndexMap) @@ -108,15 +107,15 @@ void getKalmanRecClks( ClockEntry& referenceRec, KFState& kfState) { - int firstBiasGroup = 0; + SatSys firstSys; for (auto& [key, index] : kfState.kfIndexMap) { if ( ( key.type == KF::REC_SYS_BIAS || key.type == KF::REC_CLOCK) - &&( firstBiasGroup == 0 - || firstBiasGroup == key.num)) + &&( firstSys == E_Sys::NONE + || firstSys == key.Sat)) { - firstBiasGroup = key.num; + firstSys = key.Sat; double clk = 0; double variance = 0; @@ -135,7 +134,7 @@ void getKalmanRecClks( } else { - clkVal.monid = key.rec_ptr->snx.monuid; + clkVal.monid = key.rec_ptr->snx.id_ptr->domes; clkVal.recPos = key.rec_ptr->snx.pos; } @@ -151,7 +150,7 @@ void getKalmanRecClks( if (key.rec_ptr) { - referenceRec.monid = key.rec_ptr->snx.monuid; + referenceRec.monid = key.rec_ptr->snx.id_ptr->domes; referenceRec.recPos = key.rec_ptr->snx.pos; } } @@ -194,7 +193,7 @@ void getPreciseRecClks( { double dt; double variance; - int ret = pephclk(time, rec.id, nav, dt, &variance); + int ret = pephclk(std::cout, time, rec.id, nav, dt, &variance); if (ret != 1) { BOOST_LOG_TRIVIAL(warning) @@ -209,7 +208,7 @@ void getPreciseRecClks( clkVal.clock = dt; clkVal.sigma = sqrt(variance); clkVal.isRec = true; - clkVal.monid = rec.snx.monuid; + clkVal.monid = rec.snx.id_ptr->domes; clkVal.recPos = rec.snx.pos; clkValList.push_back(clkVal); @@ -219,24 +218,22 @@ void getPreciseRecClks( void getSatClksFromEph( ClockList& clkValList, GTime& time, - OutSys& outSys, - E_Ephemeris ephType) + map& outSys, + vector ephType) { - for (auto& [satId, satNav] : nav.satNavMap) + for (auto& [Sat, satNav] : nav.satNavMap) { - SatSys Sat; - Sat.fromHash(satId); - - if (!outSys[Sat.sys]) + if (outSys[Sat.sys] == false) continue; // Create a dummy observation - Obs obs; - obs.Sat = Sat; - - obs.satNav_ptr = &nav.satNavMap[obs.Sat]; // for satpos_ssr() + GObs obs; + obs.Sat = Sat; + obs.satNav_ptr = &nav.satNavMap[Sat]; // for satpos_ssr() - int pass = satpos(std::cout, time, time, obs, ephType, E_OffsetType::COM, nav, false); + bool pass = true; + pass &= satclk(nullStream, time, time, obs, ephType, nav); + pass &= satpos(nullStream, time, time, obs, ephType, E_OffsetType::COM, nav); //use both for now to get ssr clocks if required if (pass == false) { BOOST_LOG_TRIVIAL(warning) @@ -248,8 +245,8 @@ void getSatClksFromEph( ClockEntry clkVal; clkVal.id = Sat.id(); - clkVal.clock = obs.dtSat[0]; - clkVal.sigma = sqrt(obs.ephVar); + clkVal.clock = obs.satClk; + clkVal.sigma = sqrt(obs.satClkVar); clkVal.isRec = false; clkValList.push_back(clkVal); @@ -260,7 +257,7 @@ void outputRinexClocksHeader( string& filename, ///< Path of tile to output to ClockList& clkValList, ///< List of clock values to output ClockEntry& referenceRec, ///< Entry for the reference receiver - OutSys& sysMap, ///< Options to enable outputting of specific systems + map& sysMap, ///< Options to enable outputting of specific systems GTime time) ///< Epoch time { std::ofstream clockFile(filename, std::ofstream::app); @@ -275,8 +272,6 @@ void outputRinexClocksHeader( if (pos != 0) return; - double ep[6] = {}; - time2epoch(time, ep); string sysDesc; if (sysMap.size() == 1) sysDesc = rinexSysDesc(sysMap.begin()->first); @@ -300,6 +295,8 @@ void outputRinexClocksHeader( sysDesc.c_str(), "RINEX VERSION / TYPE"); + GEpoch ep = time; + tracepdeex(0,clockFile,"%-20s%-20s%4d%02d%02d %02d%02d%02d %4s%s\n", acsConfig.analysis_program .c_str(), acsConfig.analysis_agency .c_str(), @@ -351,55 +348,54 @@ void outputRinexClocksHeader( if (sysMap[E_Sys::GLO]) num_sats += NSATGLO; if (sysMap[E_Sys::GAL]) num_sats += NSATGAL; if (sysMap[E_Sys::BDS]) num_sats += NSATBDS; - + if (sysMap[E_Sys::QZS]) num_sats += NSATQZS; + /* output satellite PRN*/ int k = 0; tracepdeex(0,clockFile,"%6d%54s%s\n",num_sats,"","# OF SOLN SATS"); - if (sysMap[E_Sys::GPS]) for (int prn = MINPRNGPS; prn <= MAXPRNGPS; prn++) {k++; SatSys s(E_Sys::GPS,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} - if (sysMap[E_Sys::GLO]) for (int prn = MINPRNGLO; prn <= MAXPRNGLO; prn++) {k++; SatSys s(E_Sys::GLO,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} - if (sysMap[E_Sys::GAL]) for (int prn = MINPRNGAL; prn <= MAXPRNGAL; prn++) {k++; SatSys s(E_Sys::GAL,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} - if (sysMap[E_Sys::BDS]) for (int prn = MINPRNBDS; prn <= MAXPRNBDS; prn++) {k++; SatSys s(E_Sys::BDS,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} + if (sysMap[E_Sys::GPS]) for (int prn = 1; prn <= NSATGPS; prn++) {k++; SatSys s(E_Sys::GPS,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} + if (sysMap[E_Sys::GLO]) for (int prn = 1; prn <= NSATGLO; prn++) {k++; SatSys s(E_Sys::GLO,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} + if (sysMap[E_Sys::GAL]) for (int prn = 1; prn <= NSATGAL; prn++) {k++; SatSys s(E_Sys::GAL,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} + if (sysMap[E_Sys::BDS]) for (int prn = 1; prn <= NSATBDS; prn++) {k++; SatSys s(E_Sys::BDS,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} + if (sysMap[E_Sys::QZS]) for (int prn = 1; prn <= NSATQZS; prn++) {k++; SatSys s(E_Sys::QZS,prn); tracepdeex(0,clockFile,"%3s ", s.id().c_str()); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} /*finish the line*/ while (k % 15 != 0) {k++; tracepdeex(0,clockFile,"%3s ", ""); if (k % 15 == 0) tracepdeex(0,clockFile,"%s\n","PRN LIST");} tracepdeex(0,clockFile,"%-60s%s\n","","END OF HEADER"); } -void outputClocks( +void outputClocksSet( string filename, - E_Ephemeris clkDataRecSrc, - E_Ephemeris clkDataSatSrc, + vector clkDataRecSrcs, + vector clkDataSatSrcs, GTime& time, - OutSys& outSys, + map& outSys, KFState& kfState, - StationMap* stationMap_ptr, - bool isUser) + StationMap* stationMap_ptr) { ClockList clkValList; ClockEntry referenceRec; referenceRec.isRec = false; - switch (clkDataSatSrc) + switch (clkDataSatSrcs.front()) //todo aaron, remove this function { - case +E_Ephemeris::NONE: break; - case +E_Ephemeris::KALMAN: getKalmanSatClks(clkValList, outSys, kfState); break; - case +E_Ephemeris::PRECISE: //fallthrough - case +E_Ephemeris::BROADCAST: //fallthrough - case +E_Ephemeris::SSR: getSatClksFromEph(clkValList, time, outSys, clkDataSatSrc); break; - default: BOOST_LOG_TRIVIAL(error) << "Error: Unknown / Undefined clock data source."; return; + case +E_Source::NONE: break; + case +E_Source::KALMAN: getKalmanSatClks(clkValList, outSys, kfState); break; + case +E_Source::PRECISE: //fallthrough + case +E_Source::BROADCAST: //fallthrough + case +E_Source::SSR: getSatClksFromEph(clkValList, time, outSys, clkDataSatSrcs); break; + default: BOOST_LOG_TRIVIAL(error) << "Error: Unknown / Undefined clock data source."; return; } - switch (clkDataRecSrc) + switch (clkDataRecSrcs.front()) { - case +E_Ephemeris::NONE: break; - case +E_Ephemeris::KALMAN: - if (isUser) getKalmanRecClks(clkValList, referenceRec, kfState); - else getKalmanRecClks(clkValList, referenceRec, stationMap_ptr); break; - case +E_Ephemeris::PRECISE: getPreciseRecClks(clkValList, stationMap_ptr, time); break; - case +E_Ephemeris::SSR: //fallthrough - case +E_Ephemeris::BROADCAST: //fallthrough - default: BOOST_LOG_TRIVIAL(error) << "Error: Printing receiver clocks for " << clkDataRecSrc._to_string() << " not implemented."; return; + case +E_Source::NONE: break; + case +E_Source::KALMAN: getKalmanRecClks(clkValList, referenceRec, kfState); break; + case +E_Source::PRECISE: getPreciseRecClks(clkValList, stationMap_ptr, time); break; + case +E_Source::SSR: //fallthrough + case +E_Source::BROADCAST: //fallthrough + default: BOOST_LOG_TRIVIAL(error) << "Error: Printing receiver clocks for " << clkDataRecSrcs.front()._to_string() << " not implemented."; return; } outputRinexClocksHeader(filename, clkValList, referenceRec, outSys, time); @@ -409,17 +405,30 @@ void outputClocks( map> getSysOutputFilenames( string filename, GTime logtime, + bool replaceSys, string id) { - logtime = logtime.roundTime(acsConfig.rotate_period); + logtime = logtime.floorTime(acsConfig.rotate_period); + + boost::posix_time::ptime logptime = boost::posix_time::from_time_t((time_t)((PTime)logtime).bigTime); - boost::posix_time::ptime logptime = boost::posix_time::from_time_t(logtime.time); + if (logtime == GTime::noTime()) + { + logptime = boost::posix_time::not_a_date_time; + } replaceString(filename, "", id); replaceTimes (filename, logptime); map> fileOutputSysMap; + if (replaceSys == false) + { + fileOutputSysMap[filename][E_Sys::NONE] = true; + + return fileOutputSysMap; + } + for (auto& [sys, output] : acsConfig.process_sys) { if (output == false) @@ -442,3 +451,19 @@ map> getSysOutputFilenames( return fileOutputSysMap; } + +void outputClocks( + string filename, + vector clkDataRecSrcs, + vector clkDataSatSrcs, + GTime& time, + KFState& kfState, + StationMap* stationMap_ptr) +{ + auto filenameSysMap = getSysOutputFilenames(filename, time); + + for (auto [sysFilename, sysMap] : filenameSysMap) + { + outputClocksSet(sysFilename, clkDataRecSrcs, clkDataSatSrcs, time, sysMap, kfState, stationMap_ptr); + } +} diff --git a/src/cpp/common/rinexClkWrite.hpp b/src/cpp/common/rinexClkWrite.hpp index ba461cbfd..601188b89 100644 --- a/src/cpp/common/rinexClkWrite.hpp +++ b/src/cpp/common/rinexClkWrite.hpp @@ -1,5 +1,5 @@ -#ifndef WRITECLK_HPP -#define WRITECLK_HPP + +#pragma once // Needed as StationMap is a kind of typedef. #include "station.hpp" @@ -10,22 +10,17 @@ using std::vector; using std::string; -using std::pair; using std::map; #include "enums.h" struct GTime; -class E_Ephemeris; +class E_Source; void outputClocks( string filename, - E_Ephemeris clkDataRecSrc, - E_Ephemeris clkDataSatSrc, + vector clkDataRecSrcs, + vector clkDataSatSrcs, GTime& time, - OutSys& outSys, KFState& kfState, - StationMap* stationMap_ptr, - bool isUser = false); - -#endif + StationMap* stationMap_ptr = nullptr); diff --git a/src/cpp/common/rinexNavWrite.cpp b/src/cpp/common/rinexNavWrite.cpp index be7cd4cd0..5929abd7b 100644 --- a/src/cpp/common/rinexNavWrite.cpp +++ b/src/cpp/common/rinexNavWrite.cpp @@ -8,11 +8,11 @@ #include "rinexNavWrite.hpp" #include "rinexObsWrite.hpp" #include "rinexClkWrite.hpp" -#include "streamTrace.hpp" #include "navigation.hpp" #include "acsConfig.hpp" #include "common.hpp" #include "rinex.hpp" +#include "trace.hpp" @@ -54,9 +54,10 @@ void outputNavRinexEph( auto sys = eph.Sat.sys; - double ep[6]; - if (sys != +E_Sys::BDS) { time2epoch(eph.toc, ep); } - else { time2epoch(gpst2bdt(eph.toc), ep); } /* gpst -> bdt */ + GEpoch ep; + GTime fakeGTime; + if (sys == +E_Sys::BDS) { fakeGTime.bigTime = eph.toc - (double)GPS_SUB_UTC_2006; ep = fakeGTime; } //todo Eugene: BEpoch? + else { ep = eph.toc; } tracepdeex(0, trace, "%-3s %04.0f %02.0f %02.0f %02.0f %02.0f %02.0f", eph.Sat.id().c_str(), ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); @@ -66,7 +67,9 @@ void outputNavRinexEph( trace << std::endl; trace << " "; - traceFormatedFloat(trace, eph.iode, formatStr); /* GPS/QZS: IODE, GAL: IODnav, BDS: AODE */ + if (sys != +E_Sys::BDS) { traceFormatedFloat(trace, eph.iode, formatStr); } /* GPS/QZS: IODE, GAL: IODnav */ + else { traceFormatedFloat(trace, eph.aode, formatStr); } /* BDS: AODE */ + traceFormatedFloat(trace, eph.crs, formatStr); traceFormatedFloat(trace, eph.deln, formatStr); traceFormatedFloat(trace, eph.M0, formatStr); @@ -96,16 +99,16 @@ void outputNavRinexEph( trace << " "; traceFormatedFloat(trace, eph.idot, formatStr); traceFormatedFloat(trace, eph.code, formatStr); - traceFormatedFloat(trace, eph.week, formatStr); /* GPS/QZS: GPS week, GAL: GAL week, BDS: BDT week */ + traceFormatedFloat(trace, eph.week, formatStr); /* GPS/QZS: GPS week, GAL: GAL week, BDS: BDT week */ traceFormatedFloat(trace, eph.flag, formatStr); trace << std::endl; trace << " "; - if (sys != +E_Sys::GAL) { traceFormatedFloat(trace, svaToUra(eph.sva), formatStr); } - else { traceFormatedFloat(trace, svaToSisa(eph.sva), formatStr); } + if (sys == +E_Sys::GAL) { traceFormatedFloat(trace, svaToSisa (eph.sva), formatStr); } + else { traceFormatedFloat(trace, svaToUra (eph.sva), formatStr); } traceFormatedFloat(trace, eph.svh, formatStr); - traceFormatedFloat(trace, eph.tgd[0], formatStr); /* GPS/QZS:TGD, GAL:BGD E5a/E1, BDS: TGD1 B1/B3 */ + traceFormatedFloat(trace, eph.tgd[0], formatStr); /* GPS/QZS:TGD, GAL:BGD E5a/E1, BDS: TGD1 B1/B3 */ if ( sys == +E_Sys::GAL || sys == +E_Sys::BDS) { traceFormatedFloat(trace, eph.tgd[1], formatStr); } /* GAL:BGD E5b/E1, BDS: TGD2 B2/B3 */ @@ -113,16 +116,16 @@ void outputNavRinexEph( trace << std::endl; trace << " "; - double ttm; - int week; - if (sys != +E_Sys::BDS) { ttm = time2gpst(eph.ttm, &week); } - else { ttm = time2bdt(gpst2bdt(eph.ttm), &week); } /* gpst -> bdt */ + double ttm = 0; + int week = 0; + if (sys == +E_Sys::BDS) { ttm = BTow(eph.ttm); week = GWeek(eph.ttm); } /* gpst -> bdt */ + else { ttm = GTow(eph.ttm); week = GWeek(eph.ttm); } traceFormatedFloat(trace, ttm + (week - eph.week) * 604800.0, formatStr); - if ( sys == +E_Sys::GPS - || sys == +E_Sys::QZS) { traceFormatedFloat(trace, eph.fit, formatStr); } - else if ( sys == +E_Sys::BDS) { traceFormatedFloat(trace, eph.iodc, formatStr); } /* AODC */ - else { traceFormatedFloat(trace, 0, formatStr); } /* spare */ + if (sys == +E_Sys::GPS) { traceFormatedFloat(trace, eph.fit, formatStr); } /* fit interval in hours for GPS */ + else if (sys == +E_Sys::QZS) { traceFormatedFloat(trace, eph.fitFlag, formatStr); } /* fit interval flag for QZS */ + else if (sys == +E_Sys::BDS) { traceFormatedFloat(trace, eph.iodc, formatStr); } /* BDS: AODC */ + else { traceFormatedFloat(trace, 0, formatStr); } /* spare */ trace << std::endl; } @@ -146,15 +149,23 @@ void outputNavRinexGeph( return; } - double tof = time2gpst(gpst2utc(geph.tof), nullptr); /* v.3: tow in utc */ + // double tof = time2gpst(gpst2utc(geph.tof), nullptr); /* v.3: tow in utc */ - double ep[6]; - GTime toe = gpst2utc(geph.toe); /* gpst -> utc */ - time2epoch(toe, ep); + UtcTime utcTime; + GTime fakeGTime; + utcTime = geph.tof; + fakeGTime.bigTime = utcTime.bigTime; // todo Eugene: UEpoch + double tof = GTow(fakeGTime); + + // GEpoch ep = geph.toe; + utcTime = geph.toe; + fakeGTime.bigTime = utcTime.bigTime; // todo Eugene: UEpoch + GEpoch ep = fakeGTime; + tracepdeex(0, trace, "%-3s %04.0f %02.0f %02.0f %02.0f %02.0f %02.0f", geph.Sat.id().c_str(), ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); - traceFormatedFloat(trace, geph.taun, formatStr); - traceFormatedFloat(trace, geph.gamn, formatStr); + traceFormatedFloat(trace,-geph.taun, formatStr); // -taun + traceFormatedFloat(trace, geph.gammaN, formatStr); traceFormatedFloat(trace, tof, formatStr); trace << std::endl; @@ -200,9 +211,9 @@ void outputNavRinexCeph( auto sys = ceph.Sat.sys; auto type = ceph.type; - double ep[6]; - if (sys != +E_Sys::BDS) { time2epoch(ceph.toc, ep); } - else { time2epoch(gpst2bdt(ceph.toc), ep); } /* gpst -> bdt */ + GEpoch ep; + if (sys != +E_Sys::BDS) { ep = ceph.toc; } +// else { ep = gpst2bdt(ceph.toc); } tracepdeex(0, trace, "%-3s %04.0f %02.0f %02.0f %02.0f %02.0f %02.0f", ceph.Sat.id().c_str(), ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); @@ -268,9 +279,10 @@ void outputNavRinexCeph( if (type==+E_NavMsgType::CNAV) { trace << " "; - double ttm; - int week; - ttm = time2gpst(ceph.ttm, &week); + double ttm = GTow(ceph.ttm); + // int week; + // ttm = time2gpst(ceph.ttm, &week); + traceFormatedFloat(trace, ttm, formatStr); traceFormatedFloat(trace, ceph.wnop, formatStr); trace << " "; @@ -287,9 +299,9 @@ void outputNavRinexCeph( trace << std::endl; trace << " "; - double ttm; - int week; - ttm = time2gpst(ceph.ttm, &week); + double ttm = GTow(ceph.ttm); + // int week; + // ttm = time2gpst(ceph.ttm, &week); traceFormatedFloat(trace, ttm, formatStr); traceFormatedFloat(trace, ceph.wnop, formatStr); trace << " "; @@ -313,7 +325,6 @@ void outputNavRinexCeph( if ( type==+E_NavMsgType::CNV1 ||type==+E_NavMsgType::CNV2) { - trace << " "; if (type==+E_NavMsgType::CNV1) { @@ -337,9 +348,8 @@ void outputNavRinexCeph( trace << std::endl; trace << " "; - double ttm; - int week; - ttm = time2bdt(gpst2bdt(ceph.ttm), &week); + double ttm = GTow(ceph.ttm); + // ttm = time2bdt(gpst2bdt(ceph.ttm), &week); traceFormatedFloat(trace, ttm, formatStr); trace << " "; traceFormatedFloat(trace, ceph.iode, formatStr); @@ -356,9 +366,8 @@ void outputNavRinexCeph( trace << std::endl; trace << " "; - double ttm; - int week; - ttm = time2bdt(gpst2bdt(ceph.ttm), &week); + double ttm = GTow(ceph.ttm); +// ttm = time2bdt(gpst2bdt(ceph.ttm), &week); traceFormatedFloat(trace, ttm, formatStr); trace << " "; trace << " "; @@ -388,9 +397,9 @@ void outputNavRinexSTO( auto sys = sto.Sat.sys; - double ep[6]; - if (sys != +E_Sys::BDS) { time2epoch(sto.tot, ep); } - else { time2epoch(gpst2bdt(sto.tot), ep); } + GEpoch ep; + if (sys != +E_Sys::BDS) { ep = sto.tot; } +// else { ep = gpst2bdt(sto.tot); } tracepdeex(0, trace, " %04.0f %02.0f %02.0f %02.0f %02.0f %02.0f", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); @@ -404,10 +413,11 @@ void outputNavRinexSTO( trace << std::endl; trace << " "; - double ttm; - int week, weekRef; - if (sys != +E_Sys::BDS) { time2gpst(sto.tot, &weekRef); ttm = time2gpst(sto.ttm, &week); } - else { time2bdt(gpst2bdt(sto.tot), &weekRef); ttm = time2bdt(gpst2bdt(sto.ttm), &week); } /* gpst -> bdt */ + int week; + int weekRef; + double ttm; + if (sys != +E_Sys::BDS) { weekRef = GWeek(sto.tot); week = GWeek(sto.ttm); ttm = GTow(sto.ttm); } + else { weekRef = GWeek(sto.tot); week = GWeek(sto.ttm); ttm = GTow(sto.ttm) - 14; } /* gpst -> bdt */ traceFormatedFloat(trace, ttm + (week - weekRef) * 604800.0, formatStr); traceFormatedFloat(trace, sto.A0, formatStr); traceFormatedFloat(trace, sto.A1, formatStr); @@ -435,10 +445,10 @@ void outputNavRinexEOP( auto sys = eop.Sat.sys; - double ep[6]; - if (sys != +E_Sys::BDS) { time2epoch(eop.teop, ep); } - else { time2epoch(gpst2bdt(eop.teop), ep); } - + GEpoch ep; + if (sys != +E_Sys::BDS) { ep = eop.teop; } +// else { ep = gpst2bdt(eop.teop); } + tracepdeex(0, trace, " %04.0f %02.0f %02.0f %02.0f %02.0f %02.0f", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); traceFormatedFloat(trace, eop.xp * R2AS, formatStr); @@ -454,10 +464,13 @@ void outputNavRinexEOP( trace << std::endl; trace << " "; - double ttm; - int week, weekRef; - if (sys != +E_Sys::BDS) { time2gpst(eop.teop, &weekRef); ttm = time2gpst(eop.ttm, &week); } - else { time2bdt(gpst2bdt(eop.teop), &weekRef); ttm = time2bdt(gpst2bdt(eop.ttm), &week); } /* gpst -> bdt */ + // double ttm; + // int week, weekRef; + // if (sys != +E_Sys::BDS) { time2gpst(eop.teop, &weekRef); ttm = time2gpst(eop.ttm, &week); } +// else { time2bdt(gpst2bdt(eop.teop), &weekRef); ttm = time2bdt(gpst2bdt(eop.ttm), &week); } /* gpst -> bdt */ + double ttm = GTow(eop.ttm); + int week = GWeek(eop.ttm); + int weekRef = GWeek(eop.teop); traceFormatedFloat(trace, ttm + (week - weekRef) * 604800.0, formatStr); traceFormatedFloat(trace, eop.dut1, formatStr); traceFormatedFloat(trace, eop.dur, formatStr); @@ -486,9 +499,9 @@ void outputNavRinexION( auto sys = ion.Sat.sys; auto type = ion.type; - double ep[6]; - if (sys != +E_Sys::BDS) { time2epoch(ion.ttm, ep); } - else { time2epoch(gpst2bdt(ion.ttm), ep); } + GEpoch ep; + if (sys != +E_Sys::BDS) { ep = ion.ttm; } +// else { ep = gpst2bdt(ion.ttm); } tracepdeex(0, trace, " %04.0f %02.0f %02.0f %02.0f %02.0f %02.0f", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); @@ -570,31 +583,32 @@ void outputNavRinexBody( { E_NavMsgType type = defNavMsgType[sys]; - ION* ion_ptr = seleph(std::cout, tsync, sys, type, nav); if (ion_ptr != nullptr) outputNavRinexION(*ion_ptr, rinexStream, rnxver); - EOP* eop_ptr = seleph(std::cout, tsync, sys, type, nav); if (eop_ptr != nullptr) outputNavRinexEOP(*eop_ptr, rinexStream, rnxver); + auto* ion_ptr = seleph(std::cout, tsync, sys, type, nav); if (ion_ptr != nullptr) outputNavRinexION(*ion_ptr, rinexStream, rnxver); + auto* eop_ptr = seleph(std::cout, tsync, sys, type, nav); if (eop_ptr != nullptr) outputNavRinexEOP(*eop_ptr, rinexStream, rnxver); } int idode = -1; - for (auto& [satId, satNav] : nav.satNavMap) + for (auto& [Sat, satNav] : nav.satNavMap) { - SatSys sat; - sat.fromHash(satId); - - if (sat.sys != sys) + if (Sat.sys != sys) continue; + E_NavMsgType nvtyp = acsConfig.used_nav_types[Sat.sys]; + if (sys == +E_Sys::GLO) { - Geph* geph_ptr = seleph(std::cout, tsync, sat, -1, nav); + auto geph_ptr = seleph(std::cout, tsync, Sat, nvtyp, ANY_IODE, nav); if (geph_ptr == nullptr) continue; + + auto& geph = *geph_ptr; - if ( outFileData.last_iode.find(sat) == outFileData.last_iode.end() - ||geph_ptr->iode != outFileData.last_iode[sat]) + if ( outFileData.last_iode.find(Sat) == outFileData.last_iode.end() + ||geph.iode != outFileData.last_iode[Sat]) { - outFileData.last_iode[sat] = geph_ptr->iode; - outputNavRinexGeph(*geph_ptr, rinexStream, rnxver); + outFileData.last_iode[Sat] = geph.iode; + outputNavRinexGeph(geph, rinexStream, rnxver); } continue; @@ -602,7 +616,7 @@ void outputNavRinexBody( else if (sys == +E_Sys::SBS) { //optional to do (probably not useful): Seph writing - // Seph* seph_ptr = seleph(std::cout, tsync, sat, -1, nav); + // Seph* seph_ptr = seleph(std::cout, tsync, sat, ANY_IODE, nav); // if (seph_ptr == nullptr) // continue; @@ -618,16 +632,16 @@ void outputNavRinexBody( } else { - Eph* eph_ptr = seleph(std::cout, tsync, sat, -1, nav); + auto eph_ptr = seleph(std::cout, tsync, Sat, nvtyp, ANY_IODE, nav); if (eph_ptr == nullptr) continue; // Note iode can be zero, checking the map makes a zero entry as well. - if ( outFileData.last_iode.find(sat) == outFileData.last_iode.end() - || eph_ptr->iode != outFileData.last_iode[sat]) + if ( outFileData.last_iode.find(Sat) == outFileData.last_iode.end() + || eph_ptr->iode != outFileData.last_iode[Sat]) { - outFileData.last_iode[sat] = eph_ptr->iode; + outFileData.last_iode[Sat] = eph_ptr->iode; outputNavRinexEph(*eph_ptr, rinexStream, rnxver); } @@ -643,15 +657,12 @@ void rinexNavHeader( Trace& rinexStream, const double rnxver) { - string prog = "PEA v1"; + string prog = "PEA v2"; string runby = "Geoscience Australia"; - GTime now = utc2gpst(timeget()); + GTime now = timeGet(); - char tempStr[20]; - time2str(now, tempStr, 0); - - string timeDate(tempStr); + string timeDate = now.to_string(); boost::replace_all(timeDate, "/", ""); boost::replace_all(timeDate, ":", ""); timeDate += " UTC"; @@ -749,10 +760,10 @@ void rinexNavHeader( for (auto& [dummy, sto] : stoList) { - int week; - double tow; - if (sys == +E_Sys::BDS) { tow = time2bdt(gpst2bdt(sto.tot), &week); } /* gpst -> bdt */ - else { tow = time2gpst(sto.tot, &week); } + int week; + double tow; + if (sys == +E_Sys::BDS) { tow = BTow(sto.tot); week = BWeek(sto.tot); } + else { tow = GTow(sto.tot); week = GWeek(sto.tot); } tracepdeex(0, rinexStream, "%s %17.10E%16.9E%7.0f%5.0f %-5s %-2s %-20s\n", code._to_string(), @@ -781,6 +792,7 @@ void writeRinexNav(const double rnxver) if (!rinexStream) { BOOST_LOG_TRIVIAL(error) << "Error opening " << filename << " for writing rinex nav"; + return; } if (rinexStream.tellp() == 0) @@ -820,13 +832,15 @@ void outputNavRinexBodyAll( } } - for (auto& [satId, ephList] : nav.ephMap) + for (auto& [satId, navList] : nav.ephMap) + for (auto& [nvtyp, ephList] : navList) for (auto& [time, eph] : ephList) { outputNavRinexEph(eph, rinexStream, rnxver); } - for (auto& [satId, gephList] : nav.gephMap) + for (auto& [satId, navList] : nav.gephMap) + for (auto& [nvtyp, gephList] : navList) for (auto& [time, geph] : gephList) { outputNavRinexGeph(geph, rinexStream, rnxver); @@ -862,10 +876,12 @@ void writeRinexNavAll(string filename, const double rnxver) if (!rinexStream) { BOOST_LOG_TRIVIAL(error) << "Error opening " << filename << " for writing rinex nav"; + return; } if (rinexStream.tellp() == 0) rinexNavHeader(sysMap, rinexStream, rnxver); + outputNavRinexBodyAll(rinexStream, rnxver); } diff --git a/src/cpp/common/rinexNavWrite.hpp b/src/cpp/common/rinexNavWrite.hpp index 37b1e02f5..d62254f03 100644 --- a/src/cpp/common/rinexNavWrite.hpp +++ b/src/cpp/common/rinexNavWrite.hpp @@ -1,10 +1,6 @@ -#ifndef __OUTPUTNAVRINEX__HPP__ -#define __OUTPUTNAVRINEX__HPP__ +#pragma once -void writeRinexNav(const double rnxver = 3.05); - -void writeRinexNavAll(std::string filename, const double rnxver = 3.05); - -#endif +void writeRinexNav( + const double rnxver = 3.05); diff --git a/src/cpp/common/rinexObsWrite.cpp b/src/cpp/common/rinexObsWrite.cpp index 75dc288b6..513c98afa 100644 --- a/src/cpp/common/rinexObsWrite.cpp +++ b/src/cpp/common/rinexObsWrite.cpp @@ -16,11 +16,11 @@ using std::pair; #include "rinexObsWrite.hpp" #include "rinexClkWrite.hpp" #include "observations.hpp" -#include "streamTrace.hpp" #include "instrument.hpp" #include "acsConfig.hpp" #include "common.hpp" #include "sinex.hpp" +#include "trace.hpp" struct RinexOutput { @@ -28,7 +28,7 @@ struct RinexOutput long headerObsPos = 0; long headerTimePos = 0; - map>> codesPerSys; + map>> codesPerSys; }; map filenameObsFileDataMap; @@ -129,10 +129,10 @@ void updateRinexObsHeader( if (rinexOutput.headerTimePos == 0) { - string tsys = "GPS"; // PEA internal time is GPS. - double ep[6]; - time2epoch(firstObsTime, ep); + string timeSysStr = "GPS"; // PEA internal time is GPS. + GEpoch ep = firstObsTime; + tracepdeex(0, rinexStream, "%10.3f%50s%-20s\n", acsConfig.epoch_interval, "", @@ -145,7 +145,7 @@ void updateRinexObsHeader( ep[3], ep[4], ep[5], - tsys, + timeSysStr, "TIME OF FIRST OBS"); rinexOutput.headerTimePos = rinexStream.tellp(); @@ -158,14 +158,14 @@ void updateRinexObsHeader( ep[3], ep[4], ep[5], - tsys, + timeSysStr, "TIME OF LAST OBS"); } } void writeRinexObsHeader( RinexOutput& fileData, - Sinex_stn_snx_t& snx, + SinexRecData& snx, std::fstream& rinexStream, GTime& firstObsTime, const double rnxver) @@ -173,17 +173,14 @@ void writeRinexObsHeader( fileData.headerTimePos = 0; // Write the RINEX header. - GTime now = utc2gpst(timeget()); - - char tempStr[20]; - time2str(now, tempStr, 0); + GTime now = timeGet(); - string timeDate(tempStr); + string timeDate = now.to_string(); boost::replace_all(timeDate, "/", ""); boost::replace_all(timeDate, ":", ""); timeDate += " UTC"; - string prog = "PEA v1"; + string prog = "PEA v2"; string runby = "Geoscience Australia"; tracepdeex(0, rinexStream, "%9.2f%-11s%-20s%-20s%-20s\n", @@ -200,11 +197,11 @@ void writeRinexObsHeader( "PGM / RUN BY / DATE"); tracepdeex(0, rinexStream, "%-60.60s%-20s\n", - snx.sitecode, + snx.id_ptr->sitecode, "MARKER NAME"); tracepdeex(0, rinexStream, "%-20.20s%-40.40s%-20s\n", - snx.monuid, + snx.id_ptr->domes, "", "MARKER NUMBER"); @@ -217,14 +214,14 @@ void writeRinexObsHeader( "OBSERVER / AGENCY"); tracepdeex(0, rinexStream, "%-20.20s%-20.20s%-20.20s%-20s\n", - snx.recsn, - snx.rectype, - snx.recfirm, + snx.rec_ptr->sn, + snx.rec_ptr->type, + snx.rec_ptr->firm, "REC # / TYPE / VERS"); tracepdeex(0, rinexStream, "%-20.20s%-20.20s%-20.20s%-20s\n", - snx.antsn, - snx.anttype, + snx.ant_ptr->sn, + snx.ant_ptr->type, "", "ANT # / TYPE"); @@ -236,9 +233,9 @@ void writeRinexObsHeader( "APPROX POSITION XYZ"); tracepdeex(0, rinexStream, "%14.4f%14.4f%14.4f%-18s%-20s\n", - snx.ecc[2], - snx.ecc[1], - snx.ecc[0], + snx.ecc_ptr->ecc[2], + snx.ecc_ptr->ecc[1], + snx.ecc_ptr->ecc[0], "", "ANTENNA: DELTA H/E/N"); @@ -258,9 +255,8 @@ void writeRinexObsBody( GTime& time, map& sysMap) { - string tsys = "GPS"; // PEA internal time is GPS. - double ep[6]; - time2epoch(time, ep); + GEpoch ep = time; + string timeSysStr = "GPS"; // PEA internal time is GPS. rinexStream.seekp(fileData.headerTimePos); tracepdeex(0, rinexStream, " %04.0f%6.0f%6.0f%6.0f%6.0f%13.7f %-12s%-20s\n", @@ -270,12 +266,23 @@ void writeRinexObsBody( ep[3], ep[4], ep[5], - tsys, + timeSysStr, "TIME OF LAST OBS"); // Write the RINEX body. rinexStream.seekp(0, std::ios::end); + int count = 0; + for (auto& obs : only(obsList)) + { + if (sysMap[obs.Sat.sys] == false) + { + continue; + } + + count++; + } + // flag epoch flag (0:ok,1:power failure,>1:event flag) int flag = 0; tracepdeex(0, rinexStream, "> %04.0f %02.0f %02.0f %02.0f %02.0f%11.7f %d%3d%21s\n", @@ -286,10 +293,10 @@ void writeRinexObsBody( ep[4], ep[5], flag, - obsList.size(), + count, ""); - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { if (sysMap[obs.Sat.sys] == false) { @@ -324,8 +331,7 @@ void writeRinexObsBody( foundObsPair = true; } - double sn_raw = (sig.snr - 0.5) / 4; - int sn_rnx = std::min(std::max((int)std::round(sn_raw / 6.0), 1), 9); + int sn_rnx = std::min(std::max((int)std::round(sig.snr / 6.0), 1), 9); switch (obsDesc) { @@ -346,8 +352,8 @@ void writeRinexObsBody( break; case E_ObsDesc::S: - if (sn_raw == 0) tracepdeex(0, rinexStream, "%14.3s ", ""); - else tracepdeex(0, rinexStream, "%14.3f ", sn_raw); + if (sig.snr == 0) tracepdeex(0, rinexStream, "%14.3s ", ""); + else tracepdeex(0, rinexStream, "%14.3f ", sig.snr); break; default: @@ -366,13 +372,13 @@ void writeRinexObsBody( } } -bool updateRinexObsOutput( +bool updateRinexObsOutput( RinexOutput& rinexOutput, ///< Information for writing file. ObsList& obsList, ///< List of observation data map sysMap) ///< Options to enable outputting specific systems { bool foundNew = false; - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { E_Sys sys = obs.Sat.sys; @@ -394,12 +400,11 @@ bool updateRinexObsOutput( code = sig.code; - double sn_raw = (sig.snr - 0.5) / 4; //todo aaron, check this code = sig.code; type = E_ObsDesc::C; if (std::find(codes.begin(), codes.end(), codePair) == codes.end() &&sig.P != 0 &&acsConfig.rinex_obs_print_C_code) { foundNew = true; codes.push_back(codePair); } type = E_ObsDesc::L; if (std::find(codes.begin(), codes.end(), codePair) == codes.end() &&sig.L != 0 &&acsConfig.rinex_obs_print_L_code) { foundNew = true; codes.push_back(codePair); } type = E_ObsDesc::D; if (std::find(codes.begin(), codes.end(), codePair) == codes.end() &&sig.D != 0 &&acsConfig.rinex_obs_print_D_code) { foundNew = true; codes.push_back(codePair); } - type = E_ObsDesc::S; if (std::find(codes.begin(), codes.end(), codePair) == codes.end() &&sn_raw != 0 &&acsConfig.rinex_obs_print_S_code) { foundNew = true; codes.push_back(codePair); } + type = E_ObsDesc::S; if (std::find(codes.begin(), codes.end(), codePair) == codes.end() &&sig.snr != 0 &&acsConfig.rinex_obs_print_S_code) { foundNew = true; codes.push_back(codePair); } } if (codes.size() == 0) @@ -411,7 +416,7 @@ bool updateRinexObsOutput( void writeRinexObsFile( RinexOutput& fileData, - Sinex_stn_snx_t& snx, + SinexRecData& snx, string fileName, ObsList& obsList, GTime& time, @@ -447,17 +452,17 @@ void writeRinexObsFile( map rinexObsFilenameMap; void writeRinexObs( - string& id, - Sinex_stn_snx_t& snx, - GTime& time, - ObsList& obsList, - const double rnxver) + string& id, + SinexRecData& snx, + GTime& time, + ObsList& obsList, + const double rnxver) { Instrument instrument(__FUNCTION__); string filename = acsConfig.rinex_obs_filename; - auto filenameSysMap = getSysOutputFilenames(filename, time, id); + auto filenameSysMap = getSysOutputFilenames(filename, time, true, id); for (auto [filename, sysMap] : filenameSysMap) { diff --git a/src/cpp/common/rinexObsWrite.hpp b/src/cpp/common/rinexObsWrite.hpp index ec672e732..ce4887114 100644 --- a/src/cpp/common/rinexObsWrite.hpp +++ b/src/cpp/common/rinexObsWrite.hpp @@ -1,11 +1,11 @@ -#ifndef __RINEXOUTPUT_H__ -#define __RINEXOUTPUT_H__ + +#pragma once + #include #include #include #include -#include #include @@ -13,22 +13,20 @@ using std::string; #include "observations.hpp" -struct Sinex_stn_snx_t; +struct SinexRecData; void writeRinexObs( - string& id, - Sinex_stn_snx_t& snx, - GTime& time, - ObsList& obsList, - const double rnxver = 3.05); + string& id, + SinexRecData& snx, + GTime& time, + ObsList& obsList, + const double rnxver = 3.05); map> getSysOutputFilenames( string filename, GTime logtime, + bool replaceSys = true, string id = ""); extern map rinexObsFilenameMap; -typedef map OutSys; - -#endif diff --git a/src/cpp/common/rtcmDecoder.cpp b/src/cpp/common/rtcmDecoder.cpp index e76b8adc0..64d4c095b 100644 --- a/src/cpp/common/rtcmDecoder.cpp +++ b/src/cpp/common/rtcmDecoder.cpp @@ -5,471 +5,726 @@ #include "rtcmEncoder.hpp" #include "rtcmDecoder.hpp" #include "streamRtcm.hpp" +#include "mongoWrite.hpp" #include "biasSINEX.hpp" #include "acsConfig.hpp" +#include "otherSSR.hpp" #include "gTime.hpp" #include "enums.h" -GTime RtcmDecoder::nowTime() +double RtcmDecoder::rtcmDeltaTime = 0; + +map RtcmDecoder::receivedTimeMap; + +map carrierFrequency = { - GTime now; - - if (rtcm_UTC != GTime::noTime()) now = rtcm_UTC; - else if (tsync != GTime::noTime()) now = tsync; - else now = timeget(); - - return now; -} + {F1, FREQ1}, + {F2, FREQ2}, + {F5, FREQ5}, + {F6, FREQ6}, + {F7, FREQ7}, + {F8, FREQ8}, + {G1, FREQ1_GLO}, + {G2, FREQ2_GLO}, + {G3, FREQ3_GLO}, + {G4, FREQ4_GLO}, + {G6, FREQ6_GLO}, + {B1, FREQ1_CMP}, + {B3, FREQ3_CMP} +}; -int RtcmDecoder::adjgpsweek( - int week) + +GTime RtcmDecoder::rtcmTime() { - int w; - GTime now = nowTime(); + GTime time; - time2gpst(now,&w); - if (w < 1560) - w = 1560; /* use 2009/12/1 if time is earlier than 2009/12/1 */ - - return week+(w-week+512)/1024*1024; + if (rtcmTimestampTime != GTime::noTime()) time = rtcmTimestampTime; + // todo Eugene: time from obs + // todo Eugene: gps nav + else if (tsync != GTime::noTime()) time = tsync; + else time = timeGet(); + + return time; } -GTime RtcmDecoder::tow2Time( - double tow) +/** adjust GPS week number according to RTCM time + */ +int RtcmDecoder::adjGpsWeek( + int week) ///< not-adjusted GPS week number { - GTime now = nowTime(); + GWeek nowWeek = rtcmTime(); + + int dWeeks = nowWeek - week; + int roundDWeeks = (dWeeks + 512) / 1024 * 1024; - int week; - double tow_p = time2gpst(now, &week); + return (week + roundDWeeks); +} + +/** adjust GST week number according to RTCM time + */ +int RtcmDecoder::adjGstWeek( + int week) ///< not-adjusted GST week number +{ + GWeek nowWeek = rtcmTime(); - int sPerWeek = 60*60*24*7; - if (tow < tow_p - sPerWeek/2) tow += sPerWeek; - else if (tow > tow_p + sPerWeek/2) tow -= sPerWeek; + int dWeeks = nowWeek - week; + int roundDWeeks = (dWeeks + 2048) / 4096 * 4096; - return gpst2time(week, tow); + return (week + roundDWeeks); } -GTime RtcmDecoder::getGpst() +/** adjust BDT week number according to RTCM time + */ +int RtcmDecoder::adjBdtWeek( + int week) ///< not-adjusted BDT week number { - return utc2gpst(timeget()); + BWeek nowWeek = rtcmTime(); + + int dWeeks = nowWeek - week; + int roundDWeeks = (dWeeks + 4096) / 8192 * 8192; + + return (week + roundDWeeks); } E_RTCMSubmessage RtcmDecoder::decodeCustomId( - uint8_t* data, - unsigned int message_length) + vector& message) { int i = 0; - int message_number = getbituInc(data, i, 12); + + int messageNumber = getbituInc(message, i, 12); + int customMessageNumber = getbituInc(message, i, 8); - E_RTCMSubmessage customType = E_RTCMSubmessage::_from_integral(getbituInc(data, i, 8)); + E_RTCMSubmessage customType = E_RTCMSubmessage::_from_integral(customMessageNumber); return customType; } -GTime RtcmDecoder::decodeCustomTimestamp( - uint8_t* data, - unsigned int message_length) +PTime RtcmDecoder::decodeCustomTimestamp( + vector& data) { int i = 0; - int message_number = getbituInc(data, i, 12); - - E_RTCMSubmessage customType = E_RTCMSubmessage::_from_integral(getbituInc(data, i, 8)); - - GTime time; - unsigned int* var = (unsigned int*) &time.time; - - var[0] = getbituInc(data,i,32); - var[1] = getbituInc(data,i,32); + + int messageNumber = getbituInc(data, i, 12); + int customMessageNumber = getbituInc(data, i, 8); - int milli_sec = getbituInc(data,i,10); + E_RTCMSubmessage customType = E_RTCMSubmessage::_from_integral(customMessageNumber); - time.sec = (double)milli_sec / 1000.0; + PTime time; + + int reserved = getbituInc(data, i, 4); + + unsigned int chunk1 = getbituInc(data, i, 32); + unsigned int chunk2 = getbituInc(data, i, 32); + + long int milliseconds = ((unsigned long int) chunk1) + + (((unsigned long int) chunk2) << 32); + + time.bigTime = milliseconds / 1000.0; return time; } - +/** decode RTCM SSR messages + */ void RtcmDecoder::decodeSSR( - uint8_t* data, - unsigned int message_length) + vector& data) ///< stream data { int i = 0; - int message_number = getbituInc(data, i, 12); - int epochTime1s = getbituInc(data, i, 20); - int ssrUpdateIntIndex = getbituInc(data, i, 4); - int multipleMessage = getbituInc(data, i, 1); - - int ssrUpdateInterval = updateInterval[ssrUpdateIntIndex]; - - double epochTime = epochTime1s + ssrUpdateInterval / 2.0; -// std::cout << "SSR message received: " << message_number << std::endl; + + int messageNumber = getbituInc(data, i, 12); - GTime messTime = tow2Time(epochTime); - traceLatency(messTime); +// std::cout << "SSR message received: " << messageNumber << std::endl; - E_Sys sys = E_Sys::NONE; - if ( message_number == +RtcmMessageType::GPS_SSR_ORB_CORR - ||message_number == +RtcmMessageType::GPS_SSR_CLK_CORR - ||message_number == +RtcmMessageType::GPS_SSR_COMB_CORR - ||message_number == +RtcmMessageType::GPS_SSR_CODE_BIAS - ||message_number == +RtcmMessageType::GPS_SSR_PHASE_BIAS - ||message_number == +RtcmMessageType::GPS_SSR_URA) + RtcmMessageType messCode; + try { - sys = E_Sys::GPS; + messCode = RtcmMessageType::_from_integral(messageNumber); } - else if ( message_number == +RtcmMessageType::GAL_SSR_ORB_CORR - ||message_number == +RtcmMessageType::GAL_SSR_CLK_CORR - ||message_number == +RtcmMessageType::GAL_SSR_CODE_BIAS - ||message_number == +RtcmMessageType::GAL_SSR_PHASE_BIAS - ||message_number == +RtcmMessageType::GAL_SSR_COMB_CORR) + catch (...) { - sys = E_Sys::GAL; + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in " << __FUNCTION__; + return; } - else + + string messCodeStr = messCode._to_string(); + string messTypeStr = messCodeStr.substr(8); + + E_Sys sys = rtcmMessageSystemMap[messCode]; + + if (sys == +E_Sys::NONE) { - BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in SSRDecoder::decode()"; + BOOST_LOG_TRIVIAL(error) << "Error: invalid message code system :" << messCode; + return; } + + if ( sys != +E_Sys::GPS + &&sys != +E_Sys::GLO + &&sys != +E_Sys::GAL + &&sys != +E_Sys::QZS + &&sys != +E_Sys::SBS + &&sys != +E_Sys::BDS) + { + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in " << __FUNCTION__; + } + + // if (sys == +E_Sys::BDS) + // { + // printf ("\nRTCM %4d: ", messageNumber); + // for (auto& dat : data) printf("%02X",dat); + // printf ("\n"); + // } + int ne = 0; + int ns = 0; int np = 0; int ni = 0; int nj = 0; - int offp = 0; switch (sys) { - case E_Sys::GPS: np=6; ni= 8; nj= 0; offp= 0; break; - case E_Sys::GLO: np=5; ni= 8; nj= 0; offp= 0; break; - case E_Sys::GAL: np=6; ni=10; nj= 0; offp= 0; break; - case E_Sys::QZS: np=4; ni= 8; nj= 0; offp=192; break; - case E_Sys::BDS: np=6; ni=10; nj=24; offp= 1; break; - case E_Sys::SBS: np=6; ni= 9; nj=24; offp=120; break; - default: BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system in SSRDecoder::decode()"; + case E_Sys::GPS: ne = 20; ns = 6; np = 6; ni = 8; nj = 0; break; + case E_Sys::GLO: ne = 17; ns = 6; np = 5; ni = 8; nj = 0; break; + case E_Sys::GAL: ne = 20; ns = 6; np = 6; ni = 10; nj = 0; break; + case E_Sys::QZS: ne = 20; ns = 4; np = 4; ni = 8; nj = 0; break; + case E_Sys::BDS: ne = 20; ns = 6; np = 6; ni = 8; nj = 10; break; + case E_Sys::SBS: ne = 20; ns = 6; np = 6; ni = 9; nj = 0; break; + default: BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system in " << __FUNCTION__; return; } + int epochTime1s = getbituInc(data, i, ne); + int updateIntIndex = getbituInc(data, i, 4); + int multipleMessage = getbituInc(data, i, 1); + + int ssrUpdateInterval = updateInterval[updateIntIndex]; + + double referenceTime; + if (updateIntIndex == 0) referenceTime = epochTime1s; + else referenceTime = epochTime1s + ssrUpdateInterval / 2.0; + + GTime nearTime = rtcmTime(); + + GTime receivedTime; + GTime t0; + if (sys == +E_Sys::GLO) + { + receivedTime = GTime(RTod(epochTime1s), nearTime); + t0 = GTime(RTod(referenceTime), nearTime); + } + else if (sys == +E_Sys::BDS) + { + receivedTime = GTime(BTow(epochTime1s), nearTime); + t0 = GTime(BTow(referenceTime), nearTime); + } + else + { + receivedTime = GTime(GTow(epochTime1s), nearTime); + t0 = GTime(GTow(referenceTime), nearTime); + } + +// std::cout << "SSR message received: " << messCode << std::endl; + unsigned int referenceDatum = 0; - if ( message_number == +RtcmMessageType::GPS_SSR_ORB_CORR - ||message_number == +RtcmMessageType::GPS_SSR_COMB_CORR - ||message_number == +RtcmMessageType::GAL_SSR_ORB_CORR - ||message_number == +RtcmMessageType::GAL_SSR_COMB_CORR) + if ( messTypeStr == "ORB_CORR" + ||messTypeStr == "COMB_CORR") { - referenceDatum = getbituInc(data, i, 1); + referenceDatum = getbituInc(data, i, 1); } - unsigned int iod = getbituInc(data, i, 4); - unsigned int provider = getbituInc(data, i, 16); - unsigned int solution = getbituInc(data, i, 4); - - unsigned int dispBiasConistInd; - unsigned int MWConistInd; - if ( message_number == +RtcmMessageType::GPS_SSR_PHASE_BIAS - ||message_number == +RtcmMessageType::GAL_SSR_PHASE_BIAS ) + + unsigned int iod = getbituInc(data, i, 4); + unsigned int provider = getbituInc(data, i, 16); + unsigned int solution = getbituInc(data, i, 4); + + unsigned int dispBiasConistInd = 0; + unsigned int MWConistInd = 0; + if ( messTypeStr == "PHASE_BIAS") { - dispBiasConistInd = getbituInc(data, i, 1); - MWConistInd = getbituInc(data, i, 1); + dispBiasConistInd = getbituInc(data, i, 1); + MWConistInd = getbituInc(data, i, 1); } - unsigned int numSats = getbituInc(data, i, 6); + unsigned int numSats = getbituInc(data, i, ns); // SRR variables for encoding and decoding. SSRMeta ssrMeta; ssrMeta.epochTime1s = epochTime1s; - ssrMeta.ssrUpdateIntIndex = ssrUpdateIntIndex; + ssrMeta.receivedTime = receivedTime; + ssrMeta.updateIntIndex = updateIntIndex; ssrMeta.multipleMessage = multipleMessage; ssrMeta.referenceDatum = referenceDatum; ssrMeta.provider = provider; ssrMeta.solution = solution; + ssrMeta.numSats = numSats; + bool failure = false; + for (int sat = 0; sat < numSats; sat++) { - unsigned int satId = getbituInc(data, i, np)+offp; + unsigned int satId = getbituInc(data, i, np); SatSys Sat(sys, satId); auto& ssr = nav.satNavMap[Sat].receivedSSR; - if ( message_number == +RtcmMessageType::GPS_SSR_ORB_CORR - ||message_number == +RtcmMessageType::GPS_SSR_COMB_CORR - ||message_number == +RtcmMessageType::GAL_SSR_ORB_CORR - ||message_number == +RtcmMessageType::GAL_SSR_COMB_CORR) + if ( messTypeStr == "ORB_CORR" + ||messTypeStr == "COMB_CORR") { SSREph ssrEph; - ssrEph.ssrMeta = ssrMeta; - - ssrEph.t0 = tow2Time(epochTime); - + ssrEph.ssrMeta = ssrMeta; + ssrEph.t0 = t0; ssrEph.udi = ssrUpdateInterval; ssrEph.iod = iod; + + ssrEph.iodcrc = getbituInc(data, i, nj); ssrEph.iode = getbituInc(data, i, ni); - // ??ssrEph.iodcrc = getbituInc(data, i, nj); - ssrEph.deph[0] = getbitsInc(data, i, 22) * 0.1e-3; // Position, radial, along track, cross track. + ssrEph.deph[0] = getbitsInc(data, i, 22) * 0.1e-3; // Position, radial, along track, cross track. ssrEph.deph[1] = getbitsInc(data, i, 20) * 0.4e-3; ssrEph.deph[2] = getbitsInc(data, i, 20) * 0.4e-3; - ssrEph.ddeph[0] = getbitsInc(data, i, 21) * 0.001e-3; // Velocity + ssrEph.ddeph[0] = getbitsInc(data, i, 21) * 0.001e-3; // Velocity ssrEph.ddeph[1] = getbitsInc(data, i, 19) * 0.004e-3; ssrEph.ddeph[2] = getbitsInc(data, i, 19) * 0.004e-3; - //tracepdeex(0,std::cout, "\n#RTCM_DEC SSRORB %s %s %4d %10.3f %10.3f %10.3f %d ", Sat.id().c_str(),ssrEph.t0.to_string(2).c_str(), ssrEph.iode,ssrEph.deph[0],ssrEph.deph[1],ssrEph.deph[2], iod); - if ( ssr.ssrEph_map.empty() - ||ssrEph.iod != ssr.ssrEph_map.begin()->second.iod - ||ssrEph.t0 != ssr.ssrEph_map.begin()->second.t0) - { - ssr.ssrEph_map[ssrEph.t0] = ssrEph; - } + tracepdeex(6,std::cout, "\n#RTCM_SSR ORBITS %s %s %4d %10.3f %10.3f %10.3f %d ", Sat.id().c_str(),ssrEph.t0.to_string(2).c_str(), ssrEph.iode,ssrEph.deph[0],ssrEph.deph[1],ssrEph.deph[2], iod); + + ssr.ssrEph_map[receivedTime] = ssrEph; if (acsConfig.output_decoded_rtcm_json) - outputSsrEphToJson(ssrEph, Sat); + traceSsrEph(messCode, Sat, ssrEph); } - if ( message_number == +RtcmMessageType::GPS_SSR_CLK_CORR - ||message_number == +RtcmMessageType::GPS_SSR_COMB_CORR - ||message_number == +RtcmMessageType::GAL_SSR_CLK_CORR - ||message_number == +RtcmMessageType::GAL_SSR_COMB_CORR) + if ( messTypeStr == "CLK_CORR" + ||messTypeStr == "COMB_CORR") { SSRClk ssrClk; - ssrClk.ssrMeta = ssrMeta; - - ssrClk.t0 = tow2Time(epochTime); - + ssrClk.ssrMeta = ssrMeta; + ssrClk.t0 = t0; ssrClk.udi = ssrUpdateInterval; ssrClk.iod = iod; // C = C_0 + C_1(t-t_0)+C_2(t-t_0)^2 where C is a correction in meters. // C gets converted into a time correction for futher calculations. + ssrClk.dclk[0] = getbitsInc(data, i, 22) * 0.1e-3; ssrClk.dclk[1] = getbitsInc(data, i, 21) * 0.001e-3; ssrClk.dclk[2] = getbitsInc(data, i, 27) * 0.00002e-3; - //tracepdeex(0,std::cout, "\n#RTCM_DEC SSRCLK %s %s %10.3f %10.3f %10.3f %d", Sat.id().c_str(),ssrClk.t0.to_string(2).c_str(), ssrClk.dclk[0],ssrClk.dclk[1],ssrClk.dclk[2], iod); - if ( ssr.ssrClk_map.empty() - ||ssrClk.iod != ssr.ssrClk_map.begin()->second.iod - ||ssrClk.t0 != ssr.ssrClk_map.begin()->second.t0) - { - ssr.ssrClk_map[ssrClk.t0] = ssrClk; - } + tracepdeex(6,std::cout, "\n#RTCM_SSR CLOCKS %s %s %10.3f %10.3f %10.3f %d", Sat.id().c_str(),ssrClk.t0.to_string(2).c_str(), ssrClk.dclk[0],ssrClk.dclk[1],ssrClk.dclk[2], iod); + + ssr.ssrClk_map[receivedTime] = ssrClk; if (acsConfig.output_decoded_rtcm_json) - outputSsrClkToJson(ssrClk, Sat); + traceSsrClk(messCode, Sat, ssrClk); } - if (message_number == +RtcmMessageType::GPS_SSR_URA) + if (messTypeStr == "URA") { //std::cout << "Received SSR URA Message.\n"; SSRUra ssrUra; - - ssrUra.t0 = tow2Time(epochTime); - + ssrUra.ssrMeta = ssrMeta; + ssrUra.t0 = t0; ssrUra.udi = ssrUpdateInterval; ssrUra.iod = iod; - ssrUra.ura = getbituInc(data, i, 6); - if ( ssr.ssrUra_map.empty() - ||ssrUra.iod != ssr.ssrUra_map.begin()->second.iod - ||ssrUra.t0 != ssr.ssrUra_map.begin()->second.t0) - { - // This is the total User Range Accuracy calculated from all the SSR. - // TODO: Check implementation, RTCM manual DF389. - ssr.ssrUra_map[ssrUra.t0] = ssrUra; - } + int uraClassValue = getbituInc(data, i, 6); + ssrUra.ura = ura_ssr[uraClassValue]; + + // This is the total User Range Accuracy calculated from all the SSR. + // TODO: Check implementation, RTCM manual DF389. + + ssr.ssrUra_map[receivedTime] = ssrUra; + + if (acsConfig.output_decoded_rtcm_json) + traceSsrUra(messCode, Sat, ssrUra); } - if ( message_number == +RtcmMessageType::GPS_SSR_CODE_BIAS - ||message_number == +RtcmMessageType::GAL_SSR_CODE_BIAS) + if (messTypeStr == "HR_CLK_CORR") { - SSRCodeBias ssrBiasCode; + SSRHRClk ssrHRClk; + ssrHRClk.ssrMeta = ssrMeta; + ssrHRClk.t0 = t0; + ssrHRClk.udi = ssrUpdateInterval; + ssrHRClk.iod = iod; + + ssrHRClk.hrclk = getbitsInc(data, i, 22) * 0.1e-3; - ssrBiasCode.t0 = tow2Time(epochTime); + ssr.ssrHRClk_map[receivedTime] = ssrHRClk; + + if (acsConfig.output_decoded_rtcm_json) + traceSsrHRClk(messCode, Sat, ssrHRClk); + } - ssrBiasCode.udi = ssrUpdateInterval; - ssrBiasCode.iod = iod; - ssrBiasCode.ssrMeta = ssrMeta; + if (messTypeStr == "CODE_BIAS") + { + SSRCodeBias ssrBiasCode; + ssrBiasCode.ssrMeta = ssrMeta; + ssrBiasCode.t0 = t0; + ssrBiasCode.udi = ssrUpdateInterval; + ssrBiasCode.iod = iod; - SinexBias entry; - string id = Sat.id() + ":" + Sat.sysChar(); + ssrBiasCode.nbias = getbituInc(data, i, 5); + BiasEntry entry; + string id; + if (Sat.sys == +E_Sys::GLO) id = Sat.id() + ":" + Sat.id(); + else id = Sat.id() + ":" + Sat.sysChar(); + entry.measType = CODE; entry.Sat = Sat; - entry.tini = tow2Time(epochTime); + entry.tini = t0; entry.tfin = entry.tini + acsConfig.ssrInOpts.code_bias_valid_time; entry.source = "ssr"; - unsigned int nbias = getbituInc(data, i, 5); - - for (int k = 0; k < nbias && i + 19 <= message_length * 8; k++) + for (int k = 0; k < ssrBiasCode.nbias && i + 19 <= data.size() * 8; k++) { - int rtcm_code = getbituInc(data, i, 5); - double bias = getbitsInc(data, i, 14) * 0.01; + int rtcmCode = getbituInc(data, i, 5); + double bias = getbitsIncScale(data, i, 14, 0.01, &failure); try { - E_ObsCode code; - if (sys == +E_Sys::GPS) { code = mCodes_gps.right.at(rtcm_code); } - else if (sys == +E_Sys::GAL) { code = mCodes_gal.right.at(rtcm_code); } + E_ObsCode obsCode; + if (sys == +E_Sys::GPS) { obsCode = mCodes_gps.right.at(rtcmCode); } + else if (sys == +E_Sys::GLO) { obsCode = mCodes_glo.right.at(rtcmCode); } + else if (sys == +E_Sys::GAL) { obsCode = mCodes_gal.right.at(rtcmCode); } + else if (sys == +E_Sys::QZS) { obsCode = mCodes_qzs.right.at(rtcmCode); } + else if (sys == +E_Sys::BDS) { obsCode = mCodes_bds.right.at(rtcmCode); } + else if (sys == +E_Sys::SBS) { obsCode = mCodes_sbs.right.at(rtcmCode); } else { - BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system in SSRDecoder::decode()"; + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system in " << __FUNCTION__; continue; } - ssrBiasCode.obsCodeBiasMap[code].bias = bias; //todo aaron missing var + + ssrBiasCode.obsCodeBiasMap[obsCode].bias = bias; //todo aaron missing var if (acsConfig.output_decoded_rtcm_json) - traceSsrCodeB(Sat, code, ssrBiasCode); + traceSsrCodeBias(messCode, Sat, obsCode, ssrBiasCode); - entry.cod1 = code; + entry.cod1 = obsCode; entry.cod2 = E_ObsCode::NONE; - entry.bias = -bias; - entry.var = 0; - entry.slop = 0; - entry.slpv = 0; + entry.bias = bias; + entry.var = 0; + entry.slop = 0; + entry.slpv = 0; pushBiasSinex(id, entry); + // BOOST_LOG_TRIVIAL(error) << "#RTCM_SSR CODBIA for " << Sat.id() << " rtcmCode: " << obsCode._to_string() << ": " << bias; } + catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "Error, Decoding SSR Message unknown RTCM code : " << rtcm_code; + // BOOST_LOG_TRIVIAL(error) << "Error, Decoding SSR Message unknown RTCM code : " << rtcmCode << " for " << rtcmMountPoint << " : " << messCode; + // BOOST_LOG_TRIVIAL(error) << "Code bias for " << Sat.id() << " rtcmCode: " << rtcmCode << ": " << bias; + continue; } } - if ( ssr.ssrCodeBias_map.empty() - ||ssrBiasCode.iod != ssr.ssrCodeBias_map.begin()->second.iod - ||ssrBiasCode.t0 != ssr.ssrCodeBias_map.begin()->second.t0) - { - ssr.ssrCodeBias_map[ssrBiasCode.t0] = ssrBiasCode; - } + ssr.ssrCodeBias_map[receivedTime] = ssrBiasCode; } - if ( message_number == +RtcmMessageType::GPS_SSR_PHASE_BIAS - ||message_number == +RtcmMessageType::GAL_SSR_PHASE_BIAS ) + if ( messTypeStr == "PHASE_BIAS") { SSRPhasBias ssrBiasPhas; SSRPhase ssrPhase; + ssrBiasPhas.ssrMeta = ssrMeta; + ssrBiasPhas.t0 = t0; + ssrBiasPhas.udi = ssrUpdateInterval; + ssrBiasPhas.iod = iod; - ssrBiasPhas.t0 = tow2Time(epochTime); + ssrPhase.dispBiasConistInd = dispBiasConistInd; + ssrPhase.MWConistInd = MWConistInd; - ssrBiasPhas.ssrMeta = ssrMeta; - ssrBiasPhas.udi = ssrUpdateInterval; - ssrBiasPhas.iod = iod; - - ssrPhase.dispBiasConistInd = dispBiasConistInd; - ssrPhase.MWConistInd = dispBiasConistInd; - ssrPhase.nbias = getbituInc(data, i, 5); - ssrPhase.yawAngle = getbituInc(data, i, 9)/256.0 *PI; - ssrPhase.yawRate = getbitsInc(data, i, 8)/8192.0 *PI; + ssrBiasPhas.nbias = getbituInc (data, i, 5); + ssrPhase.yawAngle = getbituIncScale (data, i, 9, 1/256.0 *SC2RAD); + ssrPhase.yawRate = getbitsIncScale (data, i, 8, 1/8192.0 *SC2RAD, &failure); ssrBiasPhas.ssrPhase = ssrPhase; - SinexBias entry; - string id = Sat.id() + ":" + Sat.sysChar(); + BiasEntry entry; + string id; + if (Sat.sys == +E_Sys::GLO) id = Sat.id() + ":" + Sat.id(); + else id = Sat.id() + ":" + Sat.sysChar(); entry.measType = PHAS; entry.Sat = Sat; - entry.tini = tow2Time(epochTime); + entry.tini = t0; entry.tfin = entry.tini + acsConfig.ssrInOpts.phase_bias_valid_time; + entry.source = "ssr"; - for (int k = 0; k < ssrPhase.nbias && i + 32 <= message_length * 8; k++) + for (int k = 0; k < ssrBiasPhas.nbias && i + 32 <= data.size() * 8; k++) { SSRPhaseCh ssrPhaseCh; - unsigned int rtcm_code = getbituInc(data, i, 5); + unsigned int rtcmCode = getbituInc(data, i, 5); ssrPhaseCh.signalIntInd = getbituInc(data, i, 1); - ssrPhaseCh.signalWidIntInd = getbituInc(data, i, 2); + ssrPhaseCh.signalWLIntInd = getbituInc(data, i, 2); ssrPhaseCh.signalDisconCnt = getbituInc(data, i, 4); - double phaseBias = getbitsInc(data, i, 20) * 0.0001; + double bias = getbitsIncScale(data, i, 20, 0.0001, &failure); try { - E_ObsCode code; - if (sys == +E_Sys::GPS) - { - code = mCodes_gps.right.at(rtcm_code); - } - else if (sys == +E_Sys::GAL) + E_ObsCode obsCode; + if (sys == +E_Sys::GPS) { obsCode = mCodes_gps.right.at(rtcmCode); } + else if (sys == +E_Sys::GLO) { obsCode = mCodes_glo.right.at(rtcmCode); } + else if (sys == +E_Sys::GAL) { obsCode = mCodes_gal.right.at(rtcmCode); } + else if (sys == +E_Sys::QZS) { obsCode = mCodes_qzs.right.at(rtcmCode); } + else if (sys == +E_Sys::BDS) { obsCode = mCodes_bds.right.at(rtcmCode); } + else if (sys == +E_Sys::SBS) { obsCode = mCodes_sbs.right.at(rtcmCode); } + else { - code = mCodes_gal.right.at(rtcm_code); + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system in " << __FUNCTION__; + continue; } - else - BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system in SSRDecoder::decode()"; - ssrBiasPhas.obsCodeBiasMap[code].bias = phaseBias; // offset meters due to satellite rotation. //todo aaron missing var - ssrBiasPhas.ssrPhaseChs [code] = ssrPhaseCh; + ssrBiasPhas.obsCodeBiasMap [obsCode].bias = bias; // offset meters due to satellite rotation. //todo aaron missing var + ssrBiasPhas.ssrPhaseChs [obsCode] = ssrPhaseCh; if (acsConfig.output_decoded_rtcm_json) - traceSsrPhasB(Sat, code, ssrBiasPhas); + traceSsrPhasBias(messCode, Sat, obsCode, ssrBiasPhas); - entry.cod1 = code; + entry.cod1 = obsCode; entry.cod2 = E_ObsCode::NONE; - entry.bias = -phaseBias; - entry.var = 0; - entry.slop = 0; - entry.slpv = 0; + entry.bias = bias; + entry.var = 0; + entry.slop = 0; + entry.slpv = 0; pushBiasSinex(id, entry); + // BOOST_LOG_TRIVIAL(error) << "#RTCM_SSR PHSBIA for " << Sat.id() << " rtcmCode: " << obsCode._to_string() << ": " << bias; } catch (std::exception& e) { - BOOST_LOG_TRIVIAL(error) << "Error, Decoding SSR Message unknown RTCM code : " << rtcm_code; + // BOOST_LOG_TRIVIAL(error) << "Error, Decoding SSR Message unknown RTCM code : " << rtcmCode << " for " << rtcmMountPoint << " : " << messCode; + continue; } } - if ( ssr.ssrPhasBias_map.empty() - ||ssrBiasPhas.iod != ssr.ssrPhasBias_map.begin()->second.iod - ||ssrBiasPhas.t0 != ssr.ssrPhasBias_map.begin()->second.t0) - { - ssr.ssrPhasBias_map[ssrBiasPhas.t0] = ssrBiasPhas; - } + ssr.ssrPhasBias_map[receivedTime] = ssrBiasPhas; } } } - +/** decode RTCM navigation messages + */ void RtcmDecoder::decodeEphemeris( - uint8_t* data, - unsigned int message_length) + vector& data) ///< stream data { - Eph eph = {}; + Eph eph = {}; + Geph geph = {}; int i = 0; - int message_number = getbituInc(data, i, 12); - E_Sys sys = E_Sys::NONE; - if ( message_number == RtcmMessageType::GPS_EPHEMERIS ) + int messageNumber = getbituInc(data, i, 12); + + RtcmMessageType messCode; + try { - sys = E_Sys::GPS; + messCode = RtcmMessageType::_from_integral(messageNumber); } - else if ( message_number == RtcmMessageType::GAL_FNAV_EPHEMERIS - ||message_number == RtcmMessageType::GAL_INAV_EPHEMERIS) + catch (...) { - sys = E_Sys::GAL; + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in " << __FUNCTION__; + return; } - else + + E_Sys sys = E_Sys::NONE; + switch (messageNumber) { - BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in EphemerisDecoder::decode()"; + case RtcmMessageType::GPS_EPHEMERIS: sys = E_Sys::GPS; break; + case RtcmMessageType::GLO_EPHEMERIS: sys = E_Sys::GLO; break; + case RtcmMessageType::BDS_EPHEMERIS: sys = E_Sys::BDS; break; + case RtcmMessageType::QZS_EPHEMERIS: sys = E_Sys::QZS; break; + case RtcmMessageType::GAL_FNAV_EPHEMERIS: //fallthrough + case RtcmMessageType::GAL_INAV_EPHEMERIS: sys = E_Sys::GAL; break; + default: + { + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in " << __FUNCTION__; + return; + } } + + bool failure = false; if (sys == +E_Sys::GPS) { - if (i + 476 > message_length * 8) + if (i + 488-12 > data.size() * 8) { - BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1019 length error: len=%d\n" << message_length; + BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1019 length error: len=" << data.size(); return; } + eph.type = E_NavMsgType::LNAV; + int prn = getbituInc(data, i, 6); - eph.week = adjgpsweek(getbituInc(data, i, 10)); - eph.sva = getbituInc(data, i, 4); - eph.code = getbituInc(data, i, 2); + eph.weekRollOver= getbituInc(data, i, 10); eph.week = adjGpsWeek(eph.weekRollOver); // rolled-over week -> full week number + eph.sva = getbituInc(data, i, 4); eph.ura[0] = svaToUra(eph.sva); + eph.code = getbituInc(data, i, 2); + eph.idot = getbitsInc(data, i, 14)*P2_43*SC2RAD; + eph.iode = getbituInc(data, i, 8); + eph.tocs = getbituInc(data, i, 16)*16.0; + eph.f2 = getbitsInc(data, i, 8)*P2_55; + eph.f1 = getbitsInc(data, i, 16)*P2_43; + eph.f0 = getbitsInc(data, i, 22)*P2_31; + eph.iodc = getbituInc(data, i, 10); + eph.crs = getbitsInc(data, i, 16)*P2_5; + eph.deln = getbitsInc(data, i, 16)*P2_43*SC2RAD; + eph.M0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.cuc = getbitsInc(data, i, 16)*P2_29; + eph.e = getbituInc(data, i, 32)*P2_33; + eph.cus = getbitsInc(data, i, 16)*P2_29; + eph.sqrtA = getbituInc(data, i, 32)*P2_19; eph.A = SQR(eph.sqrtA); + eph.toes = getbituInc(data, i, 16)*16.0; + eph.cic = getbitsInc(data, i, 16)*P2_29; + eph.OMG0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.cis = getbitsInc(data, i, 16)*P2_29; + eph.i0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.crc = getbitsInc(data, i, 16)*P2_5; + eph.omg = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.OMGd = getbitsInc(data, i, 24)*P2_43*SC2RAD; + eph.tgd[0] = getbitsInc(data, i, 8)*P2_31; + int svh = getbituInc(data, i, 6); eph.svh = (E_Svh)svh; + eph.flag = getbituInc(data, i, 1); + eph.fitFlag = getbituInc(data, i, 1); eph.fit = eph.fitFlag?0.0:4.0; // 0:4hr,1:>4hr + + if (prn >= 40) + { + sys = E_Sys::SBS; + prn += 80; + } + eph.Sat = SatSys(sys, prn); + + GTime nearTime = rtcmTime(); + + eph.ttm = nearTime; + eph.toe = GTime(GTow(eph.toes), nearTime); + eph.toc = GTime(GTow(eph.tocs), nearTime); + + decomposeTGDBias(eph.Sat, eph.tgd[0]); + } + else if (sys == +E_Sys::GLO) + { + if (i + 360-12 > data.size() * 8) + { + BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1020 length error: len=" << data.size(); + return; + } + + geph.type = E_NavMsgType::FDMA; + + int prn = getbituInc(data, i, 6); + geph.frq = getbituInc(data, i, 5)-7; i += 4; // skip DF104, 105, 106 (almanac health, P1) + geph.tk_hour = getbituInc(data, i, 5); + geph.tk_min = getbituInc(data, i, 6); + geph.tk_sec = getbituInc(data, i, 1)*30; + int svh = getbituInc(data, i, 1); geph.svh = (E_Svh)svh; + + int dummy = getbituInc(data, i, 1); // skip DF109 (P2) + geph.tb = getbituInc(data, i, 7); geph.iode = geph.tb; + geph.vel[0] = getbitgInc(data, i, 24)*P2_20*1E3; + geph.pos[0] = getbitgInc(data, i, 27)*P2_11*1E3; + geph.acc[0] = getbitgInc(data, i, 5)*P2_30*1E3; + geph.vel[1] = getbitgInc(data, i, 24)*P2_20*1E3; + geph.pos[1] = getbitgInc(data, i, 27)*P2_11*1E3; + geph.acc[1] = getbitgInc(data, i, 5)*P2_30*1E3; + geph.vel[2] = getbitgInc(data, i, 24)*P2_20*1E3; + geph.pos[2] = getbitgInc(data, i, 27)*P2_11*1E3; + geph.acc[2] = getbitgInc(data, i, 5)*P2_30*1E3; + dummy = getbituInc(data, i, 1); // skip DF120 (P3) + geph.gammaN = getbitgInc(data, i, 11)*P2_40; + dummy = getbituInc(data, i, 3); // skip DF122, 123 (P, ln) + geph.taun = getbitgInc(data, i, 22)*P2_30; + geph.dtaun = getbitgInc(data, i, 5)*P2_30; + geph.age = getbituInc(data, i, 5); + dummy = getbituInc(data, i, 5); // skip DF127, 128 (P4, FT) + geph.NT = getbituInc(data, i, 11); // GLONASS-M only, may be arbitrary value + geph.glonassM = getbituInc(data, i, 2); // if GLONASS-M data feilds valid + geph.moreData = getbituInc(data, i, 1); // availability of additional data + i += 43; // skip DF132, 133 (NA, tauc) + geph.N4 = getbituInc(data, i, 5); // additional data and GLONASS-M only, may be arbitrary value + + geph.Sat = SatSys(sys, prn); + + RTod toes = geph.tb * 15 * 60; + + RTod tofs = geph.tk_hour * 60 * 60 + + geph.tk_min * 60 + + geph.tk_sec; + + GTime nearTime = rtcmTime(); + geph.toe = GTime(toes, nearTime); + geph.tof = GTime(tofs, nearTime); + } + else if (sys == +E_Sys::BDS) + { + if (i + 511-12 > data.size() * 8) + { + BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1042 length error: len=" << data.size(); + return; + } + + eph.type = E_NavMsgType::D1; + + int prn = getbituInc(data, i, 6); + eph.weekRollOver= getbituInc(data, i, 13); eph.week = adjBdtWeek(eph.weekRollOver); // rolled-over week -> full week number + eph.sva = getbituInc(data, i, 4); eph.ura[0] = svaToUra(eph.sva); eph.idot = getbitsInc(data, i, 14)*P2_43*SC2RAD; - eph.iode = getbituInc(data, i, 8); - double toc = getbituInc(data, i, 16)*16.0; + eph.aode = getbituInc(data, i, 5); + eph.tocs = getbituInc(data, i, 17)*8.0; + eph.f2 = getbitsInc(data, i, 11)*P2_66; + eph.f1 = getbitsInc(data, i, 22)*P2_50; + eph.f0 = getbitsInc(data, i, 24)*P2_33; + eph.aodc = getbituInc(data, i, 5); + eph.crs = getbitsInc(data, i, 18)*P2_6; + eph.deln = getbitsInc(data, i, 16)*P2_43*SC2RAD; + eph.M0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.cuc = getbitsInc(data, i, 18)*P2_31; + eph.e = getbituInc(data, i, 32)*P2_33; + eph.cus = getbitsInc(data, i, 18)*P2_31; + eph.sqrtA = getbituInc(data, i, 32)*P2_19; eph.A = SQR(eph.sqrtA); + eph.toes = getbituInc(data, i, 17)*8.0; + eph.cic = getbitsInc(data, i, 18)*P2_31; + eph.OMG0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.cis = getbitsInc(data, i, 18)*P2_31; + eph.i0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.crc = getbitsInc(data, i, 18)*P2_6; + eph.omg = getbitsInc(data, i, 32)*P2_31*SC2RAD; + eph.OMGd = getbitsInc(data, i, 24)*P2_43*SC2RAD; + eph.tgd[0] = getbitsInc(data, i, 10)*1E-10; + eph.tgd[1] = getbitsInc(data, i, 10)*1E-10; + int svh = getbituInc(data, i, 1); eph.svh = (E_Svh)svh; + + eph.Sat = SatSys(sys, prn); + + eph.iode = int(eph.tocs / 720) % 240; + eph.iodc = eph.iode + 256 * int(eph.tocs / 172800) % 4; + + GTime nearTime = rtcmTime(); + + eph.ttm = nearTime; + eph.toe = GTime(BTow(eph.toes), nearTime); + eph.toc = GTime(BTow(eph.tocs), nearTime); + } + else if (sys == +E_Sys::QZS) + { + if (i + 485-12 > data.size() * 8) + { + BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1044 length error: len=" << data.size(); + return; + } + + eph.type = E_NavMsgType::LNAV; + + int prn = getbituInc(data, i, 4); + eph.tocs = getbituInc(data, i, 16)*16.0; eph.f2 = getbitsInc(data, i, 8)*P2_55; eph.f1 = getbitsInc(data, i, 16)*P2_43; eph.f0 = getbitsInc(data, i, 22)*P2_31; - eph.iodc = getbituInc(data, i, 10); + eph.iode = getbituInc(data, i, 8); eph.crs = getbitsInc(data, i, 16)*P2_5; eph.deln = getbitsInc(data, i, 16)*P2_43*SC2RAD; eph.M0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; eph.cuc = getbitsInc(data, i, 16)*P2_29; eph.e = getbituInc(data, i, 32)*P2_33; eph.cus = getbitsInc(data, i, 16)*P2_29; - double sqrtA = getbituInc(data, i, 32)*P2_19; + eph.sqrtA = getbituInc(data, i, 32)*P2_19; eph.A = SQR(eph.sqrtA); eph.toes = getbituInc(data, i, 16)*16.0; eph.cic = getbitsInc(data, i, 16)*P2_29; eph.OMG0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; @@ -478,62 +733,58 @@ void RtcmDecoder::decodeEphemeris( eph.crc = getbitsInc(data, i, 16)*P2_5; eph.omg = getbitsInc(data, i, 32)*P2_31*SC2RAD; eph.OMGd = getbitsInc(data, i, 24)*P2_43*SC2RAD; + eph.idot = getbitsInc(data, i, 14)*P2_43*SC2RAD; + eph.code = getbituInc(data, i, 2); + eph.weekRollOver= getbituInc(data, i, 10); eph.week = adjGpsWeek(eph.weekRollOver); // rolled-over week -> full week number + eph.sva = getbituInc(data, i, 4); eph.ura[0] = svaToUra(eph.sva); + int svh = getbituInc(data, i, 6); eph.svh = (E_Svh)svh; eph.tgd[0] = getbitsInc(data, i, 8)*P2_31; - eph.svh = (E_Svh)getbituInc(data, i, 6); - eph.flag = getbituInc(data, i, 1); - eph.fit = getbituInc(data, i, 1)?0.0:4.0; /* 0:4hr,1:>4hr */ - - if (prn >= 40) - { - sys = E_Sys::SBS; - prn += 80; - } - - if (1) //todo aaron, janky? - { - int week; - GTime now = getGpst(); + eph.iodc = getbituInc(data, i, 10); + eph.fitFlag = getbituInc(data, i, 1); eph.fit = eph.fitFlag?0.0:2.0; // 0:2hr,1:>2hr - double tow = time2gpst(now, &week); - eph.ttm = gpst2time(week, floor(tow)); - } eph.Sat = SatSys(sys, prn); - eph.toe = gpst2time(eph.week,eph.toes); - eph.toc = gpst2time(eph.week,toc); - eph.A = SQR(sqrtA); + + GTime nearTime = rtcmTime(); + + eph.ttm = nearTime; + eph.toe = GTime(GTow(eph.toes), nearTime); + eph.toc = GTime(GTow(eph.tocs), nearTime); decomposeTGDBias(eph.Sat, eph.tgd[0]); } else if (sys == +E_Sys::GAL) { - if ( message_number == RtcmMessageType::GAL_FNAV_EPHEMERIS ) + if (messageNumber == RtcmMessageType::GAL_FNAV_EPHEMERIS ) { - if (i + 496-12 > message_length * 8) + if (i + 496-12 > data.size() * 8) { - BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1045 length error: len=%d\n" << message_length; + BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1045 length error: len=" << data.size(); return; } + + eph.type = E_NavMsgType::FNAV; } - else if (message_number == RtcmMessageType::GAL_INAV_EPHEMERIS) + else if (messageNumber == RtcmMessageType::GAL_INAV_EPHEMERIS) { - if (i + 504-12 > message_length * 8) + if (i + 504-12 > data.size() * 8) { - BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1046 length error: len=%d\n" << message_length; + BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 1046 length error: len=" << data.size(); return; } + + eph.type = E_NavMsgType::INAV; } else { - BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message for GAL in EphemerisDecoder::decode()"; + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message for GAL in " << __FUNCTION__; } int prn = getbituInc(data, i, 6); - eph.week = adjgpsweek(getbituInc(data, i, 12)); - eph.iode = getbituInc(data, i, 10); // Documented as IODnav - eph.sva = getbituInc(data, i, 8); // Documented SISA - + eph.weekRollOver= getbituInc(data, i, 12); eph.week = adjGstWeek(eph.weekRollOver) + 1024; // rolled-over week -> full week number and align to GPST + eph.iode = getbituInc(data, i, 10); eph.iodc = eph.iode; // Documented as IODnav + eph.sva = getbituInc(data, i, 8); eph.ura[0] = svaToSisa(eph.sva); // Documented SISA eph.idot = getbitsInc(data, i, 14)*P2_43*SC2RAD; - double toc = getbituInc(data, i, 14)*60.0; + eph.tocs = getbituInc(data, i, 14)*60.0; eph.f2 = getbitsInc(data, i, 6)*P2_59; eph.f1 = getbitsInc(data, i, 21)*P2_46; eph.f0 = getbitsInc(data, i, 31)*P2_34; @@ -543,7 +794,7 @@ void RtcmDecoder::decodeEphemeris( eph.cuc = getbitsInc(data, i, 16)*P2_29; eph.e = getbituInc(data, i, 32)*P2_33; eph.cus = getbitsInc(data, i, 16)*P2_29; - double sqrtA = getbituInc(data, i, 32)*P2_19; + eph.sqrtA = getbituInc(data, i, 32)*P2_19; eph.A = SQR(eph.sqrtA); eph.toes = getbituInc(data, i, 14)*60.0; eph.cic = getbitsInc(data, i, 16)*P2_29; eph.OMG0 = getbitsInc(data, i, 32)*P2_31*SC2RAD; @@ -554,219 +805,112 @@ void RtcmDecoder::decodeEphemeris( eph.OMGd = getbitsInc(data, i, 24)*P2_43*SC2RAD; eph.tgd[0] = getbitsInc(data, i, 10)*P2_32; - int e5a_hs = 0; - int e5a_dvs = 0; - int rsv = 0; - int e5b_hs = 0; - int e5b_dvs = 0; - int e1_hs = 0; - int e1_dvs = 0; - if (message_number == RtcmMessageType::GAL_FNAV_EPHEMERIS ) + if (messageNumber == RtcmMessageType::GAL_FNAV_EPHEMERIS) { - e5a_hs = getbituInc(data, i, 2); // OSHS - e5a_dvs = getbituInc(data, i, 1); // OSDVS - rsv = getbituInc(data, i, 7); + eph.e5a_hs = getbituInc(data, i, 2); // OSHS + eph.e5a_dvs = getbituInc(data, i, 1); // OSDVS + // eph.rsv = getbituInc(data, i, 7); + + int svh = (eph.e5a_hs << 4) + + (eph.e5a_dvs << 3); + eph.svh = (E_Svh)svh; + eph.code = (1<<1)+(1<<8); // data source = F/NAV+E5a } - else if (message_number == RtcmMessageType::GAL_INAV_EPHEMERIS) + else if (messageNumber == RtcmMessageType::GAL_INAV_EPHEMERIS) { - eph.tgd[1] = getbitsInc(data, i,10)*P2_32; // E5b/E1 - e5b_hs = getbituInc(data, i, 2); // E5b OSHS - e5b_dvs = getbituInc(data, i, 1); // E5b OSDVS - e1_hs = getbituInc(data, i, 2); // E1 OSHS - e1_dvs = getbituInc(data, i, 1); // E1 OSDVS + eph.tgd[1] = getbitsInc(data, i,10)*P2_32; // E5b/E1 + eph.e5b_hs = getbituInc(data, i, 2); // E5b OSHS + eph.e5b_dvs = getbituInc(data, i, 1); // E5b OSDVS + eph.e1_hs = getbituInc(data, i, 2); // E1 OSHS + eph.e1_dvs = getbituInc(data, i, 1); // E1 OSDVS + + int svh = (eph.e5b_hs << 7) + + (eph.e5b_dvs << 6) + + (eph.e1_hs << 1) + + (eph.e1_dvs << 0); + eph.svh = (E_Svh)svh; + eph.code = (1<<0)+(1<<2)+(1<<9); // data source = I/NAV+E1+E5b decomposeBGDBias(eph.Sat, eph.tgd[0], eph.tgd[1]); } - if (1) //todo aaron, janky? - { - int week; - double tow = time2gpst(utc2gpst(timeget()), &week); - eph.ttm = gpst2time(week, floor(tow)); - } eph.Sat = SatSys(sys, prn); - eph.toe = gpst2time(eph.week,eph.toes); - eph.toc = gpst2time(eph.week,toc); - eph.A = SQR(sqrtA); - if (message_number == RtcmMessageType::GAL_FNAV_EPHEMERIS ) - { - eph.svh= (E_Svh)( (e5a_hs<<4) - +(e5a_dvs<<3)); - eph.code=(1<<1)+(1<<8); // data source = F/NAV+E5a - eph.iodc=eph.iode; - } - else if (message_number == RtcmMessageType::GAL_INAV_EPHEMERIS) - { - eph.svh= (E_Svh)( (e5b_hs <<7) - +(e5b_dvs <<6) - +(e1_hs <<1) - +(e1_dvs <<0)); - eph.code=(1<<0)+(1<<2)+(1<<9); // data source = I/NAV+E1+E5b - eph.iodc=eph.iode; - } + GTime nearTime = rtcmTime(); + + eph.ttm = nearTime; + eph.toe = GTime(GTow(eph.toes), nearTime); + eph.toc = GTime(GTow(eph.tocs), nearTime); } else { - BOOST_LOG_TRIVIAL(error) << "Error: unrecognised sys in EphemerisDecoder::decode()"; + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system in " << __FUNCTION__; + return; } - //tracepdeex(rtcmdeblvl,std::cout, "\n#RTCM_DEC BRCEPH %s %s %4d %16.9e %13.6e %10.3e, %d ", eph.Sat.id().c_str(),eph.toe.to_string(2).c_str(), eph.iode, eph.f0,eph.f1,eph.f2, message_number); - //std::cout << "Adding ephemeris for " << eph.Sat.id() << std::endl; - - if (nav.ephMap[eph.Sat].find(eph.toe) == nav.ephMap[eph.Sat].end()) + if ( sys == +E_Sys::GPS + ||sys == +E_Sys::GAL + ||sys == +E_Sys::BDS + ||sys == +E_Sys::QZS) { - nav.ephMap[eph.Sat][eph.toe] = eph; + nav.ephMap[eph.Sat][eph.type][eph.toe] = eph; + tracepdeex(6,std::cout, "\n#RTCM_BRD EPHEMR %s %s %d", eph.Sat.id().c_str(),eph.toe.to_string(2).c_str(), eph.iode); + if (acsConfig.output_decoded_rtcm_json) - traceBroEph(eph, sys); + traceBrdcEph(messCode, eph); + + if (acsConfig.localMongo.output_rtcm_messages) + mongoBrdcEph(eph); } -} - - -// sys -> rtcm signal enum -> siginfo (sig enum, -map> codeTypeMap = -{ - { E_Sys::GPS, - { - {E_ObsCode::L1C, L1 }, - {E_ObsCode::L1P, L1 }, - {E_ObsCode::L1W, L1 }, - - {E_ObsCode::L2C, L2 }, - {E_ObsCode::L2P, L2 }, - {E_ObsCode::L2W, L2 }, - {E_ObsCode::L2S, L2 }, - {E_ObsCode::L2L, L2 }, - {E_ObsCode::L2X, L2 }, - - {E_ObsCode::L5I, L5 }, - {E_ObsCode::L5Q, L5 }, - {E_ObsCode::L5X, L5 }, - - {E_ObsCode::L1S, L1 }, - {E_ObsCode::L1L, L1 }, - {E_ObsCode::L1X, L1 } - } - }, - - { E_Sys::GLO, - { - {E_ObsCode::L1C, G1 }, - {E_ObsCode::L1P, G1 }, - - {E_ObsCode::L2C, G2 }, - {E_ObsCode::L2P, G2 } - } - }, - - { E_Sys::GAL, - { - {E_ObsCode::L1C, E1 }, - {E_ObsCode::L1A, E1 }, - {E_ObsCode::L1B, E1 }, - {E_ObsCode::L1X, E1 }, - {E_ObsCode::L1Z, E1 }, - - {E_ObsCode::L6C, E6 }, - {E_ObsCode::L6A, E6 }, - {E_ObsCode::L6B, E6 }, - {E_ObsCode::L6X, E6 }, - {E_ObsCode::L6Z, E6 }, - - {E_ObsCode::L7I, E5B }, - {E_ObsCode::L7Q, E5B }, - {E_ObsCode::L7X, E5B }, - - {E_ObsCode::L8I, E5AB}, - {E_ObsCode::L8Q, E5AB}, - {E_ObsCode::L8X, E5AB}, - - {E_ObsCode::L5I, E5A }, - {E_ObsCode::L5Q, E5A }, - {E_ObsCode::L5X, E5A } - } - }, - - { E_Sys::QZS, - { - {E_ObsCode::L1C, L1 }, - - {E_ObsCode::L6S, LEX }, - {E_ObsCode::L6L, LEX }, - {E_ObsCode::L6X, LEX }, - - {E_ObsCode::L2S, L2 }, - {E_ObsCode::L2L, L2 }, - {E_ObsCode::L2X, L2 }, - - {E_ObsCode::L5I, L5 }, - {E_ObsCode::L5Q, L5 }, - {E_ObsCode::L5X, L5 }, - - {E_ObsCode::L1S, L1 }, - {E_ObsCode::L1L, L1 }, - {E_ObsCode::L1X, L1 } - } - }, - - { E_Sys::BDS, - { - {E_ObsCode::L2I, B1 }, - {E_ObsCode::L2Q, B1 }, - {E_ObsCode::L2X, B1 }, - - {E_ObsCode::L6I, B3 }, - {E_ObsCode::L6Q, B3 }, - {E_ObsCode::L6X, B3 }, - - {E_ObsCode::L7I, B2 }, - {E_ObsCode::L7Q, B2 }, - {E_ObsCode::L7X, B2 } - } + else if (sys == +E_Sys::GLO) + { + nav.gephMap[geph.Sat][E_NavMsgType::FDMA][geph.toe] = geph; + + tracepdeex(6,std::cout, "\n#RTCM_BRD EPHEMR %s %s %d", geph.Sat.id().c_str(), geph.toe.to_string(2).c_str(), geph.iode); + + if (acsConfig.output_decoded_rtcm_json) + traceBrdcEph(messCode, geph); + + if (acsConfig.localMongo.output_rtcm_messages) + mongoBrdcEph(geph); } -}; - - -E_FType RtcmDecoder::code_to_ftype(E_Sys sys, E_ObsCode code) -{ - if ( codeTypeMap .count(sys) > 0 - &&codeTypeMap[sys] .count(code) > 0) + else { - return codeTypeMap.at(sys).at(code); + if (acsConfig.output_decoded_rtcm_json) + traceUnknown(); } - - return FTYPE_NONE; } + // sys -> rtcm signal enum -> siginfo (sig enum,// From the RTCM spec... // - table 3.5-91 (GPS) // - table 3.5-96 (GLONASS) // - table 3.5-99 (GALILEO) // - table 3.5-105 (QZSS) // - table 3.5-108 (BEIDOU) -map> signal_id_mapping = +map> sysIdSignalMapMap = { { E_Sys::GPS, { - {2, {2, L1, E_ObsCode::L1C}}, - {3, {3, L1, E_ObsCode::L1P}}, - {4, {4, L1, E_ObsCode::L1W}}, - - {8, {8, L2, E_ObsCode::L2C}}, - {9, {9, L2, E_ObsCode::L2P}}, - {10, {10, L2, E_ObsCode::L2W}}, - {15, {15, L2, E_ObsCode::L2S}}, - {16, {16, L2, E_ObsCode::L2L}}, - {17, {17, L2, E_ObsCode::L2X}}, - - {22, {22, L5, E_ObsCode::L5I}}, - {23, {23, L5, E_ObsCode::L5Q}}, - {24, {24, L5, E_ObsCode::L5X}}, - - {30, {2, L1, E_ObsCode::L1S}}, - {31, {2, L1, E_ObsCode::L1L}}, - {32, {2, L1, E_ObsCode::L1X}} + {2, {2, F1, E_ObsCode::L1C}}, + {3, {3, F1, E_ObsCode::L1P}}, + {4, {4, F1, E_ObsCode::L1W}}, + + {8, {8, F2, E_ObsCode::L2C}}, + {9, {9, F2, E_ObsCode::L2P}}, + {10, {10, F2, E_ObsCode::L2W}}, + {15, {15, F2, E_ObsCode::L2S}}, + {16, {16, F2, E_ObsCode::L2L}}, + {17, {17, F2, E_ObsCode::L2X}}, + + {22, {22, F5, E_ObsCode::L5I}}, + {23, {23, F5, E_ObsCode::L5Q}}, + {24, {24, F5, E_ObsCode::L5X}}, + + {30, {2, F1, E_ObsCode::L1S}}, + {31, {2, F1, E_ObsCode::L1L}}, + {32, {2, F1, E_ObsCode::L1X}} } }, @@ -782,51 +926,51 @@ map> signal_id_mapping = { E_Sys::GAL, { - {2, {2, E1, E_ObsCode::L1C}}, - {3, {3, E1, E_ObsCode::L1A}}, - {4, {4, E1, E_ObsCode::L1B}}, - {5, {5, E1, E_ObsCode::L1X}}, - {6, {6, E1, E_ObsCode::L1Z}}, - - {8, {8, E6, E_ObsCode::L6C}}, - {9, {9, E6, E_ObsCode::L6A}}, - {10, {10, E6, E_ObsCode::L6B}}, - {11, {11, E6, E_ObsCode::L6X}}, - {12, {12, E6, E_ObsCode::L6Z}}, - - {14, {14, E5B, E_ObsCode::L7I}}, - {15, {15, E5B, E_ObsCode::L7Q}}, - {16, {16, E5B, E_ObsCode::L7X}}, - - {18, {18, E5AB, E_ObsCode::L8I}}, - {19, {19, E5AB, E_ObsCode::L8Q}}, - {20, {20, E5AB, E_ObsCode::L8X}}, - - {22, {22, E5A, E_ObsCode::L5I}}, - {23, {23, E5A, E_ObsCode::L5Q}}, - {24, {24, E5A, E_ObsCode::L5X}} + {2, {2, F1, E_ObsCode::L1C}}, + {3, {3, F1, E_ObsCode::L1A}}, + {4, {4, F1, E_ObsCode::L1B}}, + {5, {5, F1, E_ObsCode::L1X}}, + {6, {6, F1, E_ObsCode::L1Z}}, + + {8, {8, F6, E_ObsCode::L6C}}, + {9, {9, F6, E_ObsCode::L6A}}, + {10, {10, F6, E_ObsCode::L6B}}, + {11, {11, F6, E_ObsCode::L6X}}, + {12, {12, F6, E_ObsCode::L6Z}}, + + {14, {14, F7, E_ObsCode::L7I}}, + {15, {15, F7, E_ObsCode::L7Q}}, + {16, {16, F7, E_ObsCode::L7X}}, + + {18, {18, F8, E_ObsCode::L8I}}, + {19, {19, F8, E_ObsCode::L8Q}}, + {20, {20, F8, E_ObsCode::L8X}}, + + {22, {22, F5, E_ObsCode::L5I}}, + {23, {23, F5, E_ObsCode::L5Q}}, + {24, {24, F5, E_ObsCode::L5X}} } }, { E_Sys::QZS, { - {2, {2, L1, E_ObsCode::L1C}}, + {2, {2, F1, E_ObsCode::L1C}}, - {9, {9, LEX, E_ObsCode::L6S}}, - {10, {10, LEX, E_ObsCode::L6L}}, - {11, {11, LEX, E_ObsCode::L6X}}, + {9, {9, F6, E_ObsCode::L6S}}, + {10, {10, F6, E_ObsCode::L6L}}, + {11, {11, F6, E_ObsCode::L6X}}, - {15, {15, L2, E_ObsCode::L2S}}, - {16, {16, L2, E_ObsCode::L2L}}, - {17, {17, L2, E_ObsCode::L2X}}, + {15, {15, F2, E_ObsCode::L2S}}, + {16, {16, F2, E_ObsCode::L2L}}, + {17, {17, F2, E_ObsCode::L2X}}, - {22, {22, L5, E_ObsCode::L5I}}, - {23, {23, L5, E_ObsCode::L5Q}}, - {24, {24, L5, E_ObsCode::L5X}}, + {22, {22, F5, E_ObsCode::L5I}}, + {23, {23, F5, E_ObsCode::L5Q}}, + {24, {24, F5, E_ObsCode::L5X}}, - {30, {30, L1, E_ObsCode::L1S}}, - {31, {31, L1, E_ObsCode::L1L}}, - {32, {32, L1, E_ObsCode::L1X}} + {30, {30, F1, E_ObsCode::L1S}}, + {31, {31, F1, E_ObsCode::L1L}}, + {32, {32, F1, E_ObsCode::L1X}} } }, @@ -840,85 +984,48 @@ map> signal_id_mapping = {9, {9, B3, E_ObsCode::L6Q}}, {10, {10, B3, E_ObsCode::L6X}}, - {14, {14, B2, E_ObsCode::L7I}}, - {15, {15, B2, E_ObsCode::L7Q}}, - {16, {16, B2, E_ObsCode::L7X}} - } - } -}; - -// From the RTCM spec table 3.5-73 - -map> signal_phase_alignment = -{ - { E_Sys::GPS, - { - {L1, 1.57542E9}, - {L2, 1.22760E9}, - {L5, 1.17645E9} - } - }, - - // TODO - - // {SatelliteSystem::GLONASS, { - // {FrequencyBand::G1, 1.57542E9}, - // {FrequencyBand::G2, 1.22760E9}, - // }}, + {14, {14, F7, E_ObsCode::L7I}}, + {15, {15, F7, E_ObsCode::L7Q}}, + {16, {16, F7, E_ObsCode::L7X}}, - { E_Sys::GAL, - { - {E1, 1.57542E9}, - {E5A, 1.17645E9}, - {E5B, 1.20714E9}, - {E5AB, 1.1191795E9}, - {E6, 1.27875E9}, - } - }, + {22, {22, F5, E_ObsCode::L5D}}, + {23, {23, F5, E_ObsCode::L5P}}, + {24, {24, F5, E_ObsCode::L5X}}, + {25, {25, F7, E_ObsCode::L7D}}, - { E_Sys::QZS, - { - {L1, 1.57542E9}, - {L2, 1.22760E9}, - {L5, 1.17645E9} - } - }, - - { E_Sys::BDS, - { - {B1, 1.561098E9}, - {B2, 1.207140E9}, - {B3, 1.26852E9} + {30, {30, F1, E_ObsCode::L1D}}, + {31, {31, F1, E_ObsCode::L1P}}, + {32, {32, F1, E_ObsCode::L1X}} } } }; -boost::optional RtcmDecoder::get_signal_info(E_Sys sys, uint8_t signal) +E_ObsCode RtcmDecoder::signal_to_code(E_Sys sys, uint8_t signal) { - if ( signal_id_mapping .count(sys) > 0 - &&signal_id_mapping[sys].count(signal) > 0) + auto it1 = sysIdSignalMapMap.find(sys); + if (it1 == sysIdSignalMapMap.end()) { - return signal_id_mapping.at(sys).at(signal); + BOOST_LOG_TRIVIAL(warning) << "Error: unrecognised system in " << __FUNCTION__ << ": mountpoint=" << rtcmMountpoint << " sys=" << sys; + + return E_ObsCode::NONE; } - - return boost::optional(); -} - -E_ObsCode RtcmDecoder::signal_to_code(E_Sys sys, uint8_t signal) -{ - boost::optional info = get_signal_info(sys, signal); - - if (info) + + auto& [dummy1, idSignalMap] = *it1; + + auto it2 = idSignalMap.find(signal); + if (it2 == idSignalMap.end()) { - return info->rinex_observation_code; + BOOST_LOG_TRIVIAL(warning) << "Error: unrecognised signal in " << __FUNCTION__ << ": mountpoint=" << rtcmMountpoint << " sys=" << sys << " signal=" << (int)signal; + + return E_ObsCode::NONE; } - - return E_ObsCode::NONE; + + auto& [dummy2, sigInfo] = *it2; + + return sigInfo.obsCode; } - - -const int DefGLOChnl [24] = { 1, -4, 5, 6, 1, -4, 5, 6, -2, -7, 0, -1, -2, -7, 0, -1, 4, -3, 3, 2, 4, -3, 3, 2 }; +const int defaultGloChannel[] = { 0, 1, -4, 5, 6, 1, -4, 5, 6, -2, -7, 0, -1, -2, -7, 0, -1, 4, -3, 3, 2, 4, -3, 3, 2 }; double lockTimeFromIndicator( int indicator) @@ -961,21 +1068,20 @@ double highResLockTimeFromIndicator( else if (i < 704) lockTime = 1048576 * i - 671088640; else if (i== 704) lockTime = 2097152 * i - 1409286144; else - printf("\nWarning high res lock time out of bounds\n"); + tracepdeex(3, std::cout, "\nWarning high res lock time out of bounds\n"); lockTime /= 1000; return lockTime; } -ObsList RtcmDecoder::decodeMSM7( - uint8_t* data, - unsigned int message_length) +ObsList RtcmDecoder::decodeMSM( + vector& data) { ObsList obsList; int i = 0; - int message_number = getbituInc(data, i, 12); + int messageNumber = getbituInc(data, i, 12); int reference_station_id = getbituInc(data, i, 12); int epoch_time_ = getbituInc(data, i, 30); int multiple_message = getbituInc(data, i, 1); @@ -986,13 +1092,36 @@ ObsList RtcmDecoder::decodeMSM7( int smoothing_indicator = getbituInc(data, i, 1); int smoothing_interval = getbituInc(data, i, 3); - int msmtyp = message_number%10; + RtcmMessageType messCode; + try + { + messCode = RtcmMessageType::_from_integral(messageNumber); + } + catch (...) + { + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in " << __FUNCTION__; + return obsList; + } + + int msmtyp = messageNumber % 10; + int lsat = 0; + int lcell = 0; + switch (msmtyp) + { + case 4: lsat = 18; lcell = 48; break; + case 5: lsat = 36; lcell = 63; break; + case 6: lsat = 18; lcell = 65; break; + case 7: lsat = 36; lcell = 80; break; + default: BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in " << __FUNCTION__; return obsList; + } + bool extrainfo = false; if ( msmtyp == 5 || msmtyp == 7) { extrainfo = true; } + int nbcd = 15; int nbph = 22; int nblk = 4; @@ -1009,51 +1138,64 @@ ObsList RtcmDecoder::decodeMSM7( nbcn = 10; scsn = 0.0625; } - int sysind = message_number / 10; // integer division is intentional + int sysind = messageNumber / 10; // integer division is intentional E_Sys rtcmsys = E_Sys::NONE; + + + GTime nearTime = rtcmTime(); + double tow = epoch_time_ * 0.001; + GTime tobs; + switch (sysind) { - case 107: rtcmsys = E_Sys::GPS; break; - case 108: rtcmsys = E_Sys::GLO; break; - case 109: rtcmsys = E_Sys::GAL; break; - case 111: rtcmsys = E_Sys::QZS; break; - case 112: rtcmsys = E_Sys::BDS; tow += 14; break; + case 107: rtcmsys = E_Sys::GPS; tobs = GTime(GTow(tow), nearTime); break; + case 108: rtcmsys = E_Sys::GLO; /*see below*/ break; + case 109: rtcmsys = E_Sys::GAL; tobs = GTime(GTow(tow), nearTime); break; + case 111: rtcmsys = E_Sys::QZS; tobs = GTime(GTow(tow), nearTime); break; + case 112: rtcmsys = E_Sys::BDS; tobs = GTime(BTow(tow), nearTime); break; + default: BOOST_LOG_TRIVIAL(error) << "Error: unrecognised message in " << __FUNCTION__; return obsList; } - GTime tobs; if (rtcmsys == +E_Sys::GLO) { - int dowi = (epoch_time_ >> 27); + int dowi = (epoch_time_ >> 27); int todi = (epoch_time_ & 0x7FFFFFF); - tow = 86400 * dowi + 0.001 * todi - 10800; - GTime tglo = tow2Time(tow); - tobs = utc2gpst(tglo); + double utctow = 86400 * dowi + + 0.001 * todi + - 10800; //3 hours moscow time + + GTime fakeGTime = GTime(GTow(utctow), nearTime); + + UtcTime utcTime; + utcTime.bigTime = fakeGTime.bigTime; + + tobs = utcTime; } - else - tobs = tow2Time(tow); traceLatency(tobs); //create observations for satellites according to the mask + int nsat = 0; for (int sat = 0; sat < 64; sat++) { bool mask = getbituInc(data, i, 1); - if (mask) + if (mask == false) { - Obs obs; - obs.Sat.sys = rtcmsys; - obs.Sat.prn = sat + 1; - obs.time=tobs; - //std::cout << "decodeMSM7, obs.time :" << std::put_time( std::gmtime( &obs.time.time ), "%F %X" ) - // << " : " << obs.time.sec << std::endl; - - obsList.push_back(obs); + continue; } + + GObs obs; + obs.Sat = SatSys(rtcmsys, sat + 1); + obs.time = tobs; + + obsList.push_back((shared_ptr)obs); + + nsat++; } //create a temporary list of signals - list signalMaskList; + vector signalMaskList; for (int sig = 0; sig < 32; sig++) { bool mask = getbituInc(data, i, 1); @@ -1065,42 +1207,64 @@ ObsList RtcmDecoder::decodeMSM7( } //create a temporary list of signal pointers for simpler iteration later - map signalPointermap; - map cellSatellitemap; - int indx=0; + map signalPointermap; + map cellSatellitemap; + int ncell = 0; //create signals for observations according to existing observations, the list of signals, and the cell mask - for (auto& obs : obsList) + for (auto& obs : only(obsList)) for (auto& sigNum : signalMaskList) { bool mask = getbituInc(data, i, 1); - if (mask) + if (mask == false) { - RawSig sig; + continue; + } + + Sig sig; + sig.code = sigNum; - sig.code = sigNum; - E_FType ft = code_to_ftype(rtcmsys, sig.code); + E_FType ft = FTYPE_NONE; + if (code2Freq.find(rtcmsys) != code2Freq.end()) + { + if (code2Freq[rtcmsys].find(sig.code) != code2Freq[rtcmsys].end()) // must not skip unknwon/unsupported systems or signals in the list of signals -- unknown != no observation + { + ft = code2Freq[rtcmsys][sig.code]; + } + else + { + BOOST_LOG_TRIVIAL(warning) << "Error: unrecognised signal in " << __FUNCTION__ << ": mountpoint=" << rtcmMountpoint << " messageNumber=" << messageNumber << " signal=" << sig.code; + } + } + else + { + BOOST_LOG_TRIVIAL(warning) << "Error: unrecognised system in " << __FUNCTION__ << ": mountpoint=" << rtcmMountpoint << "messageNumber=" << messageNumber; + } - obs.SigsLists[ft].push_back(sig); + obs.SigsLists[ft].push_back(sig); - RawSig* pointer = &obs.SigsLists[ft].back(); - signalPointermap [indx] = pointer; - cellSatellitemap [indx] = obs.Sat; - indx++; - } + Sig* pointer = &obs.SigsLists[ft].back(); + signalPointermap[ncell] = pointer; + cellSatellitemap[ncell] = obs.Sat; + ncell++; + } + + if (i + nsat * lsat + ncell * lcell > data.size() * 8) + { + BOOST_LOG_TRIVIAL(error) << "Error: rtcm3 " << messageNumber << " length error: len=" << data.size(); + return obsList; } //get satellite specific data - needs to be in chunks - map SatelliteDatainvalid; - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { int ms_rough_range = getbituInc(data, i, 8); if (ms_rough_range == 255) { - SatelliteDatainvalid[obs.Sat]=true; + obs.excludeBadRange = true; + continue; } - else SatelliteDatainvalid[obs.Sat]=false; - + for (auto& [ft, sigList] : obs.SigsLists) for (auto& sig : sigList) { @@ -1112,40 +1276,38 @@ ObsList RtcmDecoder::decodeMSM7( map> GLOFreqShift; if (extrainfo) { - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { int extended_sat_info = getbituInc(data, i, 4); - - if(rtcmsys == +E_Sys::GLO) + if (rtcmsys == +E_Sys::GLO) { - GLOFreqShift[obs.Sat][G1] = 562500.0*(extended_sat_info-7); - GLOFreqShift[obs.Sat][G2] = 437500.0*(extended_sat_info-7); + GLOFreqShift[obs.Sat][G1] = DFRQ1_GLO * (extended_sat_info-7); + GLOFreqShift[obs.Sat][G2] = DFRQ2_GLO * (extended_sat_info-7); } } } else if(rtcmsys == +E_Sys::GLO) { - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { short int prn = obs.Sat.prn; - if (prn > 24 || prn<1) + if ( prn > 24 + || prn < 1) { - SatelliteDatainvalid[obs.Sat] = true; GLOFreqShift[obs.Sat][G1] = 0; GLOFreqShift[obs.Sat][G2] = 0; - } else { - GLOFreqShift[obs.Sat][G1] = 562500.0 * DefGLOChnl[prn-1]; - GLOFreqShift[obs.Sat][G2] = 437500.0 * DefGLOChnl[prn-1]; + GLOFreqShift[obs.Sat][G1] = DFRQ1_GLO * defaultGloChannel[prn]; + GLOFreqShift[obs.Sat][G2] = DFRQ2_GLO * defaultGloChannel[prn]; } } } - for (auto& obs : obsList) + for (auto& obs : only(obsList)) { int rough_range_modulo = getbituInc(data, i, 10); @@ -1157,12 +1319,15 @@ ObsList RtcmDecoder::decodeMSM7( } } - if(extrainfo) - for (auto& obs : obsList) + if (extrainfo) + for (auto& obs : only(obsList)) { - int rough_doppler = getbituInc(data, i, 14); - if (rough_doppler == 0x2000) + bool failure = false; + double rough_doppler = getbitsIncScale(data, i, 14, 1, &failure); + if (failure) + { continue; + } for (auto& [ft, sigList] : obs.SigsLists) for (auto& sig : sigList) @@ -1174,405 +1339,415 @@ ObsList RtcmDecoder::decodeMSM7( //get signal specific data for (auto& [indx, signalPointer] : signalPointermap) { - int fine_pseudorange = getbitsInc(data, i, nbcd); - if (fine_pseudorange == 0x80000) + Sig& sig = *signalPointer; + + bool failure = false; + double fine_pseudorange = getbitsIncScale(data, i, nbcd, sccd, &failure); + if (failure) { - SatelliteDatainvalid[cellSatellitemap[indx]] = true; + sig.invalid = true; continue; } - RawSig& sig = *signalPointer; - sig.P += fine_pseudorange * sccd; + sig.P += fine_pseudorange; } for (auto& [indx, signalPointer] : signalPointermap) { - int fine_phase_range = getbitsInc(data, i, nbph); - if (fine_phase_range == 0x800000) + Sig& sig = *signalPointer; + + bool failure = false; + double fine_phase_range = getbitsIncScale(data, i, nbph, scph, &failure); + if (failure) { - SatelliteDatainvalid[cellSatellitemap[indx]] = true; + sig.invalid = true; + continue; } - RawSig& sig = *signalPointer; - sig.L += fine_phase_range * scph; + tracepdeex(6,std::cout, "\n#RTCM_MSM PHASEMS %s %s %.4f ", cellSatellitemap[indx].id().c_str(), sig.code._to_string(), sig.L*CLIGHT/1000 ); + sig.L += fine_phase_range; + tracepdeex(6,std::cout, "%.4e %.10e", fine_phase_range/scph, scph ); } for (auto& [indx, signalPointer] : signalPointermap) { - int lockTimeIndicator = getbituInc(data, i, nblk); + int lockTimeIndicator = getbituInc(data, i, nblk); - double lockTime = highResLockTimeFromIndicator(lockTimeIndicator); + double lockTime = 0; + if ( msmtyp <= 5) lockTime = lockTimeFromIndicator(lockTimeIndicator); + else if ( msmtyp == 6 + || msmtyp == 7) lockTime = highResLockTimeFromIndicator(lockTimeIndicator); - RawSig& sig = *signalPointer; - SatSys& Sat = cellSatellitemap[indx]; + Sig& sig = *signalPointer; + SatSys& Sat = cellSatellitemap[indx]; - sig.LLI = 0; - - if (lockTime < acsConfig.epoch_interval) - { - sig.LLI = 1; - } - -// if ( MSM7_lock_time .find(Sat) != MSM7_lock_time .end() -// &&MSM7_lock_time[sat] .find(sig.code) != MSM7_lock_time[sat] .end()) -// { -// int past_time = MSM7_lock_time[Sat][sig.code]; -// -// if (lock_time_indicator < past_time) -// sig.LLI = 1; -// } -// -// MSM7_lock_time[sat][sig.code] = lock_time_indicator; + if (lockTime < acsConfig.epoch_interval) sig.LLI = true; + else sig.LLI = false; } for (auto& [indx, signalPointer] : signalPointermap) { int half_cycle_ambiguity = getbituInc(data, i, 1); - RawSig& sig = *signalPointer; + Sig& sig = *signalPointer; + if (half_cycle_ambiguity > 0) + sig.LLI = true; } for (auto& [indx, signalPointer] : signalPointermap) { - int carrier_noise_ratio = getbituInc(data, i, nbcn); + double carrier_noise_ratio = getbituIncScale(data, i, nbcn, scsn); - RawSig& sig = *signalPointer; - sig.snr = carrier_noise_ratio * scsn; + Sig& sig = *signalPointer; + sig.snr = carrier_noise_ratio; } if (extrainfo) for (auto& [indx, signalPointer] : signalPointermap) { - int fine_doppler = getbitsInc(data, i, 15); + bool failure = false; + double fine_doppler = getbitsIncScale(data, i, 15, 0.0001, &failure); - if (fine_doppler == 0x4000) + if (failure) continue; - RawSig& sig = *signalPointer; + Sig& sig = *signalPointer; - sig.D += fine_doppler * 0.0001; + sig.D += fine_doppler; } - //convert millisecond measurements to meters or cycles - for (auto& obs : obsList) + //convert millisecond or m/s measurements to meters or cycles or Hz + for (auto& obs : only(obsList)) for (auto& [ft, sigList] : obs.SigsLists) for (auto& sig : sigList) { - double freqcy = signal_phase_alignment[rtcmsys][ft]; - if(rtcmsys == +E_Sys::GLO) freqcy += GLOFreqShift[obs.Sat][ft]; + double freqcy = carrierFrequency[ft]; + if (rtcmsys == +E_Sys::GLO) + freqcy += GLOFreqShift[obs.Sat][ft]; - sig.P *= CLIGHT / 1000; - sig.L *= freqcy / 1000; + sig.P *= CLIGHT / 1000; // ms -> metre + sig.L *= freqcy / 1000; // ms -> cycle + sig.D *= -freqcy / CLIGHT; // m/s -> Hz - //tracepdeex(rtcmdeblvl,std::cout, "\n#RTCM_DEC MSMOBS %s %s %d %s %.4f %.4f", obs.time.to_string(2), obs.Sat.id().c_str(), ft, sig.code._to_string(),sig.P, sig.L ); + + tracepdeex(6,std::cout, "\n#RTCM_MSM OBSERV %s %s %d %s %.4f %.4f", obs.time.to_string(2), obs.Sat.id().c_str(), ft, sig.code._to_string(), sig.P, sig.L ); + + if (acsConfig.output_decoded_rtcm_json) + traceMSM(messCode, obs.time, obs.Sat, sig); } - + + return obsList; } -uint16_t RtcmDecoder::message_length(char header[2]) -{ - // Message length is 10 bits starting at bit 6 - return getbitu((uint8_t*)header, 6, 10); -} - -RtcmMessageType RtcmDecoder::message_type(const uint8_t message[]) -{ - auto id = getbitu(message, 0, 12); - - if (!RtcmMessageType::_is_valid(id)) - { - return RtcmMessageType::NONE; - } - - return RtcmMessageType::_from_integral(id); -} - - void RtcmDecoder::traceLatency(GTime tobs) { - GTime now = getGpst(); - long sec = now.time - tobs.time; - double frac_sec = now.sec - tobs.sec; - double latency = (double)sec + frac_sec; + GTime now = timeGet(); + + double latency = (now - tobs).to_double(); + //std::cout << "traceLatency : " << latency << " seconds.\n"; totalLatency += latency; numMessagesLatency++; } -void RtcmStream::parseRTCM( - std::istream& inputStream) +RtcmDecoder::E_ReturnType RtcmDecoder::decode( + vector& message) { - while (inputStream) + E_ReturnType retVal = E_ReturnType::OK; + + int messageNumber = getbitu(message, 0, 12); + + switch (messageNumber) { - int byteCnt = 0; - int pos; - while (true) + default: retVal = E_ReturnType::UNSUPPORTED; break; + + case +RtcmMessageType::CUSTOM: retVal = decodeCustom (message); break; + + case +RtcmMessageType::GPS_EPHEMERIS: //fallthrough + case +RtcmMessageType::GLO_EPHEMERIS: //fallthrough + case +RtcmMessageType::BDS_EPHEMERIS: //fallthrough + case +RtcmMessageType::QZS_EPHEMERIS: //fallthrough + case +RtcmMessageType::GAL_INAV_EPHEMERIS: //fallthrough + case +RtcmMessageType::GAL_FNAV_EPHEMERIS: decodeEphemeris (message); break; + + case +RtcmMessageType::GPS_SSR_ORB_CORR: //fallthrough + case +RtcmMessageType::GPS_SSR_CLK_CORR: //fallthrough + case +RtcmMessageType::GPS_SSR_COMB_CORR: //fallthrough + case +RtcmMessageType::GPS_SSR_CODE_BIAS: //fallthrough + case +RtcmMessageType::GPS_SSR_PHASE_BIAS: //fallthrough + case +RtcmMessageType::GPS_SSR_URA: //fallthrough + case +RtcmMessageType::GPS_SSR_HR_CLK_CORR: //fallthrough + case +RtcmMessageType::GLO_SSR_ORB_CORR: //fallthrough + case +RtcmMessageType::GLO_SSR_CLK_CORR: //fallthrough + case +RtcmMessageType::GLO_SSR_COMB_CORR: //fallthrough + case +RtcmMessageType::GLO_SSR_CODE_BIAS: //fallthrough + case +RtcmMessageType::GLO_SSR_PHASE_BIAS: //fallthrough + case +RtcmMessageType::GLO_SSR_URA: //fallthrough + case +RtcmMessageType::GLO_SSR_HR_CLK_CORR: //fallthrough + case +RtcmMessageType::GAL_SSR_ORB_CORR: //fallthrough + case +RtcmMessageType::GAL_SSR_CLK_CORR: //fallthrough + case +RtcmMessageType::GAL_SSR_COMB_CORR: //fallthrough + case +RtcmMessageType::GAL_SSR_CODE_BIAS: //fallthrough + case +RtcmMessageType::GAL_SSR_PHASE_BIAS: //fallthrough + case +RtcmMessageType::GAL_SSR_URA: //fallthrough + case +RtcmMessageType::GAL_SSR_HR_CLK_CORR: //fallthrough + case +RtcmMessageType::QZS_SSR_ORB_CORR: //fallthrough + case +RtcmMessageType::QZS_SSR_CLK_CORR: //fallthrough + case +RtcmMessageType::QZS_SSR_COMB_CORR: //fallthrough + case +RtcmMessageType::QZS_SSR_CODE_BIAS: //fallthrough + case +RtcmMessageType::QZS_SSR_PHASE_BIAS: //fallthrough + case +RtcmMessageType::QZS_SSR_URA: //fallthrough + case +RtcmMessageType::QZS_SSR_HR_CLK_CORR: //fallthrough + case +RtcmMessageType::BDS_SSR_ORB_CORR: //fallthrough + case +RtcmMessageType::BDS_SSR_CLK_CORR: //fallthrough + case +RtcmMessageType::BDS_SSR_COMB_CORR: //fallthrough + case +RtcmMessageType::BDS_SSR_CODE_BIAS: //fallthrough + case +RtcmMessageType::BDS_SSR_PHASE_BIAS: //fallthrough + case +RtcmMessageType::BDS_SSR_URA: //fallthrough + case +RtcmMessageType::BDS_SSR_HR_CLK_CORR: //fallthrough + case +RtcmMessageType::SBS_SSR_ORB_CORR: //fallthrough + case +RtcmMessageType::SBS_SSR_CLK_CORR: //fallthrough + case +RtcmMessageType::SBS_SSR_COMB_CORR: //fallthrough + case +RtcmMessageType::SBS_SSR_CODE_BIAS: //fallthrough + case +RtcmMessageType::SBS_SSR_PHASE_BIAS: //fallthrough + case +RtcmMessageType::SBS_SSR_URA: //fallthrough + case +RtcmMessageType::SBS_SSR_HR_CLK_CORR: decodeSSR (message); break; + + case +RtcmMessageType::MSM4_GPS: //fallthrough + case +RtcmMessageType::MSM4_GLONASS: //fallthrough + case +RtcmMessageType::MSM4_GALILEO: //fallthrough + case +RtcmMessageType::MSM4_QZSS: //fallthrough + case +RtcmMessageType::MSM4_BEIDOU: //fallthrough + case +RtcmMessageType::MSM5_GPS: //fallthrough + case +RtcmMessageType::MSM5_GLONASS: //fallthrough + case +RtcmMessageType::MSM5_GALILEO: //fallthrough + case +RtcmMessageType::MSM5_QZSS: //fallthrough + case +RtcmMessageType::MSM5_BEIDOU: //fallthrough + case +RtcmMessageType::MSM6_GPS: //fallthrough + case +RtcmMessageType::MSM6_GLONASS: //fallthrough + case +RtcmMessageType::MSM6_GALILEO: //fallthrough + case +RtcmMessageType::MSM6_QZSS: //fallthrough + case +RtcmMessageType::MSM6_BEIDOU: //fallthrough + case +RtcmMessageType::MSM7_GPS: //fallthrough + case +RtcmMessageType::MSM7_GLONASS: //fallthrough + case +RtcmMessageType::MSM7_GALILEO: //fallthrough + case +RtcmMessageType::MSM7_QZSS: //fallthrough + case +RtcmMessageType::MSM7_BEIDOU: //fallthrough { - // Skip to the start of the frame - marked by preamble character 0xD3 - pos = inputStream.tellg(); + ObsList obsList = decodeMSM(message); - unsigned char c; - inputStream.read((char*)&c, 1); + int i = 54; + int multimessage = getbituInc(message, i, 1); - if (inputStream) +// tracepdeex(0, std::cout, "\n%2d %s %2d %2d ", messageId, obsList.front()->time.to_string().c_str(), obsList.size(), multimessage); + + if ( superObsList .empty() == false + && obsList .empty() == false + && fabs((superObsList.front()->time - obsList.front()->time).to_double()) > DTTOL) //todo aaron ew, fix { - if (c == RTCM_PREAMBLE) - { - break; - } + //time delta, push the old list and start a new one + obsListList.push_back(std::move(superObsList)); + superObsList.clear(); + + retVal = E_ReturnType::GOT_OBS; } - else + + //copy the new data into the new list + superObsList.insert(superObsList.end(), obsList.begin(), obsList.end()); + + if (multimessage == 0) { - return; + obsListList.push_back(std::move(superObsList)); + superObsList.clear(); + + retVal = E_ReturnType::GOT_OBS; } - byteCnt++; - } - - if (numPreambleFound == 0) - byteCnt = 0; - numPreambleFound++; - numNonMessBytes += byteCnt; - - if (byteCnt != 0) - { - std::stringstream message; - message << "RTCM Extra Bytes, size : " << byteCnt; - message << ", Total extra bytes : " << numNonMessBytes; - messageRtcmLog(message.str()); - } - - // Read the frame length - 2 bytes big endian only want 10 bits - char buf[2]; - inputStream.read((char*)buf, 2); - int pos2=inputStream.tellg(); - if (inputStream.fail()) - { - inputStream.clear(); - inputStream.seekg(pos); - return; - } - - auto message_length = RtcmDecoder::message_length(buf); - - // Read the frame data (include the header) - unsigned char data[message_length + 3]; - data[0] = RTCM_PREAMBLE; - data[1] = buf[0]; - data[2] = buf[1]; - unsigned char* message = data + 3; - inputStream.read((char*)message, message_length); - if (inputStream.fail()) - { - inputStream.clear(); - inputStream.seekg(pos); - return; - } - - // Read the frame CRC - unsigned int crcRead = 0; - inputStream.read((char*)&crcRead, 3); - if (inputStream.fail()) - { - inputStream.clear(); - inputStream.seekg(pos); - return; + if (superObsList.size() > 1000) + { + superObsList.clear(); + } + + break; } + + case +RtcmMessageType::IGS_SSR: decodeigsSSR (message, rtcmTime()); break; + // case +RtcmMessageType::COMPACT_SSR: decodecompactSSR(message, rtcmTime()); break; + } + + + if ( retVal == E_ReturnType::OK + || retVal == E_ReturnType::GOT_OBS) + { + frameDecoded(); + } + else if ( retVal == E_ReturnType::UNSUPPORTED) + { + if (acsConfig.output_decoded_rtcm_json) + traceUnknown(); + } + + return retVal; +} - unsigned int crcCalc = crc24q(data, sizeof(data)); - int nmeass = 0; - if (message_length > 8) - nmeass = getbitu(message, 0, 12); - if ( (((char*)&crcCalc)[0] != ((char*)&crcRead)[2]) - ||(((char*)&crcCalc)[1] != ((char*)&crcRead)[1]) - ||(((char*)&crcCalc)[2] != ((char*)&crcRead)[0])) - { - numFramesFailedCRC++; - std::stringstream message; - message << "RTCM CRC Failure, Number Fail CRC : " << numFramesFailedCRC; - message << ", Number Passed CRC : " << numFramesPassCRC; - message << ", Number Decoded : " << numFramesDecoded; - message << ", Number Preamble : " << numPreambleFound; - messageRtcmLog(message.str()); - inputStream.seekg(pos2); - continue; - } +/** extract unsigned bits from byte data +*/ +unsigned int getbitu( + const unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len) ///< bit length (bits) (len<=32) +{ + unsigned int bits = 0; + for (int i = pos; i < pos+len; i++) + bits = (bits<<1) + ((buff[i/8]>>(7-i%8))&1u); + + return bits; +} +/** extract unsigned bits from RTCM messages +*/ +unsigned int getbitu( + vector& buff, ///< RTCM messages + int pos, ///< bit position from start of data (bits) + int len) ///< bit length (bits) (len<=32) +{ + return getbitu(buff.data(), pos, len); +} - if (record_rtcm) +/** extract signed bits from byte data +*/ +int getbits( + const unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + bool* failure_ptr) ///< pointer for failure flag +{ + unsigned int bits = getbitu(buff, pos, len); + + long int invalid = (1ul<<(len-1)); + + if (bits == invalid) + { +// std::cout << "warning: invalid number received on " << __FUNCTION__ << " " << invalid << " " << len << std::endl; + if (failure_ptr) { - // Set the filenames based on system time, when replaying recorded streams - // the tsync time may be different. - - // Get time_t seconds since 00:00, 1/1/1970. - GTime curTime; - time(&curTime.time); - long int roundTime = curTime.time; - roundTime /= acsConfig.rotate_period; - roundTime *= acsConfig.rotate_period; - curTime.time = roundTime; - - string logtime = curTime.to_string(0); - std::replace( logtime.begin(), logtime.end(), '/', '-'); - - string path_rtcm = rtcm_filename; - replaceString(path_rtcm, "", logtime); //todo aaron, remove - - std::ofstream ofs(path_rtcm, std::ofstream::app); - - //Write the custom time stamp message. - RtcmEncoder encoder; - encoder.encodeTimeStampRTCM(); //todo aaron, this looks screwy, needs a return value to work? - encoder.encodeWriteMessages(ofs); - - //copy the message to the output file too - ofs.write((char *)data, message_length+3); - ofs.write((char *)&crcRead, 3); + *failure_ptr = true; } + } + + if ( len <= 0 + ||len >= 32 + ||!(bits&(1u<<(len-1)))) + { + return (int)bits; + } + return (int)(bits|(~0u<& buff, ///< byte data + int& pos, ///< bit position from start of data (bits) + int len) ///< bit length (bits) (len<=32) +{ + return getbituInc(buff.data(), pos, len); +} - rtcm_UTC = timestamp; +/** increasingly extract signed bits from byte data +*/ +int getbitsInc( + const unsigned char* buff, ///< byte data + int& pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + bool* failure_ptr) ///< pointer for failure flag +{ + int ans = getbits(buff, pos, len, failure_ptr); + pos += len; + return ans; +} - if (acsConfig.simulate_real_time) - { - //get the current time and compare it with the timestamp in the message - - boost::posix_time::ptime now_ptime = boost::posix_time::microsec_clock::universal_time(); - - // Number of seconds since 1/1/1970, long is 64 bits and all may be used. - long int seconds = (now_ptime - boost::posix_time::from_time_t(0)).total_seconds(); - - //Number of fractional seconds, The largest this can be is 1000 which is 10 bits unsigned. - boost::posix_time::ptime now_mod_seconds = boost::posix_time::from_time_t(seconds); - auto subseconds = now_ptime - now_mod_seconds; - int milli_sec = subseconds.total_milliseconds(); - - GTime now_gtime; - now_gtime.time = seconds; - now_gtime.sec = milli_sec / 1000.0; - - //find the delay between creation of the timestamp, and now - auto thisDeltaTime = now_gtime - timestamp; - - //initialise the global rtcm delay if needed - if (rtcmDeltaTime == GTime::noTime()) - { - rtcmDeltaTime = thisDeltaTime; - } - - //if the delay is shorter than the global, go back and wait until it is longer - if (thisDeltaTime < rtcmDeltaTime) - { -// printf("%ld\n", thisDeltaTime); - inputStream.seekg(pos); - return; - } - } - break; - } - } - } +/** increasingly extract signed bits from RTCM messages +*/ +int getbitsInc( + vector& buff, ///< byte data + int& pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + bool* failure_ptr) ///< pointer for failure flag +{ + return getbitsInc(buff.data(), pos, len, failure_ptr); +} - if ( message_type == +RtcmMessageType::GPS_EPHEMERIS - ||message_type == +RtcmMessageType::GAL_FNAV_EPHEMERIS - /*||message_type == +RtcmMessageType::GAL_INAV_EPHEMERIS*/) - { - numFramesDecoded++; - decodeEphemeris((uint8_t*) message, message_length); - } - else if ( message_type == +RtcmMessageType::GPS_SSR_COMB_CORR - ||message_type == +RtcmMessageType::GPS_SSR_ORB_CORR - ||message_type == +RtcmMessageType::GPS_SSR_CLK_CORR - ||message_type == +RtcmMessageType::GPS_SSR_URA - ||message_type == +RtcmMessageType::GAL_SSR_COMB_CORR - ||message_type == +RtcmMessageType::GAL_SSR_ORB_CORR - ||message_type == +RtcmMessageType::GAL_SSR_CLK_CORR - ||message_type == +RtcmMessageType::GPS_SSR_CODE_BIAS - ||message_type == +RtcmMessageType::GAL_SSR_CODE_BIAS - ||message_type == +RtcmMessageType::GPS_SSR_PHASE_BIAS - ||message_type == +RtcmMessageType::GAL_SSR_PHASE_BIAS) - { - numFramesDecoded++; - decodeSSR((uint8_t*) message, message_length); - } - else if ( message_type == +RtcmMessageType::MSM4_GPS - ||message_type == +RtcmMessageType::MSM4_GLONASS - ||message_type == +RtcmMessageType::MSM4_GALILEO - ||message_type == +RtcmMessageType::MSM4_QZSS - ||message_type == +RtcmMessageType::MSM4_BEIDOU - ||message_type == +RtcmMessageType::MSM5_GPS - ||message_type == +RtcmMessageType::MSM5_GLONASS - ||message_type == +RtcmMessageType::MSM5_GALILEO - ||message_type == +RtcmMessageType::MSM5_QZSS - ||message_type == +RtcmMessageType::MSM5_BEIDOU - ||message_type == +RtcmMessageType::MSM6_GPS - ||message_type == +RtcmMessageType::MSM6_GLONASS - ||message_type == +RtcmMessageType::MSM6_GALILEO - ||message_type == +RtcmMessageType::MSM6_QZSS - ||message_type == +RtcmMessageType::MSM6_BEIDOU - ||message_type == +RtcmMessageType::MSM7_GPS - ||message_type == +RtcmMessageType::MSM7_GLONASS - ||message_type == +RtcmMessageType::MSM7_GALILEO - ||message_type == +RtcmMessageType::MSM7_QZSS - ||message_type == +RtcmMessageType::MSM7_BEIDOU) - { - numFramesDecoded++; - ObsList obsList = decodeMSM7((uint8_t*) message, message_length); +/** increasingly extract signed bits from RTCM messages with scale factor/resolution applied +*/ +double getbitsIncScale( + vector& buff, ///< byte data + int& pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + double scale, ///< scale factor/resolution + bool* failure_ptr) ///< pointer for failure flag +{ + return scale * getbitsInc(buff.data(), pos, len, failure_ptr); +} - int i = 54; - int multimessage = getbituInc(message, i, 1); +/** increasingly extract unsigned bits from RTCM messages with scale factor/resolution applied +*/ +double getbituIncScale( + vector& buff, ///< byte data + int& pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + double scale) ///< scale factor/resolution +{ + return scale * getbituInc(buff.data(), pos, len); +} - //tracepdeex(rtcmdeblvl,std::cout, "\n%s %4d %s %2d %1d", station.name.c_str(), message_type._to_integral(), obsList.front().time.to_string(0).c_str(), obsList.size(), multimessage); +/** extract sign-magnitude bits applied in GLO nav messages from byte data +*/ +int getbitg( + const unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len) ///< bit length (bits) (len<=32) +{ + int value = getbitu(buff, pos+1, len-1); + return getbitu(buff, pos, 1) ? -value : value; +} - if (multimessage == 0) - { - SuperList.insert(SuperList.end(),obsList.begin(),obsList.end()); - obsListList.push_back(SuperList); - SuperList.clear(); - // Line added for parsing RTCM files, value indicates that it is the last MSM message - // for a given time and reference station ID. - return; - } - else if ( SuperList.size() > 0 - && obsList.size() > 0 - && fabs(SuperList.front().time - obsList.front().time) > 0.5) - { - obsListList.push_back(SuperList); - SuperList.clear(); - SuperList.insert(SuperList.end(), obsList.begin(), obsList.end()); - } - else - { - SuperList.insert(SuperList.end(), obsList.begin(), obsList.end()); - } +/** increasingly extract sign-magnitude bits applied in GLO nav messages from byte data +*/ +int getbitgInc( + const unsigned char* buff, ///< byte data + int& pos, ///< bit position from start of data (bits) + int len) ///< bit length (bits) (len<=32) +{ + int ans = getbitg(buff, pos, len); + pos += len; + return ans; +} - if (SuperList.size() > 1000) - { - SuperList.clear(); - } - } - } +/** increasingly extract sign-magnitude bits applied in GLO nav messages from RTCM messages +*/ +int getbitgInc( + vector& buff, ///< byte data + int& pos, ///< bit position from start of data (bits) + int len) ///< bit length (bits) (len<=32) +{ + return getbitgInc(buff.data(), pos, len); } diff --git a/src/cpp/common/rtcmDecoder.hpp b/src/cpp/common/rtcmDecoder.hpp index 3e2e3909e..3452b224d 100644 --- a/src/cpp/common/rtcmDecoder.hpp +++ b/src/cpp/common/rtcmDecoder.hpp @@ -1,19 +1,32 @@ -#ifndef __RTCM_DECODER__ -#define __RTCM_DECODER__ +#pragma once -#include "ntripTrace.hpp" +#include "packetStatistics.hpp" +#include "observations.hpp" +#include "rtcmEncoder.hpp" +#include "rtcmTrace.hpp" +#include "streamObs.hpp" +#include "acsConfig.hpp" +#include "gTime.hpp" +#include "enums.h" struct SignalInfo { uint8_t signal_id; E_FType ftype; - E_ObsCode rinex_observation_code; + E_ObsCode obsCode; }; -struct RtcmDecoder : RtcmTrace, RtcmStatistics +struct RtcmDecoder : RtcmTrace, ObsLister, PacketStatistics { - map> MSM7_lock_time; + static double rtcmDeltaTime; ///< Common time used among all rtcmDecoders for delaying decoding when realtime is enabled + static map receivedTimeMap; + + GTime lastTimeStamp; + + GTime receivedTime; ///< Recent internal time from decoded rtcm messages + + ObsList superObsList; ///< List to accumulate observations from smaller lists which share a common time static uint16_t message_length( char header[2]); @@ -21,13 +34,14 @@ struct RtcmDecoder : RtcmTrace, RtcmStatistics static RtcmMessageType message_type( const uint8_t message[]); - int adjgpsweek( + int adjGpsWeek( int week); - GTime tow2Time( - double tow); + int adjGstWeek( + int week); - GTime getGpst(); + int adjBdtWeek( + int week); void traceLatency(GTime gpsTime); @@ -36,43 +50,218 @@ struct RtcmDecoder : RtcmTrace, RtcmStatistics 1, 2, 5, 10, 15, 30, 60, 120, 240, 300, 600, 900, 1800, 3600, 7200, 10800 }; - E_FType code_to_ftype( - E_Sys sys, - E_ObsCode code); - - GTime rtcm_UTC; - - - boost::optional get_signal_info( - E_Sys sys, - uint8_t signal); + GTime rtcmTimestampTime; + GWeek rtcmWeek = -1; E_ObsCode signal_to_code( E_Sys sys, uint8_t signal); - GTime nowTime(); + GTime rtcmTime(); void decodeEphemeris( - uint8_t* data, - unsigned int message_length); + vector& message); void decodeSSR( - uint8_t* data, - unsigned int message_length); + vector& message); - GTime decodeCustomTimestamp( - uint8_t* data, - unsigned int message_length); + PTime decodeCustomTimestamp( + vector& message); E_RTCMSubmessage decodeCustomId( - uint8_t* data, - unsigned int message_length); + vector& message); - ObsList decodeMSM7( - uint8_t* data, - unsigned int message_length); + ObsList decodeMSM( + vector& message); + + string rtcm_filename; //todo aaron rename + + void recordFrame( + vector& data, + unsigned int crcRead) + { + if (rtcm_filename.empty()) + { + return; + } + + std::ofstream ofs(rtcm_filename, std::ofstream::app); + + if (!ofs) + { + return; + } + + //Write the custom time stamp message. + RtcmEncoder encoder; + encoder.rtcmTraceFilename = rtcmTraceFilename; + + auto buffer = encoder.encodeTimeStampRTCM(); + bool write = encoder.encodeWriteMessageToBuffer(buffer); + + if (write) + { + encoder.encodeWriteMessages(ofs); + } + + //copy the message to the output file too + ofs.write((char *)data.data(), data.size()); + ofs.write((char *)&crcRead, 3); + } + + + + enum E_ReturnType + { + UNSUPPORTED, + OK, + WAIT, + GOT_OBS + }; + + E_ReturnType decodeCustom( + vector& message) + { + E_RTCMSubmessage submessage = decodeCustomId(message); + + switch (submessage) + { + case (E_RTCMSubmessage::TIMESTAMP): + { + GTime timeStamp = decodeCustomTimestamp(message); + + rtcmTimestampTime = timeStamp; + + if (acsConfig.simulate_real_time) + { + //get the current time and compare it with the timestamp in the message + GTime now = timeGet(); + + //find the delay between creation of the timestamp, and now + double thisDeltaTime = (now - timeStamp).to_double(); + + //initialise the global rtcm delay if needed + if (rtcmDeltaTime == 0) + { + rtcmDeltaTime = thisDeltaTime; + } + + //if the delay is shorter than the global, go back and wait until it is longer + if (thisDeltaTime < rtcmDeltaTime) + { + return E_ReturnType::WAIT; + } + + if (acsConfig.output_decoded_rtcm_json) + traceTimestamp(timeStamp); + + break; + } + + if (1) + { + int& waitingStreams = receivedTimeMap[timeStamp]; + + if (lastTimeStamp == GTime::noTime()) + { + lastTimeStamp = timeStamp; + waitingStreams++; + + return E_ReturnType::WAIT; + } + + if (timeStamp != lastTimeStamp) + { + lastTimeStamp = timeStamp; + waitingStreams++; + } + + + auto& [firstTime, count] = *receivedTimeMap.begin(); + + if (timeStamp > firstTime) + { + return E_ReturnType::WAIT; + } + + if (timeStamp < firstTime) + { + std::cout << "unexpected time here" << std::endl; + exit(1); + } + + //we are the head of the pack, decrement/remove, and process + waitingStreams--; + + if (waitingStreams <= 0) + { + receivedTimeMap.erase(timeStamp); + } + } + + if (acsConfig.output_decoded_rtcm_json) + traceTimestamp(timeStamp); + + break; + } + default: + { + if (acsConfig.output_decoded_rtcm_json) + traceUnknown(); + + break; + } + } + + return E_ReturnType::OK; + } + + E_ReturnType decode( + vector& message); + }; -#endif +unsigned int getbitu (const unsigned char *buff, int pos, int len); + int getbits (const unsigned char *buff, int pos, int len, bool* failure_ptr = nullptr); +unsigned int getbituInc (const unsigned char *buff, int& pos, int len); + int getbitsInc (const unsigned char *buff, int& pos, int len, bool* failure_ptr = nullptr); + + +int getbitg (const unsigned char *buff, int pos, int len); +int getbitgInc (const unsigned char *buff, int& pos, int len); + +int getbitgInc( + vector& buff, + int& pos, + int len); + +unsigned int getbitu( + vector& buff, + int pos, + int len); + +unsigned int getbituInc( + vector& buff, + int& pos, + int len); + +int getbitsInc( + vector& buff, + int& pos, + int len, + bool* failure_ptr = nullptr); + +double getbituIncScale( + vector& buff, + int& pos, + int len, + double scale); + +double getbitsIncScale( + vector& buff, + int& pos, + int len, + double scale, + bool* failure_ptr = nullptr); + diff --git a/src/cpp/common/rtcmEncoder.cpp b/src/cpp/common/rtcmEncoder.cpp index fb8ed83ea..c04c027cf 100644 --- a/src/cpp/common/rtcmEncoder.cpp +++ b/src/cpp/common/rtcmEncoder.cpp @@ -7,13 +7,25 @@ #include "acsConfig.hpp" #include "constants.hpp" +/** Convert SSR URA to URA_CLASS and URA_VALUE combination, with 3 Msb URA_CLASS and 3Lsb URA_VALUE +*/ +int uraToClassValue(double ura) +{ + int uraClassValue = 0; + + for (uraClassValue = 0; uraClassValue < 64; uraClassValue++) + if (ura_ssr[uraClassValue] >= ura) + break; + + return uraClassValue; +} void calculateSsrComb( - GTime curTime, - int period, - SSRMeta ssrMeta, - int masterIod, - map& ssrOutMap) + GTime referenceTime, + int udi, + SSRMeta ssrMeta, + int masterIod, + SsrOutMap& ssrOutMap) { if (ssrOutMap.empty()) { @@ -21,8 +33,8 @@ void calculateSsrComb( return; } - map> commonClockOffsetsMap; // 0: bias; 1: bias rate - map> commonClockEpochsMap; // 0: 1st straddle pt epoch; 1: 2nd straddle pt epoch + map> commonClockOffsetsMap; // 0: bias; 1: bias rate + map> commonClockEpochsMap; // 0: 1st straddle pt epoch; 1: 2nd straddle pt epoch for (auto& [Sat, ssrOut] : ssrOutMap) { @@ -34,25 +46,30 @@ void calculateSsrComb( auto& ssrEph = ssrOut.ssrEph; auto& ssrClk = ssrOut.ssrClk; + auto& ssrUra = ssrOut.ssrUra; auto& ssrEphInput = ssrOut.ephInput; auto& ssrClkInput = ssrOut.clkInput; - ssrEph.t0 = curTime + period / 2; - ssrClk.t0 = curTime + period / 2; - ssrEph.udi = period; - ssrClk.udi = period; - ssrEph.iod = masterIod; - ssrClk.iod = masterIod; + ssrEph.t0 = referenceTime; + ssrClk.t0 = referenceTime; + ssrUra.t0 = referenceTime; + ssrEph.udi = udi; + ssrClk.udi = udi; + ssrUra.udi = udi; + ssrEph.iod = masterIod; + ssrClk.iod = masterIod; + ssrUra.iod = masterIod; - ssrEph.ssrMeta = ssrMeta; - ssrClk.ssrMeta = ssrMeta; + ssrEph.ssrMeta = ssrMeta; + ssrClk.ssrMeta = ssrMeta; + ssrUra.ssrMeta = ssrMeta; - ssrEph.iode = ssrEphInput.vals[0].iode; - - // ssrEph.iodcrc = ?? + ssrEph.iode = ssrEphInput.vals[0].iode; + // ssrEph.iodcrc = ?? double clkCorrections[2]; Vector3d posCorrections[2]; + double uras[2]; for (int i = 0; i < 2; i++) { @@ -60,20 +77,23 @@ void calculateSsrComb( - ssrEphInput.vals[i].precPos; clkCorrections[i] = ssrClkInput.vals[i].brdcClk - ssrClkInput.vals[i].precClk; + uras[i] = ephVarToUra(ssrEphInput.vals[i].ephVar); } - if (acsConfig.ssrOpts.extrapolate_corrections) + if (acsConfig.ssrOpts.extrapolate_corrections) // todo Eugene: check if ura can be interpolated { Vector3d diffRAC[2]; double diffClock[2]; + double uraSsr[2]; for (int dt : {0, 1}) { - double ephRatio = (ssrEph.t0 + dt - ssrEphInput.vals[0].time) / (ssrEphInput.vals[1].time - ssrEphInput.vals[0].time); - double clkRatio = (ssrClk.t0 + dt - ssrClkInput.vals[0].time) / (ssrClkInput.vals[1].time - ssrClkInput.vals[0].time); + double ephRatio = (ssrEph.t0 + dt - ssrEphInput.vals[0].time).to_double() / (ssrEphInput.vals[1].time - ssrEphInput.vals[0].time).to_double(); + double clkRatio = (ssrClk.t0 + dt - ssrClkInput.vals[0].time).to_double() / (ssrClkInput.vals[1].time - ssrClkInput.vals[0].time).to_double(); Vector3d posCorrection = posCorrections[0] + ephRatio * (posCorrections[1] - posCorrections[0]); double clkCorrection = clkCorrections[0] + clkRatio * (clkCorrections[1] - clkCorrections[0]); + double ura = uras[0] + ephRatio * (uras[1] - uras[0]); Vector3d satPosition = ssrEphInput.vals[0].brdcPos + ephRatio * (ssrEphInput.vals[1].brdcPos - ssrEphInput.vals[0].brdcPos); Vector3d satVelocity = ssrEphInput.vals[0].brdcVel + ephRatio * (ssrEphInput.vals[1].brdcVel - ssrEphInput.vals[0].brdcVel); @@ -82,6 +102,7 @@ void calculateSsrComb( diffRAC [dt] = diffRac; diffClock [dt] = -clkCorrection; + uraSsr [dt] = ura; } ssrEph. deph = diffRAC[0]; @@ -90,29 +111,32 @@ void calculateSsrComb( ssrClk.dclk[0] = diffClock[0]; ssrClk.dclk[1] = 0; //diffClock[1] - diffClock[0]; ssrClk.dclk[2] = 0; // set to zero (not used) + + ssrUra.ura = uraSsr[0]; } else { ssrEph.deph = ecef2rac(ssrEphInput.vals[1].brdcPos, ssrEphInput.vals[1].brdcVel) * posCorrections[1]; ssrClk.dclk[0] = -clkCorrections[1]; + ssrUra.ura = uras[1]; } //adjust all clock corrections so that they remain within the bounds of the outputs - E_BiasGroup biasGroup = E_BiasGroup::_from_integral(Sat.biasGroup()); - if (commonClockOffsetsMap[biasGroup][0] == 0) + E_Sys sys = Sat.sys; + if (commonClockOffsetsMap[sys][0] == 0) { - commonClockOffsetsMap[biasGroup][0] = ssrClk.dclk[0]; - commonClockOffsetsMap[biasGroup][1] = ssrClk.dclk[1]; - commonClockEpochsMap [biasGroup][0] = ssrClkInput.vals[0].time; - commonClockEpochsMap [biasGroup][1] = ssrClkInput.vals[1].time; + commonClockOffsetsMap[sys][0] = ssrClk.dclk[0]; + commonClockOffsetsMap[sys][1] = ssrClk.dclk[1]; + commonClockEpochsMap [sys][0] = ssrClkInput.vals[0].time; + commonClockEpochsMap [sys][1] = ssrClkInput.vals[1].time; } - if ( ssrClkInput.vals[0].time != commonClockEpochsMap[biasGroup][0] - ||ssrClkInput.vals[1].time != commonClockEpochsMap[biasGroup][1]) + if ( ssrClkInput.vals[0].time != commonClockEpochsMap[sys][0] + ||ssrClkInput.vals[1].time != commonClockEpochsMap[sys][1]) { continue; // commonClockOffset is lagging/leading this sat's clock, skip } - ssrClk.dclk[0] -= commonClockOffsetsMap[biasGroup][0]; - ssrClk.dclk[1] -= commonClockOffsetsMap[biasGroup][1]; + ssrClk.dclk[0] -= commonClockOffsetsMap[sys][0]; + ssrClk.dclk[1] -= commonClockOffsetsMap[sys][1]; } } @@ -152,133 +176,322 @@ bool RtcmEncoder::encodeWriteMessageToBuffer( { return false; } + + if (messLength > 1023) + { + BOOST_LOG_TRIVIAL(error) << "Error: message length exceeds the limit."; + return false; + } // unsigned char nbuf[messLength+6]; - vector newbuffer(messLength+6); + vector newbuffer(messLength + 6); unsigned char* nbuf = newbuffer.data(); unsigned char* buf = buffer.data(); - i = setbituInc(nbuf,i,8, RTCM_PREAMBLE); - i = setbituInc(nbuf,i,6, 0); - i = setbituInc(nbuf,i,10, messLength); + i = setbituInc(nbuf, i, 8, RTCM_PREAMBLE); + i = setbituInc(nbuf, i, 6, 0); + i = setbituInc(nbuf, i, 10, messLength); - memcpy(nbuf+3,buf,sizeof(uint8_t)*messLength); - i = i + messLength*8; + memcpy(nbuf + 3, buf, sizeof(uint8_t)* messLength); + i = i + messLength * 8; const unsigned char* bCrcBuf = (const unsigned char *)nbuf; - unsigned int crcCalc = crc24q(bCrcBuf, sizeof(char)*(messLength+3)); + unsigned int crcCalc = crc24q(bCrcBuf, sizeof(char) * (messLength + 3)); unsigned char* bCrcCalc = (unsigned char*)&crcCalc; unsigned int b1 = 0; unsigned int b2 = 0; unsigned int b3 = 0; - setbituInc((unsigned char *)&b1,0,8,*(bCrcCalc+0)); - setbituInc((unsigned char *)&b2,0,8,*(bCrcCalc+1)); - setbituInc((unsigned char *)&b3,0,8,*(bCrcCalc+2)); - i = setbituInc(nbuf,i,8,b3); - i = setbituInc(nbuf,i,8,b2); - i = setbituInc(nbuf,i,8,b1); + setbituInc((unsigned char *)&b1, 0, 8, *(bCrcCalc + 0)); + setbituInc((unsigned char *)&b2, 0, 8, *(bCrcCalc + 1)); + setbituInc((unsigned char *)&b3, 0, 8, *(bCrcCalc + 2)); + i = setbituInc(nbuf, i, 8, b3); + i = setbituInc(nbuf, i, 8, b2); + i = setbituInc(nbuf, i, 8, b1); - data.insert(data.end(), &nbuf[0], &nbuf[messLength+6]); + data.insert(data.end(), &nbuf[0], &nbuf[messLength + 6]); return true; } + vector RtcmEncoder::encodeTimeStampRTCM() { // Custom message code, for crcsi maximum length 4096 bits or 512 bytes. unsigned int messCode = +RtcmMessageType::CUSTOM; unsigned int messType = +E_RTCMSubmessage::TIMESTAMP; - boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); - - // Number of seconds since 1/1/1970, long is 64 bits and all may be used. - long int seconds = (now - boost::posix_time::from_time_t(0)).total_seconds(); - - //Number of fractional seconds, The largest this can be is 1000 which is 10 bits unsigned. - boost::posix_time::ptime now_mod_seconds = boost::posix_time::from_time_t(seconds); - auto subseconds = now - now_mod_seconds; - int milli_sec = subseconds.total_milliseconds(); - - unsigned int* var = (unsigned int*) &seconds; + PTime now = timeGet(); int i = 0; - //int byteLen = ceil((12.0+8.0+64.0+10.0)/8.0); - int byteLen = 12; + int byteLen = 11; vector buffer(byteLen); unsigned char* buf = buffer.data(); - i = setbituInc(buf, i, 12, messCode); - i = setbituInc(buf, i, 8, messType); - i = setbituInc(buf, i, 32, var[0]); - i = setbituInc(buf, i, 32, var[1]); - i = setbituInc(buf, i, 10, (int)milli_sec); + unsigned int reserved = 0; + i = setbituInc(buf, i, 12, messCode); + i = setbituInc(buf, i, 8, messType); + i = setbituInc(buf, i, 4, reserved); + + long int milliseconds = now.bigTime * 1000; + + unsigned int chunk; + chunk = milliseconds; i = setbituInc(buf, i, 32, chunk); milliseconds >>= 32; + chunk = milliseconds; i = setbituInc(buf, i, 32, chunk); + + traceTimestamp(now); return buffer; } -vector RtcmEncoder::encodeSsrComb( - map& ssrOutMap) + +/** encode SSR header information +*/ +int RtcmEncoder::encodeSsrHeader( + unsigned char* buf, ///< byte data + E_Sys sys, ///< system to encode + RtcmMessageType messCode, ///< RTCM message code to encode ephemeris of + SSRMeta& ssrMeta, ///< SSR metadata + int iod, ///< IOD SSR + int dispBiasConistInd, ///< Dispersive Bias Consistency Indicator (for phase bias only) + int MWConistInd) ///< MW Consistency Indicator (for phase bias only) +{ + string messCodeStr = messCode._to_string(); + string messTypeStr = messCodeStr.substr(8); + + int ne = 0; + int ns = 0; + switch (sys) + { + case E_Sys::GPS: ne = 20; ns = 6; break; + case E_Sys::GLO: ne = 17; ns = 6; break; + case E_Sys::GAL: ne = 20; ns = 6; break; + case E_Sys::QZS: ne = 20; ns = 4; break; + case E_Sys::BDS: ne = 20; ns = 6; break; + case E_Sys::SBS: ne = 20; ns = 6; break; + default: + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system: " << sys._to_string() << " in " << __FUNCTION__; + return 0; + } + + int i = 0; + i = setbituInc(buf, i, 12, messCode); + i = setbituInc(buf, i, ne, ssrMeta.epochTime1s); + i = setbituInc(buf, i, 4, ssrMeta.updateIntIndex); + i = setbituInc(buf, i, 1, ssrMeta.multipleMessage); + + if ( messTypeStr == "ORB_CORR" + ||messTypeStr == "COMB_CORR") + { + i = setbituInc(buf, i, 1, ssrMeta.referenceDatum); + } + + i = setbituInc(buf, i, 4, iod); + i = setbituInc(buf, i, 16, ssrMeta.provider); + i = setbituInc(buf, i, 4, ssrMeta.solution); + + if ( messTypeStr == "PHASE_BIAS") + { + i = setbituInc(buf, i, 1, dispBiasConistInd); + i = setbituInc(buf, i, 1, MWConistInd); + } + + i = setbituInc(buf, i, ns, ssrMeta.numSats); + + return i; +} + +/** encode orbit/clock messages +*/ +vector RtcmEncoder::encodeSsrOrbClk( + SsrOutMap& ssrOutMap, ///< orbits/clocks to encode + RtcmMessageType messCode) ///< RTCM message code to encode ephemeris of { - int numSat = ssrOutMap.size(); - if (numSat == 0) + string messCodeStr = messCode._to_string(); + string messTypeStr = messCodeStr.substr(8); + + int numSats = ssrOutMap.size(); + if (numSats == 0) { return vector(); } - auto& [Sat, ssrOut1] = *ssrOutMap.begin(); - auto& ssrEph = ssrOut1.ssrEph; + auto& [Sat, ssrOut] = *ssrOutMap.begin(); + auto& ssrEph = ssrOut.ssrEph; auto& ssrMeta = ssrEph.ssrMeta; - - int i = 0; - int bitLen = 0; - int ni = 0; - unsigned int messCode = 0; - if (Sat.sys == +E_Sys::GPS) { messCode = +RtcmMessageType::GPS_SSR_COMB_CORR; ni= 8; bitLen = 68+numSat*205;} - else if (Sat.sys == +E_Sys::GAL) { messCode = +RtcmMessageType::GAL_SSR_COMB_CORR; ni=10; bitLen = 68+numSat*207;} - - int byteLen = ceil(bitLen/8.0); + ssrMeta.numSats = numSats; + + int np = 0; + int ni = 0; + int nj = 0; + switch (Sat.sys) + { + case E_Sys::GPS: np = 6; ni = 8; nj = 0; break; + case E_Sys::GLO: np = 5; ni = 8; nj = 0; break; + case E_Sys::GAL: np = 6; ni = 10; nj = 0; break; + case E_Sys::QZS: np = 4; ni = 8; nj = 0; break; + case E_Sys::BDS: np = 6; ni = 8; nj = 10; break; + case E_Sys::SBS: np = 6; ni = 9; nj = 0; break; + default: + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system: " << Sat.sysName() << " in " << __FUNCTION__; + return vector(); + } + + int bitLen = 0; + switch (messCode) + { + case RtcmMessageType::GPS_SSR_ORB_CORR: bitLen = 68 + numSats * 135; break; + case RtcmMessageType::GPS_SSR_CLK_CORR: bitLen = 67 + numSats * 76; break; + case RtcmMessageType::GPS_SSR_COMB_CORR: bitLen = 68 + numSats * 205; break; + case RtcmMessageType::GPS_SSR_HR_CLK_CORR: bitLen = 67 + numSats * 28; break; + case RtcmMessageType::GLO_SSR_ORB_CORR: bitLen = 65 + numSats * 134; break; + case RtcmMessageType::GLO_SSR_CLK_CORR: bitLen = 64 + numSats * 75; break; + case RtcmMessageType::GLO_SSR_COMB_CORR: bitLen = 65 + numSats * 204; break; + case RtcmMessageType::GLO_SSR_HR_CLK_CORR: bitLen = 64 + numSats * 27; break; + case RtcmMessageType::GAL_SSR_ORB_CORR: bitLen = 68 + numSats * 137; break; + case RtcmMessageType::GAL_SSR_CLK_CORR: bitLen = 67 + numSats * 76; break; + case RtcmMessageType::GAL_SSR_COMB_CORR: bitLen = 68 + numSats * 207; break; + case RtcmMessageType::GAL_SSR_HR_CLK_CORR: bitLen = 67 + numSats * 28; break; + case RtcmMessageType::QZS_SSR_ORB_CORR: bitLen = 66 + numSats * 133; break; + case RtcmMessageType::QZS_SSR_CLK_CORR: bitLen = 65 + numSats * 74; break; + case RtcmMessageType::QZS_SSR_COMB_CORR: bitLen = 66 + numSats * 203; break; + case RtcmMessageType::QZS_SSR_HR_CLK_CORR: bitLen = 65 + numSats * 26; break; + case RtcmMessageType::BDS_SSR_ORB_CORR: bitLen = 68 + numSats * 145; break; + case RtcmMessageType::BDS_SSR_CLK_CORR: bitLen = 67 + numSats * 76; break; + case RtcmMessageType::BDS_SSR_COMB_CORR: bitLen = 68 + numSats * 215; break; + case RtcmMessageType::BDS_SSR_HR_CLK_CORR: bitLen = 67 + numSats * 28; break; + case RtcmMessageType::SBS_SSR_ORB_CORR: bitLen = 68 + numSats * 160; break; + case RtcmMessageType::SBS_SSR_CLK_CORR: bitLen = 67 + numSats * 76; break; + case RtcmMessageType::SBS_SSR_COMB_CORR: bitLen = 68 + numSats * 230; break; + case RtcmMessageType::SBS_SSR_HR_CLK_CORR: bitLen = 67 + numSats * 28; break; + default: return vector(); + } + + int byteLen = ceil(bitLen / 8.0); vector buffer(byteLen); unsigned char* buf = buffer.data(); + int i = 0; // Write the header information. - i = setbituInc(buf,i,12, messCode); - i = setbituInc(buf,i,20, ssrMeta.epochTime1s); - i = setbituInc(buf,i,4, ssrMeta.ssrUpdateIntIndex); - i = setbituInc(buf,i,1, ssrMeta.multipleMessage); - i = setbituInc(buf,i,1, ssrMeta.referenceDatum); - i = setbituInc(buf,i,4, ssrEph.iod); - i = setbituInc(buf,i,16, ssrMeta.provider); - i = setbituInc(buf,i,4, ssrMeta.solution); - i = setbituInc(buf,i,6, numSat); + i = encodeSsrHeader(buf, Sat.sys, messCode, ssrMeta, ssrEph.iod); for (auto& [Sat, ssrOut] : ssrOutMap) { auto& ssrEph = ssrOut.ssrEph; auto& ssrClk = ssrOut.ssrClk; + + SSRHRClk ssrHRClk; + ssrHRClk.ssrMeta = ssrClk.ssrMeta; + ssrHRClk.t0 = ssrClk.t0; + ssrHRClk.udi = ssrClk.udi; + ssrHRClk.iod = ssrClk.iod; + + //convert doubles to scaled integers + int deph [3]; + int ddeph [3]; + int dclk [3]; + deph[0] = (int)round(ssrEph.deph[0] / 0.1e-3); + deph[1] = (int)round(ssrEph.deph[1] / 0.4e-3); + deph[2] = (int)round(ssrEph.deph[2] / 0.4e-3); + ddeph[0] = (int)round(ssrEph.ddeph[0] / 0.001e-3); + ddeph[1] = (int)round(ssrEph.ddeph[1] / 0.004e-3); + ddeph[2] = (int)round(ssrEph.ddeph[2] / 0.004e-3); + dclk[0] = (int)round(ssrClk.dclk[0] / 0.1e-3); + dclk[1] = (int)round(ssrClk.dclk[1] / 0.001e-3); + dclk[2] = (int)round(ssrClk.dclk[2] / 0.00002e-3); + + i = setbituInc(buf, i, np, Sat.prn); + + if ( messTypeStr == "ORB_CORR" + ||messTypeStr == "COMB_CORR") + { + i = setbituInc(buf, i, nj, ssrEph.iodcrc); + i = setbituInc(buf, i, ni, ssrEph.iode); - i = setbituInc(buf,i, 6, Sat.prn); - i = setbituInc(buf,i, ni, ssrEph.iode); - - int d; - d = (int)round(ssrEph.deph[0] / 0.1e-3); i = setbitsInc(buf,i,22,d); - d = (int)round(ssrEph.deph[1] / 0.4e-3); i = setbitsInc(buf,i,20,d); - d = (int)round(ssrEph.deph[2] / 0.4e-3); i = setbitsInc(buf,i,20,d); - d = (int)round(ssrEph.ddeph[0] / 0.001e-3); i = setbitsInc(buf,i,21,d); - d = (int)round(ssrEph.ddeph[1] / 0.004e-3); i = setbitsInc(buf,i,19,d); - d = (int)round(ssrEph.ddeph[2] / 0.004e-3); i = setbitsInc(buf,i,19,d); - - d = (int)round(ssrClk.dclk[0] / 0.1e-3); i = setbitsInc(buf,i,22,d); - d = (int)round(ssrClk.dclk[1] / 0.001e-3); i = setbitsInc(buf,i,21,d); - d = (int)round(ssrClk.dclk[2] / 0.00002e-3); i = setbitsInc(buf,i,27,d); + i = setbitsInc(buf, i, 22, deph[0]); + i = setbitsInc(buf, i, 20, deph[1]); + i = setbitsInc(buf, i, 20, deph[2]); + i = setbitsInc(buf, i, 21, ddeph[0]); + i = setbitsInc(buf, i, 19, ddeph[1]); + i = setbitsInc(buf, i, 19, ddeph[2]); + + lastRegSsrEphMap[Sat] = ssrEph; - outputSsrEphToJson(ssrEph, Sat); - outputSsrClkToJson(ssrClk, Sat); + nav.satNavMap[Sat].transmittedSSR.ssrEph_map[ssrEph.t0] = ssrEph; + traceSsrEph(messCode, Sat, ssrEph); + } + + if ( messTypeStr == "CLK_CORR" + ||messTypeStr == "COMB_CORR") + { + try + { + auto& lastSsrEph = lastRegSsrEphMap.at(Sat); + + if (ssrEph.iode != lastSsrEph.iode) + { + return vector(); + } + } + catch (...) + { + return vector(); + } + + i = setbitsInc(buf, i, 22, dclk[0]); + i = setbitsInc(buf, i, 21, dclk[1]); + i = setbitsInc(buf, i, 27, dclk[2]); + + lastRegSsrClkMap[Sat] = ssrClk; + + nav.satNavMap[Sat].transmittedSSR.ssrClk_map[ssrClk.t0] = ssrClk; + traceSsrClk(messCode, Sat, ssrClk); + } + + if ( messTypeStr == "HR_CLK_CORR") + { + try + { + auto& lastSsrEph = lastRegSsrEphMap.at(Sat); + + if (ssrEph.iode != lastSsrEph.iode) + { + return vector(); + } + } + catch (...) + { + return vector(); + } + + try + { + auto& lastRegSsrClk = lastRegSsrClkMap.at(Sat); + + GTime currentTime = ssrHRClk.t0; + double tClk = (currentTime - lastRegSsrClk.t0).to_double(); + + double dclkReg = lastRegSsrClk.dclk[0] + + lastRegSsrClk.dclk[1] * tClk + + lastRegSsrClk.dclk[2] * tClk * tClk; + + ssrHRClk.hrclk = ssrClk.dclk[0] - dclkReg; + } + catch (...) + { + return vector(); + } + + i = setbitsInc(buf, i, 22, ssrHRClk.hrclk / 0.1e-3); + + nav.satNavMap[Sat].transmittedSSR.ssrHRClk_map[ssrHRClk.t0] = ssrHRClk; + traceSsrHRClk(messCode, Sat, ssrHRClk); + } } - int bitl = byteLen*8-i; + int bitl = byteLen * 8 - i; if (bitl > 7 ) { - BOOST_LOG_TRIVIAL(error) << "Error encoding combined.\n"; + BOOST_LOG_TRIVIAL(error) << "Error encoding SSR Orbit/Clock.\n"; BOOST_LOG_TRIVIAL(error) << "Error: bitl : " << bitl << ", i : " << i << ", byteLen : " << byteLen << std::endl; } i = setbituInc(buf, i, bitl, 0); @@ -286,63 +499,82 @@ vector RtcmEncoder::encodeSsrComb( return buffer; } +/** encode phase bias messages +*/ vector RtcmEncoder::encodeSsrPhase( - SsrPBMap& ssrPBMap) + SsrPBMap& ssrPBMap, ///< phase biases to encode + RtcmMessageType messCode) ///< RTCM message code to encode ephemeris of { - int numSat = ssrPBMap.size(); - - int i = 0; - int bitLen = 0; + int numSats = ssrPBMap.size(); + if (numSats == 0) + { + return vector(); + } - int totalNbias = 0; - for (auto& [Sat,ssrPhasBias] : ssrPBMap) + int totalNumBias = 0; + for (auto& [Sat, ssrPhasBias] : ssrPBMap) { - totalNbias += ssrPhasBias.obsCodeBiasMap.size(); + totalNumBias += ssrPhasBias.obsCodeBiasMap.size(); } - - if (totalNbias == 0) + if (totalNumBias == 0) + { return vector(); + } - // Write the header information. - auto s_it = ssrPBMap.begin(); - auto& [Sat, ssrPhasBias] = *s_it; - SSRMeta& ssrMeta = ssrPhasBias.ssrMeta; + auto& [Sat, ssrPhasBias] = *ssrPBMap.begin(); + auto& ssrMeta = ssrPhasBias.ssrMeta; + ssrMeta.numSats = numSats; int np = 0; - int ni = 0; - int nj = 0; - int offp = 0; - unsigned int messCode = 0; - if (Sat.sys == +E_Sys::GPS) { messCode = +RtcmMessageType::GPS_SSR_PHASE_BIAS; np=6; ni= 8; nj= 0; offp=0; bitLen = 69+numSat*28+totalNbias*32;} - if (Sat.sys == +E_Sys::GAL) { messCode = +RtcmMessageType::GAL_SSR_PHASE_BIAS; np=6; ni=10; nj= 0; offp=0; bitLen = 69+numSat*28+totalNbias*32;} + switch (Sat.sys) + { + case E_Sys::GPS: np = 6; break; + case E_Sys::GLO: np = 5; break; + case E_Sys::GAL: np = 6; break; + case E_Sys::QZS: np = 4; break; + case E_Sys::BDS: np = 6; break; + case E_Sys::SBS: np = 6; break; + default: + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system: " << Sat.sysName() << " in " << __FUNCTION__; + return vector(); + } + + int bitLen = 0; + switch (messCode) + { + case RtcmMessageType::GPS_SSR_PHASE_BIAS: bitLen = 69 + numSats * 28 + totalNumBias * 32; break; + case RtcmMessageType::GLO_SSR_PHASE_BIAS: bitLen = 66 + numSats * 27 + totalNumBias * 32; break; + case RtcmMessageType::GAL_SSR_PHASE_BIAS: bitLen = 69 + numSats * 28 + totalNumBias * 32; break; + case RtcmMessageType::QZS_SSR_PHASE_BIAS: bitLen = 67 + numSats * 26 + totalNumBias * 32; break; + case RtcmMessageType::BDS_SSR_PHASE_BIAS: bitLen = 69 + numSats * 28 + totalNumBias * 32; break; + case RtcmMessageType::SBS_SSR_PHASE_BIAS: bitLen = 69 + numSats * 28 + totalNumBias * 32; break; + default: return vector(); + } - int byteLen = ceil(bitLen/8.0); + int byteLen = ceil(bitLen / 8.0); vector buffer(byteLen); unsigned char* buf = buffer.data(); - i = setbituInc(buf,i,12,messCode); - i = setbituInc(buf,i,20,ssrMeta.epochTime1s); - i = setbituInc(buf,i,4, ssrMeta.ssrUpdateIntIndex); - i = setbituInc(buf,i,1, ssrMeta.multipleMessage); - - i = setbituInc(buf,i,4, ssrPhasBias.iod); - i = setbituInc(buf,i,16,ssrMeta.provider); - i = setbituInc(buf,i,4, ssrMeta.solution); - - i = setbituInc(buf,i,1, ssrPhasBias.ssrPhase.dispBiasConistInd); - i = setbituInc(buf,i,1, ssrPhasBias.ssrPhase.MWConistInd); - - i = setbituInc(buf,i,6,numSat); + int i = 0; + // Write the header information. + int dispBiasConistInd = ssrPhasBias.ssrPhase.dispBiasConistInd; + int MWConistInd = ssrPhasBias.ssrPhase.MWConistInd; + i = encodeSsrHeader(buf, Sat.sys, messCode, ssrMeta, ssrPhasBias.iod, dispBiasConistInd, MWConistInd); - for (auto& [sat, ssrPhasBias] : ssrPBMap) + for (auto& [Sat, ssrPhasBias] : ssrPBMap) { + ssrPhasBias.udi = updateInterval[ssrMeta.updateIntIndex]; // for rtcmTrace (debugging) + SSRPhase ssrPhase = ssrPhasBias.ssrPhase; - int d; - i = setbituInc(buf,i,np,sat.prn); - d = ssrPhasBias.obsCodeBiasMap.size(); i = setbituInc(buf,i,5, d); - d = (int)round(ssrPhase.yawAngle *256 /PI); i = setbituInc(buf,i,9, d); - d = (int)round(ssrPhase.yawRate *8192 /PI); i = setbitsInc(buf,i,8, d); + unsigned int nbias = ssrPhasBias.obsCodeBiasMap.size(); + int yawAngle = (int)round(ssrPhase.yawAngle * 256 / SC2RAD); + int yawRate = (int)round(ssrPhase.yawRate * 8192 / SC2RAD); + + i = setbituInc(buf, i, np, Sat.prn); + i = setbituInc(buf, i, 5, nbias); + i = setbituInc(buf, i, 9, yawAngle); + i = setbitsInc(buf, i, 8, yawRate); for (auto& [obsCode, entry] : ssrPhasBias.obsCodeBiasMap) { @@ -353,110 +585,677 @@ vector RtcmEncoder::encodeSsrPhase( //BOOST_LOG_TRIVIAL(debug) << "mCodes_gps.size() : " << mCodes_gps.size() << std::endl; //print_map( mCodes_gps.left, " E_ObsCode <--> RTCM ", BOOST_LOG_TRIVIAL(debug) ); - int rtcm_code = 0; - if ( sat.sys == +E_Sys::GPS ) rtcm_code = mCodes_gps.left.at(obsCode); //todo aaron, crash heaven, needs else, try - else if ( sat.sys == +E_Sys::GAL ) rtcm_code = mCodes_gal.left.at(obsCode); + int rtcmCode = 0; + if (Sat.sys == +E_Sys::GPS) { rtcmCode = mCodes_gps.left.at(obsCode); } //todo aaron, crash heaven, needs else, try + else if (Sat.sys == +E_Sys::GLO) { rtcmCode = mCodes_glo.left.at(obsCode); } + else if (Sat.sys == +E_Sys::GAL) { rtcmCode = mCodes_gal.left.at(obsCode); } + else if (Sat.sys == +E_Sys::QZS) { rtcmCode = mCodes_qzs.left.at(obsCode); } + else if (Sat.sys == +E_Sys::BDS) { rtcmCode = mCodes_bds.left.at(obsCode); } + else if (Sat.sys == +E_Sys::SBS) { rtcmCode = mCodes_sbs.left.at(obsCode); } - //BOOST_LOG_TRIVIAL(debug) << "rtcm_code : " << rtcm_code << std::endl; + //BOOST_LOG_TRIVIAL(debug) << "rtcmCode : " << rtcmCode << std::endl; - i = setbituInc(buf,i,5, rtcm_code); - i = setbituInc(buf,i,1, ssrPhaseCh.signalIntInd); - i = setbituInc(buf,i,2, ssrPhaseCh.signalWidIntInd); - i = setbituInc(buf,i,4, ssrPhaseCh.signalDisconCnt); - d = (int)round(entry.bias / 0.0001); i = setbitsInc(buf,i,20,d); + int bias = (int)round(entry.bias / 0.0001); + + i = setbituInc(buf, i, 5, rtcmCode); + i = setbituInc(buf, i, 1, ssrPhaseCh.signalIntInd); + i = setbituInc(buf, i, 2, ssrPhaseCh.signalWLIntInd); + i = setbituInc(buf, i, 4, ssrPhaseCh.signalDisconCnt); + i = setbitsInc(buf, i, 20, bias); + + nav.satNavMap[Sat].transmittedSSR.ssrPhasBias_map[ssrPhasBias.t0] = ssrPhasBias; - traceSsrPhasB(sat, obsCode, ssrPhasBias); + traceSsrPhasBias(messCode, Sat, obsCode, ssrPhasBias); } } - int bitl = byteLen*8-i; + int bitl = byteLen * 8 - i; if (bitl > 7 ) { BOOST_LOG_TRIVIAL(error) << "Error encoding SSR Phase.\n"; BOOST_LOG_TRIVIAL(error) << "Error: bitl : " << bitl << ", i : " << i << ", byteLen : " << byteLen << std::endl; } - i = setbituInc(buf,i,bitl,0); + i = setbituInc(buf, i, bitl, 0); return buffer; } - +/** encode code bias messages +*/ vector RtcmEncoder::encodeSsrCode( - SsrCBMap& ssrCBMap) + SsrCBMap& ssrCBMap, ///< code biases to encode + RtcmMessageType messCode) ///< RTCM message code to encode ephemeris of { - int numSat = ssrCBMap.size(); + int numSats = ssrCBMap.size(); + if (numSats == 0) + { + return vector(); + } + int totalNumBias = 0; + for (auto& [Sat, ssrCodeBias] : ssrCBMap) + { + totalNumBias += ssrCodeBias.obsCodeBiasMap.size(); + } + if (totalNumBias == 0) + { + return vector(); + } + + auto& [Sat, ssrCodeBias] = *ssrCBMap.begin(); + auto& ssrMeta = ssrCodeBias.ssrMeta; + ssrMeta.numSats = numSats; + + int np = 0; + switch (Sat.sys) + { + case E_Sys::GPS: np = 6; break; + case E_Sys::GLO: np = 5; break; + case E_Sys::GAL: np = 6; break; + case E_Sys::QZS: np = 4; break; + case E_Sys::BDS: np = 6; break; + case E_Sys::SBS: np = 6; break; + default: + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system: " << Sat.sysName() << " in " << __FUNCTION__; + return vector(); + } + + int bitLen = 0; + switch (messCode) + { + case RtcmMessageType::GPS_SSR_CODE_BIAS: bitLen = 67 + numSats * 11 + totalNumBias * 19; break; + case RtcmMessageType::GLO_SSR_CODE_BIAS: bitLen = 64 + numSats * 10 + totalNumBias * 19; break; + case RtcmMessageType::GAL_SSR_CODE_BIAS: bitLen = 67 + numSats * 11 + totalNumBias * 19; break; + case RtcmMessageType::QZS_SSR_CODE_BIAS: bitLen = 65 + numSats * 9 + totalNumBias * 19; break; + case RtcmMessageType::BDS_SSR_CODE_BIAS: bitLen = 67 + numSats * 11 + totalNumBias * 19; break; + case RtcmMessageType::SBS_SSR_CODE_BIAS: bitLen = 67 + numSats * 11 + totalNumBias * 19; break; + default: return vector(); + } + + int byteLen = ceil(bitLen / 8.0); + vector buffer(byteLen); + unsigned char* buf = buffer.data(); + int i = 0; + // Write the header information. + i = encodeSsrHeader(buf, Sat.sys, messCode, ssrMeta, ssrCodeBias.iod); - int totalNbias = 0; - for (auto s_it = ssrCBMap.begin(); s_it != ssrCBMap.end(); s_it++) + for (auto& [Sat, ssrCodeBias] : ssrCBMap) { - SSRCodeBias ssrCodeBias = s_it->second; - totalNbias += ssrCodeBias.obsCodeBiasMap.size(); + ssrCodeBias.udi = updateInterval[ssrMeta.updateIntIndex]; // for rtcmTrace (debugging) + + unsigned int nbias = ssrCodeBias.obsCodeBiasMap.size(); + + i = setbituInc(buf, i, np, Sat.prn); + i = setbituInc(buf, i, 5, nbias); + + for (auto& [obsCode, entry] : ssrCodeBias.obsCodeBiasMap) + { + int rtcmCode = 0; + if (Sat.sys == +E_Sys::GPS) { rtcmCode = mCodes_gps.left.at(obsCode); } + else if (Sat.sys == +E_Sys::GLO) { rtcmCode = mCodes_glo.left.at(obsCode); } + else if (Sat.sys == +E_Sys::GAL) { rtcmCode = mCodes_gal.left.at(obsCode); } + else if (Sat.sys == +E_Sys::QZS) { rtcmCode = mCodes_qzs.left.at(obsCode); } + else if (Sat.sys == +E_Sys::BDS) { rtcmCode = mCodes_bds.left.at(obsCode); } + else if (Sat.sys == +E_Sys::SBS) { rtcmCode = mCodes_sbs.left.at(obsCode); } + + int bias = (int)round(entry.bias / 0.01); + + i = setbituInc(buf, i, 5, rtcmCode); + i = setbitsInc(buf, i, 14, bias); + + nav.satNavMap[Sat].transmittedSSR.ssrCodeBias_map[ssrCodeBias.t0] = ssrCodeBias; + + traceSsrCodeBias(messCode, Sat, obsCode, ssrCodeBias); + } } - if (totalNbias == 0) + int bitl = byteLen * 8 - i; + if (bitl > 7) { - return vector(); + BOOST_LOG_TRIVIAL(error) << "Error encoding SSR Code.\n"; + BOOST_LOG_TRIVIAL(error) << "Error: bitl : " << bitl << ", i : " << i << ", byteLen : " << byteLen << std::endl; } + i = setbituInc(buf, i, bitl, 0); - // Write the header information. + return buffer; +} - auto s_it = ssrCBMap.begin(); - auto& [Sat, ssrCodeBias] = *s_it; - SSRMeta& ssrMeta = ssrCodeBias.ssrMeta; +/** encode URA messages +*/ +vector RtcmEncoder::encodeSsrUra( + SsrOutMap& ssrOutMap, ///< URAs to encode + RtcmMessageType messCode) ///< RTCM message code to encode ephemeris of +{ + int numSats = ssrOutMap.size(); + if (numSats == 0) + { + return vector(); + } - int bitLen = 67 - + 11 * numSat - + 19 * totalNbias; - int byteLen = ceil(bitLen / 8.0); + auto& [Sat, ssrOut] = *ssrOutMap.begin(); + auto& ssrUra = ssrOut.ssrUra; + auto& ssrMeta = ssrUra.ssrMeta; + ssrMeta.numSats = numSats; + int np = 0; + switch (Sat.sys) + { + case E_Sys::GPS: np = 6; break; + case E_Sys::GLO: np = 5; break; + case E_Sys::GAL: np = 6; break; + case E_Sys::QZS: np = 4; break; + case E_Sys::BDS: np = 6; break; + case E_Sys::SBS: np = 6; break; + default: + BOOST_LOG_TRIVIAL(error) << "Error: unrecognised system: " << Sat.sysName() << " in " << __FUNCTION__; + return vector(); + } + + int bitLen = 0; + switch (messCode) + { + case RtcmMessageType::GPS_SSR_URA: bitLen = 67 + numSats * 12; break; + case RtcmMessageType::GLO_SSR_URA: bitLen = 64 + numSats * 11; break; + case RtcmMessageType::GAL_SSR_URA: bitLen = 67 + numSats * 12; break; + case RtcmMessageType::QZS_SSR_URA: bitLen = 65 + numSats * 10; break; + case RtcmMessageType::BDS_SSR_URA: bitLen = 67 + numSats * 12; break; + case RtcmMessageType::SBS_SSR_URA: bitLen = 67 + numSats * 12; break; + default: return vector(); + } + + int byteLen = ceil(bitLen / 8.0); vector buffer(byteLen); unsigned char* buf = buffer.data(); + + int i = 0; + // Write the header information. + i = encodeSsrHeader(buf, Sat.sys, messCode, ssrMeta, ssrUra.iod); - unsigned int messCode = 0; - if (Sat.sys == +E_Sys::GPS) { messCode = +RtcmMessageType::GPS_SSR_CODE_BIAS;} - if (Sat.sys == +E_Sys::GAL) { messCode = +RtcmMessageType::GAL_SSR_CODE_BIAS;} + for (auto& [Sat, ssrOut] : ssrOutMap) + { + auto& ssrUra = ssrOut.ssrUra; - i = setbituInc(buf,i,12,messCode); - i = setbituInc(buf,i,20,ssrMeta.epochTime1s); - i = setbituInc(buf,i,4, ssrMeta.ssrUpdateIntIndex); - i = setbituInc(buf,i,1, ssrMeta.multipleMessage); + ssrUra.udi = updateInterval[ssrMeta.updateIntIndex]; // for rtcmTrace (debugging) + + int uraClassValue = uraToClassValue(ssrUra.ura); + + i = setbituInc(buf, i, np, Sat.prn); + i = setbituInc(buf, i, 6, uraClassValue); + + nav.satNavMap[Sat].transmittedSSR.ssrUra_map[ssrUra.t0] = ssrUra; + + traceSsrUra(messCode, Sat, ssrUra); + } + + int bitl = byteLen * 8 - i; + if (bitl > 7 ) + { + BOOST_LOG_TRIVIAL(error) << "Error encoding SSR URA.\n"; + BOOST_LOG_TRIVIAL(error) << "Error: bitl : " << bitl << ", i : " << i << ", byteLen : " << byteLen << std::endl; + } + i = setbituInc(buf, i, bitl, 0); - i = setbituInc(buf,i,4, ssrCodeBias.iod); - i = setbituInc(buf,i,16,ssrMeta.provider); - i = setbituInc(buf,i,4, ssrMeta.solution); - i = setbituInc(buf,i,6, numSat); + return buffer; +} - for (auto& [sat, ssrCodeBias] : ssrCBMap) +/** encode GPS/GAL/BDS/QZS ephemeris messages +*/ +vector RtcmEncoder::encodeEphemeris( + Eph& eph, ///< ephemeris to encode + RtcmMessageType messCode) ///< RTCM message code to encode ephemeris of +{ + int bitLen = 0; + switch (messCode) { - i = setbituInc(buf, i, 6, sat.prn); - unsigned int nbias = ssrCodeBias.obsCodeBiasMap.size(); + case RtcmMessageType:: GPS_EPHEMERIS: { bitLen = 488; break; } + case RtcmMessageType:: BDS_EPHEMERIS: { bitLen = 511; break; } + case RtcmMessageType:: QZS_EPHEMERIS: { bitLen = 485; break; } + case RtcmMessageType:: GAL_FNAV_EPHEMERIS: { bitLen = 496; break; } + case RtcmMessageType:: GAL_INAV_EPHEMERIS: { bitLen = 504; break; } + default: return vector(); + } - i = setbituInc(buf, i, 5, nbias); - - for (auto& [obsCode, entry] : ssrCodeBias.obsCodeBiasMap) - { - int rtcm_code = 0; - if ( sat.sys == +E_Sys::GPS ) { rtcm_code = mCodes_gps.left.at(obsCode); } - else if ( sat.sys == +E_Sys::GAL ) { rtcm_code = mCodes_gal.left.at(obsCode); } + int byteLen = ceil(bitLen / 8.0); + vector buffer(byteLen); + unsigned char* buf = buffer.data(); + + int i = 0; + i = setbituInc(buf, i, 12, messCode); + + auto Sat = eph.Sat; + auto type = eph.type; + if (Sat.sys == +E_Sys::GPS) + { + int idot = (int) round(eph.idot /P2_43/SC2RAD); + int tocs = (int) round(eph.tocs /16.0 ); + int f2 = (int) round(eph.f2 /P2_55); + int f1 = (int) round(eph.f1 /P2_43); + int f0 = (int) round(eph.f0 /P2_31); + int crs = (int) round(eph.crs /P2_5 ); + int deln = (int) round(eph.deln /P2_43/SC2RAD); + int M0 = (int) round(eph.M0 /P2_31/SC2RAD); + int cuc = (int) round(eph.cuc /P2_29); + unsigned int e = (unsigned int)round(eph.e /P2_33); + int cus = (int) round(eph.cus /P2_29); + unsigned int sqrtA = (unsigned int)round(eph.sqrtA /P2_19); + int toes = (int) round(eph.toes /16.0 ); + int cic = (int) round(eph.cic /P2_29); + int OMG0 = (int) round(eph.OMG0 /P2_31/SC2RAD); + int cis = (int) round(eph.cis /P2_29); + int i0 = (int) round(eph.i0 /P2_31/SC2RAD); + int crc = (int) round(eph.crc /P2_5 ); + int omg = (int) round(eph.omg /P2_31/SC2RAD); + int OMGd = (int) round(eph.OMGd /P2_43/SC2RAD); + int tgd = (int) round(eph.tgd[0]/P2_31); + + i = setbituInc(buf, i, 6, Sat.prn); + i = setbituInc(buf, i, 10, eph.weekRollOver); + i = setbituInc(buf, i, 4, eph.sva); + i = setbituInc(buf, i, 2, eph.code); + i = setbitsInc(buf, i, 14, idot); + i = setbituInc(buf, i, 8, eph.iode); + i = setbituInc(buf, i, 16, tocs); + i = setbitsInc(buf, i, 8, f2); + i = setbitsInc(buf, i, 16, f1); + i = setbitsInc(buf, i, 22, f0); + i = setbituInc(buf, i, 10, eph.iodc); + i = setbitsInc(buf, i, 16, crs); + i = setbitsInc(buf, i, 16, deln); + i = setbitsInc(buf, i, 32, M0); + i = setbitsInc(buf, i, 16, cuc); + i = setbituInc(buf, i, 32, e); + i = setbitsInc(buf, i, 16, cus); + i = setbituInc(buf, i, 32, sqrtA); + i = setbituInc(buf, i, 16, toes); + i = setbitsInc(buf, i, 16, cic); + i = setbitsInc(buf, i, 32, OMG0); + i = setbitsInc(buf, i, 16, cis); + i = setbitsInc(buf, i, 32, i0); + i = setbitsInc(buf, i, 16, crc); + i = setbitsInc(buf, i, 32, omg); + i = setbitsInc(buf, i, 24, OMGd); + i = setbitsInc(buf, i, 8, tgd); + i = setbituInc(buf, i, 6, eph.svh); + i = setbituInc(buf, i, 1, eph.flag); + i = setbituInc(buf, i, 1, eph.fitFlag); + } + else if (Sat.sys == +E_Sys::BDS) + { + int idot = (int) round(eph.idot /P2_43/SC2RAD); + int tocs = (int) round(eph.tocs /8.0 ); + int f2 = (int) round(eph.f2 /P2_66); + int f1 = (int) round(eph.f1 /P2_50); + int f0 = (int) round(eph.f0 /P2_33); + int crs = (int) round(eph.crs /P2_6 ); + int deln = (int) round(eph.deln /P2_43/SC2RAD); + int M0 = (int) round(eph.M0 /P2_31/SC2RAD); + int cuc = (int) round(eph.cuc /P2_31); + unsigned int e = (unsigned int)round(eph.e /P2_33); + int cus = (int) round(eph.cus /P2_31); + unsigned int sqrtA = (unsigned int)round(eph.sqrtA /P2_19); + int toes = (int) round(eph.toes /8.0 ); + int cic = (int) round(eph.cic /P2_31); + int OMG0 = (int) round(eph.OMG0 /P2_31/SC2RAD); + int cis = (int) round(eph.cis /P2_31); + int i0 = (int) round(eph.i0 /P2_31/SC2RAD); + int crc = (int) round(eph.crc /P2_6 ); + int omg = (int) round(eph.omg /P2_31/SC2RAD); + int OMGd = (int) round(eph.OMGd /P2_43/SC2RAD); + int tgd1 = (int) round(eph.tgd[0]/1E-10); + int tgd2 = (int) round(eph.tgd[1]/1E-10); + + i = setbituInc(buf, i, 6, Sat.prn); + i = setbituInc(buf, i, 13, eph.weekRollOver); + i = setbituInc(buf, i, 4, eph.sva); + i = setbitsInc(buf, i, 14, idot); + i = setbituInc(buf, i, 5, eph.aode); + i = setbituInc(buf, i, 17, tocs); + i = setbitsInc(buf, i, 11, f2); + i = setbitsInc(buf, i, 22, f1); + i = setbitsInc(buf, i, 24, f0); + i = setbituInc(buf, i, 5, eph.aodc); + i = setbitsInc(buf, i, 18, crs); + i = setbitsInc(buf, i, 16, deln); + i = setbitsInc(buf, i, 32, M0); + i = setbitsInc(buf, i, 18, cuc); + i = setbituInc(buf, i, 32, e); + i = setbitsInc(buf, i, 18, cus); + i = setbituInc(buf, i, 32, sqrtA); + i = setbituInc(buf, i, 17, toes); + i = setbitsInc(buf, i, 18, cic); + i = setbitsInc(buf, i, 32, OMG0); + i = setbitsInc(buf, i, 18, cis); + i = setbitsInc(buf, i, 32, i0); + i = setbitsInc(buf, i, 18, crc); + i = setbitsInc(buf, i, 32, omg); + i = setbitsInc(buf, i, 24, OMGd); + i = setbitsInc(buf, i, 10, tgd1); + i = setbitsInc(buf, i, 10, tgd2); + i = setbituInc(buf, i, 1, eph.svh); + } + else if (Sat.sys == +E_Sys::QZS) + { + int tocs = (int) round(eph.tocs /16.0 ); + int f2 = (int) round(eph.f2 /P2_55); + int f1 = (int) round(eph.f1 /P2_43); + int f0 = (int) round(eph.f0 /P2_31); + int crs = (int) round(eph.crs /P2_5 ); + int deln = (int) round(eph.deln /P2_43/SC2RAD); + int M0 = (int) round(eph.M0 /P2_31/SC2RAD); + int cuc = (int) round(eph.cuc /P2_29); + unsigned int e = (unsigned int)round(eph.e /P2_33); + int cus = (int) round(eph.cus /P2_29); + unsigned int sqrtA = (unsigned int)round(eph.sqrtA /P2_19); + int toes = (int) round(eph.toes /16.0 ); + int cic = (int) round(eph.cic /P2_29); + int OMG0 = (int) round(eph.OMG0 /P2_31/SC2RAD); + int cis = (int) round(eph.cis /P2_29); + int i0 = (int) round(eph.i0 /P2_31/SC2RAD); + int crc = (int) round(eph.crc /P2_5 ); + int omg = (int) round(eph.omg /P2_31/SC2RAD); + int OMGd = (int) round(eph.OMGd /P2_43/SC2RAD); + int idot = (int) round(eph.idot /P2_43/SC2RAD); + int tgd = (int) round(eph.tgd[0]/P2_31); + + i = setbituInc(buf, i, 4, Sat.prn); + i = setbituInc(buf, i, 16, tocs); + i = setbitsInc(buf, i, 8, f2); + i = setbitsInc(buf, i, 16, f1); + i = setbitsInc(buf, i, 22, f0); + i = setbituInc(buf, i, 8, eph.iode); + i = setbitsInc(buf, i, 16, crs); + i = setbitsInc(buf, i, 16, deln); + i = setbitsInc(buf, i, 32, M0); + i = setbitsInc(buf, i, 16, cuc); + i = setbituInc(buf, i, 32, e); + i = setbitsInc(buf, i, 16, cus); + i = setbituInc(buf, i, 32, sqrtA); + i = setbituInc(buf, i, 16, toes); + i = setbitsInc(buf, i, 16, cic); + i = setbitsInc(buf, i, 32, OMG0); + i = setbitsInc(buf, i, 16, cis); + i = setbitsInc(buf, i, 32, i0); + i = setbitsInc(buf, i, 16, crc); + i = setbitsInc(buf, i, 32, omg); + i = setbitsInc(buf, i, 24, OMGd); + i = setbitsInc(buf, i, 14, idot); + i = setbituInc(buf, i, 2, eph.code); + i = setbituInc(buf, i, 10, eph.weekRollOver); + i = setbituInc(buf, i, 4, eph.sva); + i = setbituInc(buf, i, 6, eph.svh); + i = setbitsInc(buf, i, 8, tgd); + i = setbituInc(buf, i, 10, eph.iodc); + i = setbituInc(buf, i, 1, eph.fitFlag); + } + else if (Sat.sys == +E_Sys::GAL) + { + int idot = (int) round(eph.idot /P2_43/SC2RAD); + int tocs = (int) round(eph.tocs /60.0 ); + int f2 = (int) round(eph.f2 /P2_59); + int f1 = (int) round(eph.f1 /P2_46); + int f0 = (int) round(eph.f0 /P2_34); + int crs = (int) round(eph.crs /P2_5 ); + int deln = (int) round(eph.deln /P2_43/SC2RAD); + int M0 = (int) round(eph.M0 /P2_31/SC2RAD); + int cuc = (int) round(eph.cuc /P2_29); + unsigned int e = (unsigned int)round(eph.e /P2_33); + int cus = (int) round(eph.cus /P2_29); + unsigned int sqrtA = (unsigned int)round(eph.sqrtA /P2_19); + int toes = (int) round(eph.toes /60.0 ); + int cic = (int) round(eph.cic /P2_29); + int OMG0 = (int) round(eph.OMG0 /P2_31/SC2RAD); + int cis = (int) round(eph.cis /P2_29); + int i0 = (int) round(eph.i0 /P2_31/SC2RAD); + int crc = (int) round(eph.crc /P2_5 ); + int omg = (int) round(eph.omg /P2_31/SC2RAD); + int OMGd = (int) round(eph.OMGd /P2_43/SC2RAD); + int bgd1 = (int) round(eph.tgd[0]/P2_32); + int bgd2 = (int) round(eph.tgd[1]/P2_32); - i = setbituInc(buf, i, 5, rtcm_code); - int d = (int)round(entry.bias / 0.01); i = setbitsInc(buf, i, 14, d); + i = setbituInc(buf, i, 6, Sat.prn); + i = setbituInc(buf, i, 12, eph.weekRollOver); + i = setbituInc(buf, i, 10, eph.iode); + i = setbituInc(buf, i, 8, eph.sva); + i = setbitsInc(buf, i, 14, idot); + i = setbituInc(buf, i, 14, tocs); + i = setbitsInc(buf, i, 6, f2); + i = setbitsInc(buf, i, 21, f1); + i = setbitsInc(buf, i, 31, f0); + i = setbitsInc(buf, i, 16, crs); + i = setbitsInc(buf, i, 16, deln); + i = setbitsInc(buf, i, 32, M0); + i = setbitsInc(buf, i, 16, cuc); + i = setbituInc(buf, i, 32, e); + i = setbitsInc(buf, i, 16, cus); + i = setbituInc(buf, i, 32, sqrtA); + i = setbituInc(buf, i, 14, toes); + i = setbitsInc(buf, i, 16, cic); + i = setbitsInc(buf, i, 32, OMG0); + i = setbitsInc(buf, i, 16, cis); + i = setbitsInc(buf, i, 32, i0); + i = setbitsInc(buf, i, 16, crc); + i = setbitsInc(buf, i, 32, omg); + i = setbitsInc(buf, i, 24, OMGd); + i = setbitsInc(buf, i, 10, bgd1); - traceSsrCodeB(sat, obsCode, ssrCodeBias); + if (type == +E_NavMsgType::FNAV) + { + i = setbituInc(buf, i, 2, eph.e5a_hs); + i = setbituInc(buf, i, 1, eph.e5a_dvs); + i = setbituInc(buf, i, 7, 0); /* reserved */ + } + else if (type == +E_NavMsgType::INAV) + { + i = setbitsInc(buf, i, 10, bgd2); + i = setbituInc(buf, i, 2, eph.e5b_hs); + i = setbituInc(buf, i, 1, eph.e5b_dvs); + i = setbituInc(buf, i, 2, eph.e1_hs); + i = setbituInc(buf, i, 1, eph.e1_dvs); } } - int bitl = byteLen*8-i; + int bitl = byteLen * 8 - i; if (bitl > 7) { - BOOST_LOG_TRIVIAL(error) << "Error encoding SSR Code.\n"; + BOOST_LOG_TRIVIAL(error) << "Error encoding ephmeris.\n"; BOOST_LOG_TRIVIAL(error) << "Error: bitl : " << bitl << ", i : " << i << ", byteLen : " << byteLen << std::endl; } - - i = setbituInc(buf,i,bitl,0); + i = setbituInc(buf, i, bitl, 0); + + if (acsConfig.output_encoded_rtcm_json) + traceBrdcEph(messCode, eph); + + return buffer; +} + +/** encode GLO ephemeris messages +*/ +vector RtcmEncoder::encodeEphemeris( + Geph& geph, ///< ephemeris to encode + RtcmMessageType messCode) ///< RTCM message code to encode ephemeris of +{ + int bitLen = 360; + + int byteLen = ceil(bitLen / 8.0); + vector buffer(byteLen); + unsigned char* buf = buffer.data(); + + int i = 0; + i = setbituInc(buf, i, 12, messCode); + + auto Sat = geph.Sat; + { + int vel[3], pos[3], acc[3]; + for (int j=0; j<3; j++) + { + vel[j] = (int)round(geph.vel[j]/P2_20/1E3); + pos[j] = (int)round(geph.pos[j]/P2_11/1E3); + acc[j] = (int)round(geph.acc[j]/P2_30/1E3); + } + + int gammaN = (int)round(geph.gammaN / P2_40); + int taun = (int)round(geph.taun / P2_30); + int dtaun = (int)round(geph.dtaun / P2_30); + + i = setbituInc(buf, i, 6, Sat.prn); + i = setbituInc(buf, i, 5, geph.frq+7); + i = setbituInc(buf, i, 4, 0); // almanac health, P1 + i = setbituInc(buf, i, 5, geph.tk_hour); + i = setbituInc(buf, i, 6, geph.tk_min); + i = setbituInc(buf, i, 1, geph.tk_sec); + i = setbituInc(buf, i, 1, geph.svh); + i = setbituInc(buf, i, 1, 0); // P2 + i = setbituInc(buf, i, 7, geph.tb); + i = setbitgInc(buf, i, 24, vel[0]); + i = setbitgInc(buf, i, 27, pos[0]); + i = setbitgInc(buf, i, 5, acc[0]); + i = setbitgInc(buf, i, 24, vel[1]); + i = setbitgInc(buf, i, 27, pos[1]); + i = setbitgInc(buf, i, 5, acc[1]); + i = setbitgInc(buf, i, 24, vel[2]); + i = setbitgInc(buf, i, 27, pos[2]); + i = setbitgInc(buf, i, 5, acc[2]); + i = setbituInc(buf, i, 1, 0); // P3 + i = setbitgInc(buf, i, 11, gammaN); + i = setbituInc(buf, i, 3, 0); // P, ln + i = setbitgInc(buf, i, 22, taun); + i = setbitgInc(buf, i, 5, dtaun); + i = setbituInc(buf, i, 5, geph.age); + i = setbituInc(buf, i, 5, 0); // P4, FT + i = setbituInc(buf, i, 11, geph.NT); // GLONASS-M only + i = setbituInc(buf, i, 2, geph.glonassM); // M (if GLONASS-M data feilds valid) + i = setbituInc(buf, i, 1, geph.moreData); // availability of additional data + i = setbituInc(buf, i, 11, 0); // NA + i = setbitgInc(buf, i, 32, 0); // tauc + i = setbituInc(buf, i, 5, geph.N4); // additional data and GLONASS-M only + i = setbitgInc(buf, i, 22, 0); // tauGPS + i = setbituInc(buf, i, 1, 0); // ln + i = setbituInc(buf, i, 7, 0); // reserved + } + + int bitl = byteLen * 8 - i; + if (bitl > 7) + { + BOOST_LOG_TRIVIAL(error) << "Error encoding ephmeris.\n"; + BOOST_LOG_TRIVIAL(error) << "Error: bitl : " << bitl << ", i : " << i << ", byteLen : " << byteLen << std::endl; + } + i = setbituInc(buf, i, bitl, 0); + + if (acsConfig.output_encoded_rtcm_json) + traceBrdcEph(messCode, geph); return buffer; } + + +/** set unsigned bits to byte data +*/ +void setbitu( + unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + unsigned int value) ///< value to set +{ + unsigned int mask=1u<<(len-1); + + if ( len <= 0 + ||len > 32) + { + return; + } + + unsigned long int invalid = (1ul<= invalid) + { + std::cout << "Warning: " << __FUNCTION__ << " has data outside range\n"; + } + + for (int i = pos; i < pos+len; i++, mask >>= 1) + { + if (value&mask) buff[i/8] |= (1u<<(7-i%8)); + else buff[i/8] &= ~(1u<<(7-i%8)); + } +} + +/** set signed bits to byte data +*/ +void setbits( + unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + int value) ///< value to set +{ + unsigned int mask = 1u<<(len-1); + + if ( len <= 0 + ||len > 32) + { + return; + } + + long int invalid = (1ul<<(len-1)); + + if ( +value >= invalid + ||-value >= invalid) + { + std::cout << "Warning: " << __FUNCTION__ << " has data outside range, setting invalid\n"; + value = -invalid; + } + + for (int i = pos; i < pos+len; i++, mask >>= 1) + { + if (value&mask) buff[i/8] |= (1u<<(7-i%8)); + else buff[i/8] &= ~(1u<<(7-i%8)); + } +} + +/** increasingly set unsigned bits to byte data +*/ +int setbituInc( + unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + unsigned int value) ///< value to set +{ + setbitu(buff, pos, len, value); + return pos + len; +} + +/** increasingly set signed bits to byte data +*/ +int setbitsInc( + unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + int value) ///< value to set +{ + setbits(buff, pos, len, value); + return pos + len; +} + +/** set sign-magnitude bits applied in GLO nav messages +*/ +void setbitg( + unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + int value) ///< value to set +{ + setbitu(buff, pos, 1, value<0?1:0); + setbitu(buff, pos+1, len-1, value<0?-value:value); +} + +/** increasingly set sign-magnitude bits applied in GLO nav messages +*/ +int setbitgInc( + unsigned char* buff, ///< byte data + int pos, ///< bit position from start of data (bits) + int len, ///< bit length (bits) (len<=32) + int value) ///< value to set +{ + setbitg(buff, pos, len, value); + return pos + len; +} diff --git a/src/cpp/common/rtcmEncoder.hpp b/src/cpp/common/rtcmEncoder.hpp index c74708d72..b61b89aa5 100644 --- a/src/cpp/common/rtcmEncoder.hpp +++ b/src/cpp/common/rtcmEncoder.hpp @@ -1,9 +1,9 @@ -#ifndef RTCMENCODER_H -#define RTCMENCODER_H + +#pragma once #include "observations.hpp" #include "navigation.hpp" -#include "ntripTrace.hpp" +#include "rtcmTrace.hpp" #include "common.hpp" #include "satSys.hpp" #include "enums.h" @@ -11,26 +11,28 @@ using std::pair; -typedef map> SsrCombMap; -typedef map SsrPBMap; -typedef map SsrCBMap; -typedef map SsrClkOutMap; -typedef map SsrClkMap; typedef map SsrEphMap; +typedef map SsrClkMap; +typedef map SsrUraMap; +typedef map SsrHRClkMap; +typedef map SsrCBMap; +typedef map SsrPBMap; +typedef map SsrOutMap; void calculateSsrComb( - GTime curTime, - int udi, - SSRMeta ssrMeta, - int masterIod, - map& ssrOutMap); + GTime referenceTime, + int udi, + SSRMeta ssrMeta, + int masterIod, + SsrOutMap& ssrOutMap); struct RtcmEncoder : RtcmTrace { RtcmEncoder( string rtcmMountpoint = "", - string rtcmTraceFilename = "") : RtcmTrace{rtcmMountpoint, rtcmTraceFilename} + string rtcmTraceFilename = "") + : RtcmTrace {rtcmMountpoint, rtcmTraceFilename} { } @@ -41,7 +43,12 @@ struct RtcmEncoder : RtcmTrace }; vector data; + + int masterIod = 1; + SsrEphMap lastRegSsrEphMap; ///< last SSR orbit corrections uploaded, used to check IODE's + SsrClkMap lastRegSsrClkMap; ///< last regular SSR clock corrections uploaded, used to calculate high rate SSR clock corrections + static int getUdiIndex( int udi); @@ -51,16 +58,42 @@ struct RtcmEncoder : RtcmTrace bool encodeWriteMessageToBuffer( vector& buffer); - vector encodeSsrComb( - map& ssrCombMap); + vector encodeTimeStampRTCM(); - vector encodeSsrPhase( - SsrPBMap& ssrPBMap); + int encodeSsrHeader( + unsigned char* buf, + E_Sys sys, + RtcmMessageType messCode, + SSRMeta& ssrMeta, + int iod, + int dispBiasConistInd = -1, + int MWConistInd = -1); + + vector encodeSsrOrbClk( + SsrOutMap& ssrOutMap, + RtcmMessageType messCode); + + vector encodeSsrUra( + SsrOutMap& ssrOutMap, + RtcmMessageType messCode); vector encodeSsrCode( - SsrCBMap& ssrCBMap); + SsrCBMap& ssrCBMap, + RtcmMessageType messCode); - vector encodeTimeStampRTCM(); + vector encodeSsrPhase( + SsrPBMap& ssrPBMap, + RtcmMessageType messCode); + + vector encodeEphemeris( + Eph& eph, + RtcmMessageType messCode); + + vector encodeEphemeris( + Geph& geph, + RtcmMessageType messCode); }; -#endif +int setbitsInc(unsigned char *buff, int pos, int len, const int value); +int setbituInc(unsigned char *buff, int pos, int len, const unsigned int value); +int setbitgInc(unsigned char *buff, int pos, int len, const int value); diff --git a/src/cpp/common/rtcmTrace.cpp b/src/cpp/common/rtcmTrace.cpp new file mode 100644 index 000000000..371dc9c49 --- /dev/null +++ b/src/cpp/common/rtcmTrace.cpp @@ -0,0 +1,722 @@ + +// #pragma GCC optimize ("O0") + +#include + +#include "rtcmTrace.hpp" +#include "ephemeris.hpp" +#include "common.hpp" +#include "ssr.hpp" + +using bsoncxx::builder::basic::kvp; + +map rtcmMessageSystemMap = +{ + {RtcmMessageType::GPS_EPHEMERIS , E_Sys::GPS}, + {RtcmMessageType::GLO_EPHEMERIS , E_Sys::GLO}, + {RtcmMessageType::BDS_EPHEMERIS , E_Sys::BDS}, + {RtcmMessageType::QZS_EPHEMERIS , E_Sys::QZS}, + {RtcmMessageType::GAL_FNAV_EPHEMERIS , E_Sys::GAL}, + {RtcmMessageType::GAL_INAV_EPHEMERIS , E_Sys::GAL}, + {RtcmMessageType::GPS_SSR_ORB_CORR , E_Sys::GPS}, + {RtcmMessageType::GPS_SSR_CLK_CORR , E_Sys::GPS}, + {RtcmMessageType::GPS_SSR_CODE_BIAS , E_Sys::GPS}, + {RtcmMessageType::GPS_SSR_COMB_CORR , E_Sys::GPS}, + {RtcmMessageType::GPS_SSR_URA , E_Sys::GPS}, + {RtcmMessageType::GPS_SSR_HR_CLK_CORR , E_Sys::GPS}, + {RtcmMessageType::GLO_SSR_ORB_CORR , E_Sys::GLO}, + {RtcmMessageType::GLO_SSR_CLK_CORR , E_Sys::GLO}, + {RtcmMessageType::GLO_SSR_CODE_BIAS , E_Sys::GLO}, + {RtcmMessageType::GLO_SSR_COMB_CORR , E_Sys::GLO}, + {RtcmMessageType::GLO_SSR_URA , E_Sys::GLO}, + {RtcmMessageType::GLO_SSR_HR_CLK_CORR , E_Sys::GLO}, + {RtcmMessageType::MSM4_GPS , E_Sys::GPS}, + {RtcmMessageType::MSM5_GPS , E_Sys::GPS}, + {RtcmMessageType::MSM6_GPS , E_Sys::GPS}, + {RtcmMessageType::MSM7_GPS , E_Sys::GPS}, + {RtcmMessageType::MSM4_GLONASS , E_Sys::GLO}, + {RtcmMessageType::MSM5_GLONASS , E_Sys::GLO}, + {RtcmMessageType::MSM6_GLONASS , E_Sys::GLO}, + {RtcmMessageType::MSM7_GLONASS , E_Sys::GLO}, + {RtcmMessageType::MSM4_GALILEO , E_Sys::GAL}, + {RtcmMessageType::MSM5_GALILEO , E_Sys::GAL}, + {RtcmMessageType::MSM6_GALILEO , E_Sys::GAL}, + {RtcmMessageType::MSM7_GALILEO , E_Sys::GAL}, + {RtcmMessageType::MSM4_QZSS , E_Sys::QZS}, + {RtcmMessageType::MSM5_QZSS , E_Sys::QZS}, + {RtcmMessageType::MSM6_QZSS , E_Sys::QZS}, + {RtcmMessageType::MSM7_QZSS , E_Sys::QZS}, + {RtcmMessageType::MSM4_BEIDOU , E_Sys::BDS}, + {RtcmMessageType::MSM5_BEIDOU , E_Sys::BDS}, + {RtcmMessageType::MSM6_BEIDOU , E_Sys::BDS}, + {RtcmMessageType::MSM7_BEIDOU , E_Sys::BDS}, + {RtcmMessageType::GAL_SSR_ORB_CORR , E_Sys::GAL}, + {RtcmMessageType::GAL_SSR_CLK_CORR , E_Sys::GAL}, + {RtcmMessageType::GAL_SSR_CODE_BIAS , E_Sys::GAL}, + {RtcmMessageType::GAL_SSR_COMB_CORR , E_Sys::GAL}, + {RtcmMessageType::GAL_SSR_URA , E_Sys::GAL}, + {RtcmMessageType::GAL_SSR_HR_CLK_CORR , E_Sys::GAL}, + {RtcmMessageType::QZS_SSR_ORB_CORR , E_Sys::QZS}, + {RtcmMessageType::QZS_SSR_CLK_CORR , E_Sys::QZS}, + {RtcmMessageType::QZS_SSR_CODE_BIAS , E_Sys::QZS}, + {RtcmMessageType::QZS_SSR_COMB_CORR , E_Sys::QZS}, + {RtcmMessageType::QZS_SSR_URA , E_Sys::QZS}, + {RtcmMessageType::QZS_SSR_HR_CLK_CORR , E_Sys::QZS}, + {RtcmMessageType::SBS_SSR_ORB_CORR , E_Sys::SBS}, + {RtcmMessageType::SBS_SSR_CLK_CORR , E_Sys::SBS}, + {RtcmMessageType::SBS_SSR_CODE_BIAS , E_Sys::SBS}, + {RtcmMessageType::SBS_SSR_COMB_CORR , E_Sys::SBS}, + {RtcmMessageType::SBS_SSR_URA , E_Sys::SBS}, + {RtcmMessageType::SBS_SSR_HR_CLK_CORR , E_Sys::SBS}, + {RtcmMessageType::BDS_SSR_ORB_CORR , E_Sys::BDS}, + {RtcmMessageType::BDS_SSR_CLK_CORR , E_Sys::BDS}, + {RtcmMessageType::BDS_SSR_CODE_BIAS , E_Sys::BDS}, + {RtcmMessageType::BDS_SSR_COMB_CORR , E_Sys::BDS}, + {RtcmMessageType::BDS_SSR_URA , E_Sys::BDS}, + {RtcmMessageType::BDS_SSR_HR_CLK_CORR , E_Sys::BDS}, + {RtcmMessageType::GPS_SSR_PHASE_BIAS , E_Sys::GPS}, + {RtcmMessageType::GLO_SSR_PHASE_BIAS , E_Sys::GLO}, + {RtcmMessageType::GAL_SSR_PHASE_BIAS , E_Sys::GAL}, + {RtcmMessageType::QZS_SSR_PHASE_BIAS , E_Sys::QZS}, + {RtcmMessageType::SBS_SSR_PHASE_BIAS , E_Sys::SBS}, + {RtcmMessageType::BDS_SSR_PHASE_BIAS , E_Sys::BDS}, + {RtcmMessageType::COMPACT_SSR , E_Sys::SUPPORTED}, + {RtcmMessageType::IGS_SSR , E_Sys::SUPPORTED} +}; + + +void RtcmTrace::traceSsrEph( + RtcmMessageType messCode, + SatSys Sat, + SSREph& ssrEph) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + GTime nearTime = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "ssrEph")); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("EpochTimeGPST", ssrEph.ssrMeta.receivedTime.to_string(1) )); + doc.append(kvp("ReferenceTimeGPST", ssrEph.t0.to_string(1) )); + doc.append(kvp("EpochTime1s", ssrEph.ssrMeta.epochTime1s )); + doc.append(kvp("SSRUpdateIntervalSec", ssrEph.udi )); + doc.append(kvp("SSRUpdateIntervalIndex", ssrEph.ssrMeta.updateIntIndex )); + doc.append(kvp("MultipleMessageIndicator", ssrEph.ssrMeta.multipleMessage )); + doc.append(kvp("SatReferenceDatum", (int)ssrEph.ssrMeta.referenceDatum )); // 0 = ITRF, 1 = Regional // bsoncxx doesn't like uints + doc.append(kvp("IODSSR", ssrEph.iod )); + doc.append(kvp("SSRProviderID", (int)ssrEph.ssrMeta.provider )); + doc.append(kvp("SSRSolutionID", (int)ssrEph.ssrMeta.solution )); + doc.append(kvp("Sat", Sat.id() )); + doc.append(kvp("IODE", ssrEph.iode )); + doc.append(kvp("IODCRC", ssrEph.iodcrc )); + doc.append(kvp("DeltaRadial", ssrEph.deph[0] )); + doc.append(kvp("DeltaAlongTrack", ssrEph.deph[1] )); + doc.append(kvp("DeltaCrossTrack", ssrEph.deph[2] )); + doc.append(kvp("DotDeltaRadial", ssrEph.ddeph[0] )); + doc.append(kvp("DotDeltaAlongTrack", ssrEph.ddeph[1] )); + doc.append(kvp("DotDeltaCrossTrack", ssrEph.ddeph[2] )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +void RtcmTrace::traceSsrClk( + RtcmMessageType messCode, + SatSys Sat, + SSRClk& ssrClk) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + GTime nearTime = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "ssrClk")); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("EpochTimeGPST", ssrClk.ssrMeta.receivedTime.to_string(1) )); + doc.append(kvp("ReferenceTimeGPST", ssrClk.t0.to_string(1) )); + doc.append(kvp("EpochTime1s", ssrClk.ssrMeta.epochTime1s )); + doc.append(kvp("SSRUpdateIntervalSec", ssrClk.udi )); + doc.append(kvp("SSRUpdateIntervalIndex", ssrClk.ssrMeta.updateIntIndex )); + doc.append(kvp("MultipleMessageIndicator", ssrClk.ssrMeta.multipleMessage )); + doc.append(kvp("SatReferenceDatum", (int)ssrClk.ssrMeta.referenceDatum )); // 0 = ITRF, 1 = Regional // could be combined corrections + doc.append(kvp("IODSSR", ssrClk.iod )); + doc.append(kvp("SSRProviderID", (int)ssrClk.ssrMeta.provider )); + doc.append(kvp("SSRSolutionID", (int)ssrClk.ssrMeta.solution )); + doc.append(kvp("Sat", Sat.id() )); + doc.append(kvp("DeltaClockC0", ssrClk.dclk[0] )); + doc.append(kvp("DeltaClockC1", ssrClk.dclk[1] )); + doc.append(kvp("DeltaClockC2", ssrClk.dclk[2] )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +void RtcmTrace::traceSsrUra( + RtcmMessageType messCode, + SatSys Sat, + SSRUra& ssrUra) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + GTime nearTime = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "ssrURA")); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("EpochTimeGPST", ssrUra.ssrMeta.receivedTime.to_string(1) )); + doc.append(kvp("ReferenceTimeGPST", ssrUra.t0.to_string(1) )); + doc.append(kvp("EpochTime1s", ssrUra.ssrMeta.epochTime1s )); + doc.append(kvp("SSRUpdateIntervalSec", ssrUra.udi )); + doc.append(kvp("SSRUpdateIntervalIndex", ssrUra.ssrMeta.updateIntIndex )); + doc.append(kvp("MultipleMessageIndicator", ssrUra.ssrMeta.multipleMessage )); + doc.append(kvp("IODSSR", ssrUra.iod )); + doc.append(kvp("SSRProviderID", (int)ssrUra.ssrMeta.provider )); + doc.append(kvp("SSRSolutionID", (int)ssrUra.ssrMeta.solution )); + doc.append(kvp("Sat", Sat.id() )); + doc.append(kvp("SSRURA", ssrUra.ura )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +void RtcmTrace::traceSsrHRClk( + RtcmMessageType messCode, + SatSys Sat, + SSRHRClk& SsrHRClk) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + GTime nearTime = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "ssrHRClk")); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("EpochTimeGPST", SsrHRClk.ssrMeta.receivedTime.to_string(1) )); + doc.append(kvp("ReferenceTimeGPST", SsrHRClk.t0.to_string(1) )); + doc.append(kvp("EpochTime1s", SsrHRClk.ssrMeta.epochTime1s )); + doc.append(kvp("SSRUpdateIntervalSec", SsrHRClk.udi )); + doc.append(kvp("SSRUpdateIntervalIndex", SsrHRClk.ssrMeta.updateIntIndex )); + doc.append(kvp("MultipleMessageIndicator", SsrHRClk.ssrMeta.multipleMessage )); + doc.append(kvp("IODSSR", SsrHRClk.iod )); + doc.append(kvp("SSRProviderID", (int)SsrHRClk.ssrMeta.provider )); + doc.append(kvp("SSRSolutionID", (int)SsrHRClk.ssrMeta.solution )); + doc.append(kvp("Sat", Sat.id() )); + doc.append(kvp("HighRateClockCorr", SsrHRClk.hrclk )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +void RtcmTrace::traceSsrCodeBias( + RtcmMessageType messCode, + SatSys Sat, + E_ObsCode code, + SSRCodeBias& ssrBias) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + GTime nearTime = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "ssrCodeBias")); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("EpochTimeGPST", ssrBias.ssrMeta.receivedTime.to_string(1) )); + doc.append(kvp("ReferenceTimeGPST", ssrBias.t0.to_string(1) )); + doc.append(kvp("EpochTime1s", ssrBias.ssrMeta.epochTime1s )); + doc.append(kvp("SSRUpdateIntervalSec", ssrBias.udi )); + doc.append(kvp("SSRUpdateIntervalIndex", ssrBias.ssrMeta.updateIntIndex )); + doc.append(kvp("MultipleMessageIndicator", ssrBias.ssrMeta.multipleMessage )); + doc.append(kvp("IODSSR", ssrBias.iod )); + doc.append(kvp("SSRProviderID", (int)ssrBias.ssrMeta.provider )); + doc.append(kvp("SSRSolutionID", (int)ssrBias.ssrMeta.solution )); + doc.append(kvp("Sat", Sat.id() )); + doc.append(kvp("Code", code._to_string() )); + doc.append(kvp("Bias", ssrBias.obsCodeBiasMap[code].bias )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +void RtcmTrace::traceSsrPhasBias( + RtcmMessageType messCode, + SatSys Sat, + E_ObsCode code, + SSRPhasBias& ssrBias) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + GTime nearTime = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "ssrPhasBias")); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("EpochTimeGPST", ssrBias.ssrMeta.receivedTime.to_string(1) )); + doc.append(kvp("ReferenceTimeGPST", ssrBias.t0.to_string(1) )); + doc.append(kvp("EpochTime1s", ssrBias.ssrMeta.epochTime1s )); + doc.append(kvp("SSRUpdateIntervalSec", ssrBias.udi )); + doc.append(kvp("SSRUpdateIntervalIndex", ssrBias.ssrMeta.updateIntIndex )); + doc.append(kvp("MultipleMessageIndicator", ssrBias.ssrMeta.multipleMessage )); + doc.append(kvp("IODSSR", ssrBias.iod )); + doc.append(kvp("SSRProviderID", (int)ssrBias.ssrMeta.provider )); + doc.append(kvp("SSRSolutionID", (int)ssrBias.ssrMeta.solution )); + doc.append(kvp("DisperBiasConsisIndicator", ssrBias.ssrPhase.dispBiasConistInd )); + doc.append(kvp("MWConsistencyIndicator", ssrBias.ssrPhase.MWConistInd )); + doc.append(kvp("Sat", Sat.id() )); + doc.append(kvp("YawAngle", ssrBias.ssrPhase.yawAngle )); + doc.append(kvp("YawRate", ssrBias.ssrPhase.yawRate )); + doc.append(kvp("Code", code._to_string() )); + doc.append(kvp("SignalIntegerIndicator", (int)ssrBias.ssrPhaseChs[code].signalIntInd )); + doc.append(kvp("SignalsWLIntegerIndicator", (int)ssrBias.ssrPhaseChs[code].signalWLIntInd )); + doc.append(kvp("SignalDiscontinuityCount", (int)ssrBias.ssrPhaseChs[code].signalDisconCnt )); + doc.append(kvp("Bias", ssrBias.obsCodeBiasMap[code].bias )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +void RtcmTrace::traceTimestamp( + GTime time) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "timestamp" )); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("time", (string)time )); + doc.append(kvp("ticks", (double)time.bigTime )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +/** Write decoded/encoded GPS/GAL/BDS/QZS ephemeris messages to a json file +*/ +void RtcmTrace::traceBrdcEph( //todo aaron, template this for gps/glo? + RtcmMessageType messCode, + Eph& eph) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + bsoncxx::builder::basic::document doc = {}; + + GTime nearTime = timeGet(); + + // Note the Satellite id is not set in rinex correctly as we a mixing GNSS systems. + doc.append(kvp("type", "brdcEph" )); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("Sat", eph.Sat.id() )); + doc.append(kvp("Type", eph.type._to_string() )); + + doc.append(kvp("ToeGPST", eph.toe.to_string(1) )); + doc.append(kvp("TocGPST", eph.toc.to_string(1) )); + + traceBrdcEphBody(doc, eph); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +/** Write decoded/encoded GAL ephemeris messages to a json file +*/ +void RtcmTrace::traceBrdcEph( + RtcmMessageType messCode, + Geph& geph) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + bsoncxx::builder::basic::document doc = {}; + + GTime nearTime = timeGet(); + + // Note the Satellite id is not set in rinex correctly as we a mixing GNSS systems. + doc.append(kvp("type", "brdcEph" )); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("Sat", geph.Sat.id() )); + doc.append(kvp("Type", geph.type._to_string() )); + + doc.append(kvp("ToeGPST", geph.toe.to_string(1) )); + doc.append(kvp("TofGPST", geph.tof.to_string(1) )); + + traceBrdcEphBody(doc, geph); + + fout << bsoncxx::to_json(doc) << std::endl; +} + +void traceBrdcEphBody( + bsoncxx::builder::basic::document& doc, + Eph& eph) +{ + doc.append(kvp("WeekDecoded", eph.weekRollOver )); + doc.append(kvp("WeekAdjusted", eph.week )); + doc.append(kvp("ToeSecOfWeek", eph.toes )); + doc.append(kvp("TocSecOfWeek", eph.tocs )); + + doc.append(kvp("AODE", eph.aode )); + doc.append(kvp("AODC", eph.aodc )); + doc.append(kvp("IODE", eph.iode )); + doc.append(kvp("IODC", eph.iodc )); + + doc.append(kvp("f0", eph.f0 )); + doc.append(kvp("f1", eph.f1 )); + doc.append(kvp("f2", eph.f2 )); + + doc.append(kvp("SqrtA", eph.sqrtA )); + doc.append(kvp("A", eph.A )); + doc.append(kvp("e", eph.e )); + doc.append(kvp("i0", eph.i0 )); + doc.append(kvp("iDot", eph.idot )); + doc.append(kvp("omg", eph.omg )); + doc.append(kvp("OMG0", eph.OMG0 )); + doc.append(kvp("OMGDot", eph.OMGd )); + doc.append(kvp("M0", eph.M0 )); + doc.append(kvp("DeltaN", eph.deln )); + doc.append(kvp("Crc", eph.crc )); + doc.append(kvp("Crs", eph.crs )); + doc.append(kvp("Cic", eph.cic )); + doc.append(kvp("Cis", eph.cis )); + doc.append(kvp("Cuc", eph.cuc )); + doc.append(kvp("Cus", eph.cus )); + + doc.append(kvp("TGD0", eph.tgd[0] )); + doc.append(kvp("TGD1", eph.tgd[1] )); // GPS/QZS no tgd[1] + doc.append(kvp("URAIndex", eph.sva )); + + if ( eph.Sat.sys == +E_Sys::GPS + ||eph.Sat.sys == +E_Sys::QZS) + { + doc.append(kvp("URA", eph.ura[0] )); + doc.append(kvp("SVHealth", eph.svh )); + doc.append(kvp("CodeOnL2", eph.code )); + doc.append(kvp("L2PDataFlag", eph.flag )); // QZS no flag + doc.append(kvp("FitFlag", eph.fitFlag )); + doc.append(kvp("FitInterval", eph.fit )); + } + else if (eph.Sat.sys == +E_Sys::GAL) + { + doc.append(kvp("SISA", eph.ura[0] )); + doc.append(kvp("SVHealth", eph.svh )); + doc.append(kvp("E5aHealth", eph.e5a_hs )); + doc.append(kvp("E5aDataValidity", eph.e5a_dvs )); + doc.append(kvp("E5bHealth", eph.e5b_hs )); + doc.append(kvp("E5bDataValidity", eph.e5b_dvs )); + doc.append(kvp("E1Health", eph.e1_hs )); + doc.append(kvp("E1DataValidity", eph.e1_dvs )); + doc.append(kvp("DataSource", eph.code )); + } + else if (eph.Sat.sys == +E_Sys::BDS) + { + doc.append(kvp("URA", eph.ura[0] )); + doc.append(kvp("SVHealth", eph.svh )); + } +} + +void traceBrdcEphBody( + bsoncxx::builder::basic::document& doc, + Geph& geph) +{ + doc.append(kvp("ToeSecOfDay", geph.tb )); + doc.append(kvp("TofHour", geph.tk_hour )); + doc.append(kvp("TofMin", geph.tk_min )); + doc.append(kvp("TofSec", geph.tk_sec )); + + doc.append(kvp("IODE", geph.iode )); + + doc.append(kvp("TauN", geph.taun )); + doc.append(kvp("GammaN", geph.gammaN )); + doc.append(kvp("DeltaTauN", geph.dtaun )); + + doc.append(kvp("PosX", geph.pos[0] )); + doc.append(kvp("PosY", geph.pos[1] )); + doc.append(kvp("PosZ", geph.pos[2] )); + doc.append(kvp("VelX", geph.vel[0] )); + doc.append(kvp("VelY", geph.vel[1] )); + doc.append(kvp("VelZ", geph.vel[2] )); + doc.append(kvp("AccX", geph.acc[0] )); + doc.append(kvp("AccY", geph.acc[1] )); + doc.append(kvp("AccZ", geph.acc[2] )); + + doc.append(kvp("FrquencyNumber", geph.frq )); + doc.append(kvp("SVHealth", geph.svh )); + doc.append(kvp("Age", geph.age )); + + doc.append(kvp("GLONASSM", geph.glonassM )); + doc.append(kvp("NumberOfDayIn4Year", geph.NT )); + doc.append(kvp("AdditionalData", geph.moreData )); + doc.append(kvp("4YearIntervalNumber", geph.N4 )); +} + +/** Writes nav.satNavMap[].ssrOut to a human-readable file +*/ +void writeSsrOutToFile( + int epochNum, + map& ssrOutMap) +{ + string filename = "ssrOut.dbg"; + std::ofstream out(filename, std::ios::app); + + if (!out) + { + BOOST_LOG_TRIVIAL(error) + << "Error: Could not open trace file for SSR messages at " << filename; + return; + } + out.precision(17); + + // Header + out << "epochNum" << "\t"; + out << "satId" << "\t"; + +// out << "SSREph.canExport" << "\t"; + out << "SSREph.t0" << "\t"; + out << "SSREph.udi" << "\t"; + out << "SSREph.iod" << "\t"; + out << "SSREph.iode" << "\t"; + out << "SSREph.deph[0]" << "\t"; + out << "SSREph.deph[1]" << "\t"; + out << "SSREph.deph[2]" << "\t"; + out << "SSREph.ddeph[0]" << "\t"; + out << "SSREph.ddeph[1]" << "\t"; + out << "SSREph.ddeph[2]" << "\t"; + +// out << "SSRClk.canExport" << "\t"; + out << "SSRClk.t0" << "\t"; + out << "SSRClk.udi" << "\t"; + out << "SSRClk.iod" << "\t"; + out << "SSRClk.dclk[0]" << "\t"; + out << "SSRClk.dclk[1]" << "\t"; + out << "SSRClk.dclk[2]" << "\t"; + + out << "SSRBias.t0_code" << "\t"; + out << "SSRBias.t0_phas" << "\t"; + out << "SSRBias.udi_code" << "\t"; + out << "SSRBias.udi_phas" << "\t"; + out << "SSRBias.iod_code" << "\t"; + out << "SSRBias.iod_phas" << "\t"; + for (int i=0; i<2; ++i) out << "ssrBias.cbias_"<< i << "\t"; + for (int i=0; i<2; ++i) out << "ssrBias.cvari_"<< i << "\t"; + for (int i=0; i<2; ++i) out << "ssrBias.pbias_"<< i << "\t"; + for (int i=0; i<2; ++i) out << "ssrBias.pvari_"<< i << "\t"; + for (int i=0; i<2; ++i) + { + out << "ssrBias.ssrPhaseCh.signalIntInd_" << i << "\t"; + out << "ssrBias.ssrPhaseCh.signalWLIntInd_" << i << "\t"; + out << "ssrBias.ssrPhaseCh.signalDisconCnt_" << i << "\t"; + } + out << std::endl; + + // Body + for (auto& [Sat, ssrOut] : ssrOutMap) + { + out << epochNum << "\t"; + out << Sat.id() << "\t"; +// out << ssrOut.ssrEph.canExport<< "\t"; + out << ssrOut.ssrEph.t0 << "\t"; + out << ssrOut.ssrEph.udi << "\t"; + out << ssrOut.ssrEph.iod << "\t"; + out << ssrOut.ssrEph.iode << "\t"; + out << ssrOut.ssrEph.deph[0] << "\t"; + out << ssrOut.ssrEph.deph[1] << "\t"; + out << ssrOut.ssrEph.deph[2] << "\t"; + out << ssrOut.ssrEph.ddeph[0] << "\t"; + out << ssrOut.ssrEph.ddeph[1] << "\t"; + out << ssrOut.ssrEph.ddeph[2] << "\t"; + +// out << ssrOut.ssrClk.canExport<< "\t"; + out << ssrOut.ssrClk.t0 << "\t"; + out << ssrOut.ssrClk.udi << "\t"; + out << ssrOut.ssrClk.iod << "\t"; + out << ssrOut.ssrClk.dclk[0] << "\t"; + out << ssrOut.ssrClk.dclk[1] << "\t"; + out << ssrOut.ssrClk.dclk[2] << "\t"; + + out << ssrOut.ssrCodeBias.t0 << "\t"; + out << ssrOut.ssrPhasBias.t0 << "\t"; + out << ssrOut.ssrCodeBias.udi << "\t"; + out << ssrOut.ssrPhasBias.udi << "\t"; + out << ssrOut.ssrCodeBias.iod << "\t"; + out << ssrOut.ssrPhasBias.iod << "\t"; + for (auto& [key, val] : ssrOut.ssrCodeBias.obsCodeBiasMap) out << val.bias << "\t" << val.var << "\t"; + for (auto& [key, val] : ssrOut.ssrPhasBias.obsCodeBiasMap) out << val.bias << "\t" << val.var << "\t"; + + for (auto& [key, ssrPhaseCh] : ssrOut.ssrPhasBias.ssrPhaseChs) + { + out << ssrPhaseCh.signalIntInd << "\t"; + out << ssrPhaseCh.signalWLIntInd << "\t"; + out << ssrPhaseCh.signalDisconCnt << "\t"; + } + out << std::endl; + } + out << std::endl; +} + + +/** Write msm message to a json file +*/ +void RtcmTrace::traceMSM( + RtcmMessageType messCode, + GTime time, + SatSys Sat, + Sig& sig) +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + GTime nearTime = timeGet(); + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "MSM" )); + doc.append(kvp("Mountpoint", rtcmMountpoint )); + doc.append(kvp("MessageNumber", messCode._to_integral() )); + doc.append(kvp("MessageType", messCode._to_string() )); + doc.append(kvp("ReceivedSentTimeGPST", nearTime.to_string(1) )); + doc.append(kvp("EpochTimeGPST", time.to_string(1) )); + doc.append(kvp("Sat", Sat.id() )); + doc.append(kvp("Code", sig.code._to_string() )); + doc.append(kvp("Pseudorange", sig.P )); + doc.append(kvp("CarrierPhase", sig.L )); + doc.append(kvp("Doppler", sig.D )); + doc.append(kvp("SNR", sig.snr )); + doc.append(kvp("LLI", sig.LLI )); + doc.append(kvp("IsInvalid", sig.invalid )); + + fout << bsoncxx::to_json(doc) << std::endl; +} + + +/** Write unknown message to a json file +*/ +void RtcmTrace::traceUnknown() +{ + if (rtcmTraceFilename.empty()) + { + return; + } + + std::ofstream fout(rtcmTraceFilename, std::ios::app); + if (!fout) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("type", "?" )); + + fout << bsoncxx::to_json(doc) << std::endl; +} diff --git a/src/cpp/common/rtcmTrace.hpp b/src/cpp/common/rtcmTrace.hpp new file mode 100644 index 000000000..878f5e735 --- /dev/null +++ b/src/cpp/common/rtcmTrace.hpp @@ -0,0 +1,133 @@ + +#pragma once + +#include +#include +#include +#include + +using std::string; + +#include +#include + +#include "observations.hpp" +#include "satSys.hpp" +#include "gTime.hpp" + +struct Eph; +struct Geph; +struct SSREph; +struct SSRClk; +struct SSRUra; +struct SSRHRClk; +struct SSRCodeBias; +struct SSRPhasBias; + +struct RtcmTrace +{ + string rtcmTraceFilename = ""; + string rtcmMountpoint; + + RtcmTrace( + string mountpoint = "", + string filename = "") + : rtcmTraceFilename {filename}, + rtcmMountpoint {mountpoint} + { + } + + void networkLog( + string message) + { + std::ofstream outStream(rtcmTraceFilename, std::iostream::app); + if (!outStream) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + outStream << (GTime)timeGet(); + outStream << " networkLog" << message << std::endl; + } + + void messageChunkLog( + string message) + { + } + + void messageRtcmLog( + string message) + { + std::ofstream outStream(rtcmTraceFilename, std::ios::app); + if (!outStream) + { + std::cout << "Error opening " << rtcmTraceFilename << " in " << __FUNCTION__ << std::endl; + return; + } + + outStream << (GTime)timeGet(); + outStream << " messageRtcmLog" << message << std::endl; + } + + void traceSsrEph( + RtcmMessageType messCode, + SatSys Sat, + SSREph& ssrEph); + + void traceSsrClk( + RtcmMessageType messCode, + SatSys Sat, + SSRClk& ssrClk); + + void traceSsrUra( + RtcmMessageType messCode, + SatSys Sat, + SSRUra& ssrUra); + + void traceSsrHRClk( + RtcmMessageType messCode, + SatSys Sat, + SSRHRClk& ssrHRClk); + + void traceSsrCodeBias( + RtcmMessageType messCode, + SatSys Sat, + E_ObsCode code, + SSRCodeBias& ssrBias); + + void traceSsrPhasBias( + RtcmMessageType messCode, + SatSys Sat, + E_ObsCode code, + SSRPhasBias& ssrBias); + + void traceTimestamp( + GTime time); + + void traceBrdcEph( + RtcmMessageType messCode, + Eph& eph); + + void traceBrdcEph( + RtcmMessageType messCode, + Geph& geph); + + void traceMSM( + RtcmMessageType messCode, + GTime time, + SatSys Sat, + Sig& sig); + + void traceUnknown(); +}; + +void traceBrdcEphBody( + bsoncxx::builder::basic::document& doc, + Eph& eph); + +void traceBrdcEphBody( + bsoncxx::builder::basic::document& doc, + Geph& geph); + +extern map rtcmMessageSystemMap; diff --git a/src/cpp/common/rtsSmoothing.cpp b/src/cpp/common/rtsSmoothing.cpp index a1e8fffb7..2273363d7 100644 --- a/src/cpp/common/rtsSmoothing.cpp +++ b/src/cpp/common/rtsSmoothing.cpp @@ -13,66 +13,101 @@ using std::map; #include "rinexClkWrite.hpp" #include "algebraTrace.hpp" #include "rtsSmoothing.hpp" +#include "binaryStore.hpp" #include "mongoWrite.hpp" #include "GNSSambres.hpp" #include "acsConfig.hpp" #include "testUtils.hpp" #include "constants.hpp" +#include "ionoModel.hpp" +#include "sp3Write.cpp" #include "metaData.hpp" #include "algebra.hpp" +#include "sinex.hpp" +#include "cost.hpp" #include "ppp.hpp" #include "gpx.hpp" + void postRTSActions( bool final, ///< This is a final answer, not intermediate - output to files KFState& kfState, ///< State to get filter traces from StationMap* stationMap_ptr) ///< Pointer to map of stations { - if ( final - && acsConfig.output_erp) + if ( final + ||acsConfig.pppOpts.output_intermediate_rts) + { + mongoStates(kfState, "_rts"); + } + + if ( final + ||acsConfig.pppOpts.output_intermediate_rts) + { + storeStates(kfState, "rts"); + } + + if (final == false) + { + return; + } + + { + std::ofstream ofs(kfState.metaDataMap[TRACE_FILENAME_STR + SMOOTHED_SUFFIX], std::ofstream::out | std::ofstream::app); + kfState.outputStates(ofs, "/RTS"); + } + + if (acsConfig.output_erp) { writeERPFromNetwork(kfState.metaDataMap[ERP_FILENAME_STR + SMOOTHED_SUFFIX], kfState); } - if ( final - && acsConfig.output_clocks - &&( acsConfig.clocks_receiver_source == +E_Ephemeris::KALMAN - ||acsConfig.clocks_satellite_source == +E_Ephemeris::KALMAN)) + if ( acsConfig.output_clocks + &&( acsConfig.clocks_receiver_sources.front() == +E_Source::KALMAN + ||acsConfig.clocks_satellite_sources.front() == +E_Source::KALMAN)) { auto kfState2 = kfState; //todo aaron, delete this after fixing something else, tryPrepareFilterPointers damages the state tryPrepareFilterPointers(kfState2, stationMap_ptr); - auto filenameSysMap = getSysOutputFilenames(acsConfig.clocks_filename + SMOOTHED_SUFFIX, kfState2.time); //todo aaron, this sucks - - for (auto [filename, sysMap] : filenameSysMap) - { - outputClocks(filename, acsConfig.clocks_receiver_source, acsConfig.clocks_satellite_source, kfState2.time, sysMap, kfState2, stationMap_ptr); - } + outputClocks (kfState.metaDataMap[CLK_FILENAME_STR + SMOOTHED_SUFFIX], acsConfig.clocks_receiver_sources, acsConfig.clocks_satellite_sources, kfState2.time, kfState2, stationMap_ptr); } - - if ( final - && acsConfig.output_trop_sinex - && acsConfig.trop_data_source == +E_Ephemeris::KALMAN) + + if (acsConfig.output_orbits) { - outputTropSinex(kfState.metaDataMap[TROP_FILENAME_STR + SMOOTHED_SUFFIX], kfState.time, *stationMap_ptr, "MIX", true); //todo aaron, no site specific version here + outputSp3 (kfState.metaDataMap[SP3_FILENAME_STR + SMOOTHED_SUFFIX], kfState.time, acsConfig.orbits_data_sources, &kfState); } - if (final) + if (acsConfig.output_trop_sinex) { - std::ofstream ofs(kfState.metaDataMap[TRACE_FILENAME_STR + SMOOTHED_SUFFIX], std::ofstream::out | std::ofstream::app); - kfState.outputStates(ofs, "/RTS"); + outputTropSinex (kfState.metaDataMap[TROP_FILENAME_STR + SMOOTHED_SUFFIX], kfState.time, kfState, "MIX", true); } - if ( acsConfig.output_mongo_states - &&( final - ||acsConfig.output_intermediate_rts)) + if (acsConfig.output_ionex) { - mongoStates(kfState, acsConfig.mongo_rts_suffix); + ionexFileWrite (kfState.metaDataMap[IONEX_FILENAME_STR + SMOOTHED_SUFFIX], kfState.time, kfState); } if (acsConfig.output_gpx) { - writeGPX(kfState.metaDataMap[GPX_FILENAME_STR + SMOOTHED_SUFFIX], "", kfState); + for (auto& [id, rec] : *stationMap_ptr) + { + writeGPX (kfState.metaDataMap[GPX_FILENAME_STR + id + SMOOTHED_SUFFIX], id, kfState); + } + } + + if (acsConfig.output_ppp_sol) + { + for (auto& [id, rec] : *stationMap_ptr) + { + outputPPPSolution (kfState.metaDataMap[SOL_FILENAME_STR + id + SMOOTHED_SUFFIX], rec); + } + } + + if (acsConfig.output_cost) + { + for (auto& [id, rec] : *stationMap_ptr) + { + outputCost (kfState.metaDataMap[COST_FILENAME_STR + id + SMOOTHED_SUFFIX], rec, kfState.time, kfState); + } } // pppoutstat(ofs, archiveKF, true); @@ -130,27 +165,25 @@ void RTS_Output( return; } - std::ofstream ofs(kfState.metaDataMap[TRACE_FILENAME_STR + SMOOTHED_SUFFIX], std::ofstream::out | std::ofstream::app); + string filename = kfState.metaDataMap[TRACE_FILENAME_STR + SMOOTHED_SUFFIX]; + std::ofstream ofs(filename, std::ofstream::out | std::ofstream::app); if (!ofs) { - std::cout << "BAD RTS Write to " << kfState.metaDataMap[TRACE_FILENAME_STR + SMOOTHED_SUFFIX]; + std::cout << "BAD RTS Write to " << filename; break; } if (acsConfig.output_residuals) { - outputResiduals(ofs, archiveMeas, -1, 0, archiveMeas.obsKeys.size()); - } + outputResiduals(ofs, archiveMeas, -1, "/RTS", 0, archiveMeas.obsKeys.size()); - if (acsConfig.output_mongo_measurements) - { - mongoMeasResiduals(archiveMeas.time, archiveMeas.obsKeys, archiveMeas.V, archiveMeas.VV, archiveMeas.R, acsConfig.mongo_rts_suffix); + mongoMeasResiduals(archiveMeas.time, archiveMeas, "_rts"); } break; } - case E_SerialObject::FILTER_PLUS: + case E_SerialObject::FILTER_SMOOTHED: { KFState archiveKF; bool pass = getFilterObjectFromFile(type, archiveKF, startPos, reversedStatesFilename); @@ -163,14 +196,12 @@ void RTS_Output( archiveKF.metaDataMap = metaDataMap; - archiveKF.dx = VectorXd::Zero(archiveKF.x.rows()); - if (acsConfig.ambrOpts.NLmode != +E_ARmode::OFF) { - TempDisabler td(acsConfig.output_mongo_measurements); - KFState ARRTScopy = archiveKF; - int nfix = smoothdAmbigResl(ARRTScopy); + + smoothdAmbigResl(ARRTScopy); + postRTSActions(true, ARRTScopy, stationMap_ptr); } else @@ -205,7 +236,11 @@ KFState RTS_Process( { return KFState(); } - + + if (stationMap_ptr) + for (auto& [id, rec] : *stationMap_ptr) + rec.obsList.clear(); + MatrixXd transitionMatrix; KFState kalmanMinus; @@ -224,12 +259,12 @@ KFState RTS_Process( } long int startPos = -1; - int lag = 0; //todo aaron, change lag to use times rather than iterations, iterations may be multiple per epoch + double lag = 0; while (lag != kfState.rts_lag) { E_SerialObject type = getFilterTypeFromFile(startPos, inputFile); -// std::cout << std::endl << "Found " << type._to_string(); + std::cout << "Found " << type._to_string() << std::endl; if (type == +E_SerialObject::NONE) { @@ -311,21 +346,21 @@ KFState RTS_Process( } case E_SerialObject::FILTER_PLUS: { - lag++; - - if (write) - { - BOOST_LOG_TRIVIAL(info) - << "RTS iterations: " << lag; - } - KFState kalmanPlus; bool pass = getFilterObjectFromFile(type, kalmanPlus, startPos, inputFile); if (pass == false) { return KFState(); } + + lag = (kfState.time - kalmanPlus.time).to_double(); + if (write) + { + BOOST_LOG_TRIVIAL(info) + << "RTS lag: " << lag; + } + if (smoothedPready == false) { kalmanPlus.metaDataMap = kfState.metaDataMap; @@ -335,8 +370,8 @@ KFState RTS_Process( if (write) { - spitFilterToFile(smoothedKF, E_SerialObject::FILTER_PLUS, outputFile); - spitFilterToFile(measurements, E_SerialObject::MEASUREMENT, outputFile); + spitFilterToFile(smoothedKF, E_SerialObject::FILTER_SMOOTHED, outputFile); + spitFilterToFile(measurements, E_SerialObject::MEASUREMENT, outputFile); } break; @@ -358,12 +393,94 @@ KFState RTS_Process( kalmanMinus.P(0,0) = 1; - MatrixXd Pinv = kalmanMinus.P.inverse(); - - Pinv = (Pinv + Pinv.transpose()).eval() / 2; - - MatrixXd Ck = kalmanPlus.P * F.transpose() * Pinv; + MatrixXd FP = F * kalmanPlus.P; + + auto Q = kalmanMinus.P.triangularView().transpose(); + + int fail1 = true; + int fail2 = true; + MatrixXd Ckt; + + E_Inverter inverter = acsConfig.pppOpts.rts_inverter; + + auto failInversion = [&]() + { + auto oldInverter = inverter; + inverter = E_Inverter::_from_integral(((int)inverter)+1); + + BOOST_LOG_TRIVIAL(warning) + << "Warning: Inverter type " << oldInverter._to_string() << " failed, trying " << inverter._to_string(); + }; + + while (inverter != +E_Inverter::FIRST_UNSUPPORTED + &&( fail1 + || fail2)) + switch (inverter) + { + default: + { + BOOST_LOG_TRIVIAL(warning) + << "Warning: Inverter type " << acsConfig.pppOpts.rts_inverter._to_string() << " not supported, reverting to LDLT"; + + acsConfig.pppOpts.rts_inverter = E_Inverter::LDLT; + inverter = E_Inverter::LDLT; + + continue; + } + case E_Inverter::INV: + { + Eigen::FullPivLU solver(Q); + + if (solver.isInvertible() == false) + { + fail1 = true; + + failInversion(); + + break; + } + + MatrixXd Pinv = solver.inverse(); + + Pinv = (Pinv + Pinv.transpose()).eval() / 2; + + Ckt = (kalmanPlus.P * F.transpose() * Pinv).transpose(); + + fail1 = false; + fail2 = false; + + break; + } + case E_Inverter::LLT: { Eigen::LLT solver; solver.compute(Q); fail1 = solver.info(); Ckt = solver.solve(FP); fail2 = solver.info(); if (fail1 || fail2) failInversion(); break; } + case E_Inverter::LDLT: { Eigen::LDLT solver; solver.compute(Q); fail1 = solver.info(); Ckt = solver.solve(FP); fail2 = solver.info(); if (fail1 || fail2) failInversion(); break; } + case E_Inverter::COLPIVHQR: { Eigen::ColPivHouseholderQR solver; solver.compute(Q); fail1 = solver.info(); Ckt = solver.solve(FP); fail2 = solver.info(); if (fail1 || fail2) failInversion(); break; } + case E_Inverter::BDCSVD: { Eigen::BDCSVD solver; solver.compute(Q); fail1 = solver.info(); Ckt = solver.solve(FP); fail2 = solver.info(); if (fail1 || fail2) failInversion(); break; } + case E_Inverter::JACOBISVD: { Eigen::JacobiSVD solver; solver.compute(Q); fail1 = solver.info(); Ckt = solver.solve(FP); fail2 = solver.info(); if (fail1 || fail2) failInversion(); break; } +// case E_Inverter::FULLPIVHQR:{ Eigen::FullPivHouseholderQR solver; solver.compute(Q); fail1 = solver.info(); Ckt = solver.solve(FP); fail2 = solver.info(); if (fail1 || fail2) failInversion(); break; } +// case E_Inverter::FULLPIVLU: { Eigen::FullPivLU solver; solver.compute(Q); fail1 = solver.info(); Ckt = solver.solve(FP); fail2 = solver.info(); if (fail1 || fail2) failInversion(); break; } + } + + if ( fail1 + || fail2) + { + BOOST_LOG_TRIVIAL(warning) + << "Warning: RTS failed to find solution to invert system of equations, smoothed values may be bad " << fail1 << " " << fail2; + + std::cout << std::endl << "P-det: " << kalmanMinus.P.determinant(); + + kalmanMinus.outputConditionNumber(std::cout); + + std::cout << std::endl << "P:\n" << kalmanMinus.P.format(HeavyFmt); + kalmanMinus.outputCorrelations(std::cout); + std::cout << std::endl; + + //break out of the loop + lag = kfState.rts_lag; + break; + } + MatrixXd Ck = Ckt.transpose(); + VectorXd deltaX = Ck * (smoothedKF.x - kalmanMinus.x); MatrixXd deltaP = Ck * (smoothedKF.P - kalmanMinus.P) * Ck.transpose(); @@ -373,7 +490,7 @@ KFState RTS_Process( if (measurements.H.cols() == deltaX.rows()) { - measurements.VV -= measurements.H * deltaX; + measurements.VV -= measurements.H * deltaX; //todo aaron, is this the correct deltaX to be adding here? wrong plus/minus timepoint? } else { @@ -384,13 +501,13 @@ KFState RTS_Process( if (write) { - spitFilterToFile(smoothedKF, E_SerialObject::FILTER_PLUS, outputFile); - spitFilterToFile(measurements, E_SerialObject::MEASUREMENT, outputFile); + spitFilterToFile(smoothedKF, E_SerialObject::FILTER_SMOOTHED, outputFile); + spitFilterToFile(measurements, E_SerialObject::MEASUREMENT, outputFile); } else { bool final = false; - if (lag == kfState.rts_lag) + if (lag >= kfState.rts_lag) { final = true; } @@ -398,10 +515,9 @@ KFState RTS_Process( // smoothedKF.metaDataMap = kfState.metaDataMap; //todo aaron check this postRTSActions(final, smoothedKF, stationMap_ptr); - if ( acsConfig.output_mongo_measurements - && acsConfig.output_intermediate_rts) + if (acsConfig.pppOpts.output_intermediate_rts) { - mongoMeasResiduals(smoothedKF.time, measurements.obsKeys, measurements.V, measurements.VV, measurements.R, acsConfig.mongo_rts_suffix); + mongoMeasResiduals(smoothedKF.time, measurements, "_rts"); } } diff --git a/src/cpp/common/rtsSmoothing.hpp b/src/cpp/common/rtsSmoothing.hpp index 63c603ffc..51ddaba5f 100644 --- a/src/cpp/common/rtsSmoothing.hpp +++ b/src/cpp/common/rtsSmoothing.hpp @@ -1,6 +1,5 @@ -#ifndef __RTS_SMOOTHING_HPP__ -#define __RTS_SMOOTHING_HPP__ +#pragma once #include #include @@ -19,4 +18,3 @@ KFState RTS_Process( StationMap* stationMap_ptr = nullptr); -#endif diff --git a/src/cpp/common/satStat.hpp b/src/cpp/common/satStat.hpp index 2a05d866e..cefc44ed0 100644 --- a/src/cpp/common/satStat.hpp +++ b/src/cpp/common/satStat.hpp @@ -1,7 +1,5 @@ - -#ifndef __SATSTAT_HPP__ -#define __SATSTAT_HPP__ +#pragma once #include @@ -18,7 +16,7 @@ using std::map; */ struct SigStat { - union + union SlipStat { unsigned int any = 0; ///< Non zero value indicates a slip has been detected struct @@ -26,23 +24,20 @@ struct SigStat unsigned LLI : 1; ///< Slip detected by loss of lock indicator unsigned GF : 1; ///< Slip detected by geometry free combination unsigned MW : 1; ///< Slip detected by Melbourne Wubenna combination - unsigned EMW : 1; ///< Slip detected by extended MW combination - unsigned CJ : 1; ///< Slip detected as clock jump unsigned SCDIA : 1; ///< Slip detected DIA }; - } slip; - - unsigned int userPhaseRejectCount = 0; - unsigned int userPhaseOutageCount = 0; + }; - unsigned int netwPhaseRejectCount = 0; - unsigned int netwPhaseOutageCount = 0; + SlipStat savedSlip; + SlipStat slip; + + unsigned int phaseRejectCount = 0; + unsigned int phaseOutageCount = 0; double recPco = 0; double recPcv = 0; double satPcv = 0; - double lambda = 0; }; @@ -84,30 +79,29 @@ struct QC */ struct SatStat : IonoStat, QC { - double phw = 0; ///< Phase windup (cycle) - double mapWet = 0; ///< troposphere wet mapping function - double mapWetGrads[2] = {}; ///< troposphere wet mapping function - Vector3d e = Vector3d::Zero(); ///< Line-of-sight unit vector + double phw = 0; ///< Phase windup (cycle) + double mapWet = 0; ///< troposphere wet mapping function + double mapWetGrads[2] = {}; ///< troposphere wet mapping function + VectorEcef e; ///< Line-of-sight unit vector - double dIono = 0; ///< TD ionosphere residual - double sigmaIono = 0; ///< TD ionosphere residual noise + double dIono = 0; ///< TD ionosphere residual + double sigmaIono = 0; ///< TD ionosphere residual noise + double prevSTEC = 0; union { - double azel[2] = {}; ///< azimuth/elevation angles as array(rad) + double azel[2] = {}; ///< azimuth/elevation angles as array(rad) struct { - double az; ///< azimuth angle (rad) - double el; ///< elevation angle (rad) + double az; ///< azimuth angle (rad) + double el; ///< elevation angle (rad) }; }; - double nadir = 0; - double sunDotSat = 0; - double sunCrossSat = 0; bool slip = false; - map sigStatMap; ///< Map for individual signal status for this SatStat object + map sigStatMap; ///< Map for individual signal status for this SatStat object + }; -#endif +string ft2string(E_FType ft); diff --git a/src/cpp/common/satSys.cpp b/src/cpp/common/satSys.cpp index e76bfb743..80d1e7804 100644 --- a/src/cpp/common/satSys.cpp +++ b/src/cpp/common/satSys.cpp @@ -1,9 +1,10 @@ +// #pragma GCC optimize ("O0") #include "satSys.hpp" -map SatSys::SatDataMap = +map SatSys::satDataMap = { }; @@ -15,10 +16,21 @@ vector getSysSats( { vector sats; /* output satellite PRN*/ - if (targetSys == +E_Sys::GPS) for (int prn = MINPRNGPS; prn <= MAXPRNGPS; prn++) { sats.push_back(SatSys(E_Sys::GPS, prn)); } - if (targetSys == +E_Sys::GLO) for (int prn = MINPRNGLO; prn <= MAXPRNGLO; prn++) { sats.push_back(SatSys(E_Sys::GLO, prn)); } - if (targetSys == +E_Sys::GAL) for (int prn = MINPRNGAL; prn <= MAXPRNGAL; prn++) { sats.push_back(SatSys(E_Sys::GAL, prn)); } - if (targetSys == +E_Sys::BDS) for (int prn = MINPRNBDS; prn <= MAXPRNBDS; prn++) { sats.push_back(SatSys(E_Sys::BDS, prn)); } + if (targetSys == +E_Sys::GPS) for (int prn = 1; prn <= NSATGPS; prn++) { sats.push_back(SatSys(E_Sys::GPS, prn)); } + if (targetSys == +E_Sys::GLO) for (int prn = 1; prn <= NSATGLO; prn++) { sats.push_back(SatSys(E_Sys::GLO, prn)); } + if (targetSys == +E_Sys::GAL) for (int prn = 1; prn <= NSATGAL; prn++) { sats.push_back(SatSys(E_Sys::GAL, prn)); } + if (targetSys == +E_Sys::BDS) for (int prn = 1; prn <= NSATBDS; prn++) { sats.push_back(SatSys(E_Sys::BDS, prn)); } + if (targetSys == +E_Sys::QZS) for (int prn = 1; prn <= NSATQZS; prn++) { sats.push_back(SatSys(E_Sys::QZS, prn)); } + if (targetSys == +E_Sys::SBS) for (int prn = 1; prn <= NSATSBS; prn++) { sats.push_back(SatSys(E_Sys::SBS, prn)); } return sats; -} \ No newline at end of file +} + +void SatSys::getId(char* str) const +{ + char sys_c = sysChar(); + + if (sys == +E_Sys::NONE) sprintf(str, ""); + else if (prn == 0) sprintf(str, "%c--", sys_c); + else sprintf(str, "%c%02d", sys_c, prn); +} diff --git a/src/cpp/common/satSys.hpp b/src/cpp/common/satSys.hpp index c90373c40..ee3442078 100644 --- a/src/cpp/common/satSys.hpp +++ b/src/cpp/common/satSys.hpp @@ -1,6 +1,5 @@ -#ifndef __SATSYS_HPP_ -#define __SATSYS_HPP_ +#pragma once #include #include @@ -13,36 +12,18 @@ using std::map; #include "enums.h" -#define MINPRNGPS 1 /* min satellite PRN number of GPS */ -#define MAXPRNGPS 32 /* max satellite PRN number of GPS */ -#define NSATGPS (MAXPRNGPS-MINPRNGPS+1) /* number of GPS satellites */ -#define NSYSGPS 1 - -#define MINPRNGLO 1 /* min satellite slot number of GLONASS */ -#define MAXPRNGLO 27 /* max satellite slot number of GLONASS */ -#define NSATGLO (MAXPRNGLO-MINPRNGLO+1) /* number of GLONASS satellites */ - -#define MINPRNGAL 1 /* min satellite PRN number of Galileo */ -#define MAXPRNGAL 30 /* max satellite PRN number of Galileo */ -#define NSATGAL (MAXPRNGAL-MINPRNGAL+1) /* number of Galileo satellites */ - -#define MINPRNQZS 193 /* min satellite PRN number of QZSS */ -#define MAXPRNQZS 199 /* max satellite PRN number of QZSS */ -#define MINPRNQZS_S 183 /* min satellite PRN number of QZSS SAIF */ -#define MAXPRNQZS_S 189 /* max satellite PRN number of QZSS SAIF */ -#define NSATQZS (MAXPRNQZS-MINPRNQZS+1) /* number of QZSS satellites */ - -#define MINPRNBDS 1 /* min satellite sat number of BeiDou */ -#define MAXPRNBDS 35 /* max satellite sat number of BeiDou */ -#define NSATBDS (MAXPRNBDS-MINPRNBDS+1) /* number of BeiDou satellites */ +#define RAW_SBAS_PRN_OFFSET 119 +#define RAW_QZSS_PRN_OFFSET 192 +#define QZS_SAIF_PRN_OFFSET 182 -#define MINPRNLEO 1 /* min satellite sat number of LEO */ -#define MAXPRNLEO 10 /* max satellite sat number of LEO */ -#define NSATLEO (MAXPRNLEO-MINPRNLEO+1) /* number of LEO satellites */ - -#define MINPRNSBS 120 /* min satellite PRN number of SBAS */ -#define MAXPRNSBS 142 /* max satellite PRN number of SBAS */ -#define NSATSBS (MAXPRNSBS-MINPRNSBS+1) /* number of SBAS satellites */ +#define NSYSGPS 1 +#define NSATGPS 32 ///< potential number of GPS satellites, PRN goes from 1 to this number +#define NSATGLO 27 ///< potential number of GLONASS satellites, PRN goes from 1 to this number +#define NSATGAL 36 ///< potential number of Galileo satellites, PRN goes from 1 to this number +#define NSATQZS 7 ///< potential number of QZSS satellites, PRN goes from 1 to this number +#define NSATLEO 78 ///< potential number of LEO satellites, PRN goes from 1 to this number +#define NSATBDS 61 ///< potential number of Beidou satellites, PRN goes from 1 to this number +#define NSATSBS 39 ///< potential number of SBAS satellites, PRN goes from 1 to this number /** Object holding satellite id, and providing related functions */ @@ -66,22 +47,6 @@ struct SatSys string svn; }; - - /** Returns the bias group associated with this satellite. - * Receivers may combine multiple satellite systems on a single internal clock, each with their own bias. - * The biases defined by this function are the basis for the different clocks calculated in this software - */ - short int biasGroup() const - { - switch (sys) - { - default: return E_BiasGroup::GPS; - case E_Sys::GLO: return E_BiasGroup::GLO; - case E_Sys::GAL: return E_BiasGroup::GAL; - case E_Sys::BDS: return E_BiasGroup::BDS; - } - } - #define SBAS_CHAR 's' /** Returns the character used as a prefix for this system. */ @@ -101,14 +66,7 @@ struct SatSys } } - /** Sets a 4 character c_string of this satellite's id. - */ - void getId(char* str) const - { - char sys_c = sysChar(); - if (sys_c == SBAS_CHAR) sprintf(str, "%03d", prn); - else sprintf(str, "%c%02d", sys_c, prn); - } + void getId(char* str) const; /** Returns a unique id for this satellite (for use in hashes) */ @@ -119,46 +77,28 @@ struct SatSys return intval; } - static map SatDataMap; + static map satDataMap; void setBlockType( string blockType) { - SatDataMap[*this].block = blockType; + satDataMap[*this].block = blockType; } void setSvn( string svn) { - SatDataMap[*this].svn = svn; + satDataMap[*this].svn = svn; } string blockType() const { - auto iterator = SatDataMap.find(*this); - if (iterator == SatDataMap.end()) - { - return ""; - } - else - { - auto& satData = iterator->second; - return satData.block; - } + return satDataMap[*this].block; } string svn() const { - auto iterator = SatDataMap.find(*this); - if (iterator == SatDataMap.end()) - { - return ""; - } - else - { - auto& satData = iterator->second; - return satData.svn; - } + return satDataMap[*this].svn; } /** Constructs a SatSys object from it's hash uid @@ -174,8 +114,11 @@ struct SatSys string id() const { char cstring[5]; + getId(cstring); + string str = cstring; + if (str != "-00") return str; else @@ -208,35 +151,33 @@ struct SatSys /** Constructs a SatSys object from a c_string id */ - SatSys(const char *id) + SatSys(const char* id) { char code; int prn_; - if (sscanf(id,"%d",&prn_)==1) + if (sscanf(id, "%d", &prn_) == 1) { prn = prn_; - if (MINPRNGPS <= prn && prn <= MAXPRNGPS) sys = E_Sys::GPS; - else if (MINPRNSBS <= prn && prn <= MAXPRNSBS) sys = E_Sys::SBS; - else if (MINPRNQZS <= prn && prn <= MAXPRNQZS) sys = E_Sys::QZS; - else return; - return; + if (1 <= prn && prn <= NSATGPS) { sys = E_Sys::GPS; return;} + + prn = prn_ - RAW_SBAS_PRN_OFFSET; + if (1 <= prn && prn <= NSATSBS) { sys = E_Sys::SBS; return;} + + prn = prn_ - RAW_QZSS_PRN_OFFSET; + if (1 <= prn && prn <= NSATQZS) { sys = E_Sys::QZS; return;} + + prn = prn_; sys = E_Sys::NONE; return; } - int found = sscanf(id,"%c%d",&code,&prn_); + + int found = sscanf(id, "%c%d", &code, &prn_); if (found > 0) { sys = sysFromChar(code); - - switch (code) - { -// case 'J': sys = E_Sys::QZS; prn_ += PRN_OFFSET_QZS; break; //todo Eugene: check if affects other code -// case 'S': sys = E_Sys::SBS; prn_ += PRN_OFFSET_SBS; break; - default: break; - } } + if (found > 1) prn = prn_; - return; } /* Returns a string of this satellite's system id @@ -276,4 +217,3 @@ namespace std vector getSysSats( E_Sys targetSys); -#endif diff --git a/src/cpp/common/sinex.cpp b/src/cpp/common/sinex.cpp index bca5b53b1..92cb06390 100644 --- a/src/cpp/common/sinex.cpp +++ b/src/cpp/common/sinex.cpp @@ -4,16 +4,19 @@ #include #include #include +#include +#include #include #include #include "eigenIncluder.hpp" -#include "streamTrace.hpp" +#include "navigation.hpp" #include "algebra.hpp" #include "station.hpp" #include "gTime.hpp" #include "sinex.hpp" +#include "trace.hpp" using std::endl; using std::getline; @@ -22,6 +25,10 @@ using std::ofstream; + +Sinex theSinex(false); // the one and only sinex object. + + // Sinex 2.02 documentation indicates 2 digit years. >50 means 1900+N. <=50 means 2000+N // To achieve this, when we read years, if >50 add 1900 else add 2000. This source will // cease to work safely around 2045! @@ -33,26 +40,35 @@ void nearestYear(int& year) else year += 2000; } -Sinex theSinex(false); // the one and only sinex object. - - -string trim(const string& ref) +/** Trims leading & trailing whitespace + */ +string trim( + const string& ref) ///< string to trim { int start = 0, stop = ref.length() - 1, len; - while (start != stop && isspace(ref[start])) - start++; - - while (stop != start && isspace(ref[stop])) - stop--; + while (start != stop && isspace(ref[start])) start++; + while (stop != start && isspace(ref[stop])) stop--; len = stop - start + 1; + return ref.substr(start, len); } -// return seconds diff bewteen left and right. If left < right the value is negative -// each argument is given as year/doy/sod -long int time_compare(int left[3], int right[3]) +/** Cuts string after first space, deletes trailing carriage return + */ +void trimCut( + string& line) ///< string to trim +{ + line = line.substr(0, line.find(' ')); + if (line.back() == '\r') + line.pop_back(); +} + +/** seconds diff bewteen left and right + * If left < right the value is negative + */ +long int time_compare(UYds& left, UYds& right) //todo aaron, delete this { long int leftfull = (left[0] * 365 + left[1]) * 86400 + left[2]; long int rightfull = (right[0] * 365 + right[1]) * 86400 + right[2]; @@ -71,9 +87,9 @@ bool compare(string& one, string& two) bool compare(Sinex_input_file_t& one, Sinex_input_file_t& two) { - if ( one.epoch[0] == two.epoch[0] - && one.epoch[1] == two.epoch[1] - && one.epoch[2] == two.epoch[2] + if ( one.yds[0] == two.yds[0] + && one.yds[1] == two.yds[1] + && one.yds[2] == two.yds[2] && one.agency .compare(two.agency) == 0 && one.file .compare(two.file) == 0 && one.description .compare(two.description) == 0) @@ -186,15 +202,6 @@ bool compare(Sinex_nutcode_t& one, Sinex_nutcode_t& two) return false; } -bool compare(Sinex_satident_t& one, Sinex_satident_t& two) -{ - if (one.svn.compare(two.svn) == 0) - { - return true; - } - return false; -} - bool compare(Sinex_satprn_t& one, Sinex_satprn_t& two) { if ( one.svn.compare(two.svn) == 0 @@ -295,12 +302,12 @@ bool compare(Sinex_sitedata_t& one, Sinex_sitedata_t& two) bool compare(Sinex_receiver_t& one, Sinex_receiver_t& two) { if ( one.sitecode.compare(two.sitecode) == 0 - &&one.recstart[0] == two.recstart[0] - &&one.recstart[1] == two.recstart[2] - &&one.recstart[2] == two.recstart[2] - &&one.recend[0] == two.recend[0] - &&one.recend[1] == two.recend[1] - &&one.recend[2] == two.recend[2]) + &&one.start[0] == two.start[0] + &&one.start[1] == two.start[1] + &&one.start[2] == two.start[2] + &&one.end[0] == two.end[0] + &&one.end[1] == two.end[1] + &&one.end[2] == two.end[2]) { return true; } @@ -310,12 +317,12 @@ bool compare(Sinex_receiver_t& one, Sinex_receiver_t& two) bool compare(Sinex_antenna_t& one, Sinex_antenna_t& two) { if ( one.sitecode.compare(two.sitecode) == 0 - &&one.antstart[0] == two.antstart[0] - &&one.antstart[1] == two.antstart[2] - &&one.antstart[2] == two.antstart[2] - &&one.antend[0] == two.antend[0] - &&one.antend[1] == two.antend[1] - &&one.antend[2] == two.antend[2]) + &&one.start[0] == two.start[0] + &&one.start[1] == two.start[1] + &&one.start[2] == two.start[2] + &&one.end[0] == two.end[0] + &&one.end[1] == two.end[1] + &&one.end[2] == two.end[2]) { return true; } @@ -345,12 +352,12 @@ bool compare(Sinex_gal_phase_center_t& one, Sinex_gal_phase_center_t& two) bool compare(Sinex_site_ecc_t& one, Sinex_site_ecc_t& two) { if ( one.sitecode.compare(two.sitecode) == 0 - &&one.eccstart[0] == two.eccstart[0] - &&one.eccstart[1] == two.eccstart[2] - &&one.eccstart[2] == two.eccstart[2] - &&one.eccend[0] == two.eccend[0] - &&one.eccend[1] == two.eccend[1] - &&one.eccend[2] == two.eccend[2]) + &&one.start[0] == two.start[0] + &&one.start[1] == two.start[1] + &&one.start[2] == two.start[2] + &&one.end[0] == two.end[0] + &&one.end[1] == two.end[1] + &&one.end[2] == two.end[2]) { return true; } @@ -361,7 +368,7 @@ bool compare(Sinex_solepoch_t& one, Sinex_solepoch_t& two) { if ( one.sitecode.compare(two.sitecode) == 0 &&one.start[0] == two.start[0] - &&one.start[1] == two.start[2] + &&one.start[1] == two.start[1] &&one.start[2] == two.start[2] &&one.end[0] == two.end[0] &&one.end[1] == two.end[1] @@ -415,7 +422,6 @@ bool compare(Sinex_solmatrix_t& one, Sinex_solmatrix_t& two) return false; } - template void dedupe(list& source) { @@ -485,7 +491,6 @@ void dedupe_sinex() // general stuff dedupe(theSinex.refstrings); - dedupe(theSinex.commentstrings); dedupe(theSinex.inputHistory); dedupe(theSinex.inputFiles); dedupe(theSinex.acknowledgements); @@ -493,12 +498,9 @@ void dedupe_sinex() dedupe(theSinex.list_precessions); dedupe(theSinex.list_source_ids); dedupe(theSinex.list_satids); - dedupe(theSinex.list_satidents); dedupe(theSinex.list_satprns); dedupe(theSinex.list_satfreqchns); - dedupe(theSinex.list_satmasses); dedupe(theSinex.list_satcoms); - dedupe(theSinex.list_satpowers); dedupe(theSinex.list_sateccs); dedupe(theSinex.list_satpcs); dedupe(theSinex.list_statistics); @@ -608,12 +610,11 @@ int read_snx_header(std::ifstream& in) return 0; } -void sinex_update_header( +void updateSinexHeader( string& create_agc, - int create_date[3], string& data_agc, - int soln_start[3], - int soln_end[3], + UYds soln_start, + UYds soln_end, const char obsCode, const char constCode, string& contents, @@ -629,28 +630,23 @@ void sinex_update_header( siht.constraint = theSinex.ConstCode; siht.num_estimates = theSinex.numparam; siht.contents = theSinex.solcont; - - memcpy(siht.create_time, theSinex.filedate, sizeof(siht.create_time)); - memcpy(siht.start, theSinex.solution_start_date, sizeof(siht.start)); - memcpy(siht.stop, theSinex.solution_end_date, sizeof(siht.stop)); + siht.create_time = theSinex.filedate; + siht.start = theSinex.solution_start_date; + siht.stop = theSinex.solution_end_date; if (theSinex.inputHistory.empty()) theSinex.inputHistory.push_back(siht); theSinex.ver = sinexVer; - if (data_agc.size() > 0) - theSinex.data_agc = data_agc; - else - theSinex.data_agc = theSinex.create_agc; - - theSinex.create_agc = create_agc; - theSinex.solcont = contents; + if (data_agc.size() > 0) theSinex.data_agc = data_agc; + else theSinex.data_agc = theSinex.create_agc; - - memcpy(theSinex.filedate, create_date, sizeof(theSinex.filedate)); - memcpy(theSinex.solution_start_date, soln_start, sizeof(theSinex.solution_start_date)); - memcpy(theSinex.solution_end_date, soln_end, sizeof(theSinex.solution_end_date)); + theSinex.create_agc = create_agc; + theSinex.solcont = contents; + theSinex.filedate = timeGet(); + theSinex.solution_start_date = soln_start; + theSinex.solution_end_date = soln_end; if (obsCode != ' ') theSinex.ObsCode = obsCode; @@ -663,13 +659,12 @@ void sinex_update_header( void write_snx_header(std::ofstream& out) { - char line[80]; + char line[81]; char c; int i; - memset(line, 0, 80); - - sprintf(line, "%%=SNX %4.2lf %3s %2.2d:%3.3d:%5.5d %3s %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %c %5d %c", + int offset = 0; + offset += snprintf(line + offset, sizeof(line) - offset, "%%=SNX %4.2lf %3s %2.2d:%3.3d:%5.5d %3s %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %c %5d %c", theSinex.ver, theSinex.create_agc.c_str(), theSinex.filedate[0] % 100, @@ -691,17 +686,12 @@ void write_snx_header(std::ofstream& out) while (c != ' ') { - char s[3]; - - sprintf(s, " %c", c); - strcat(line, s); - - ++i; + snprintf(line + offset, sizeof(line) - offset, " %c", c); + + i++; - if (i <= static_cast(theSinex.solcont.length())) - c = theSinex.solcont[i]; - else - c = ' '; + if (i <= theSinex.solcont.length()) c = theSinex.solcont[i]; + else c = ' '; } out << line << endl; @@ -725,63 +715,45 @@ void write_as_comments(ofstream& out, list& comments) } } -void write_pretty_line(ofstream& out) -{ - out << '*'+string(79, '-') << endl; -} - void comments_override() { // overriding only those that can be found in IGS/CODE/GRG SINEX files - if (!theSinex.inputHistory. empty()) {theSinex.historyComments. clear(); theSinex.historyComments. push_back("*_VERSION_ CRE __CREATION__ OWN _DATA_START_ __DATA_END__ T PARAM S ____TYPE____"); } // INPUT/HISTORY - if (!theSinex.inputFiles. empty()) {theSinex.filesComments. clear(); theSinex.filesComments. push_back("*OWN __CREATION__ ___________FILENAME__________ ___________DESCRIPTION__________"); } // INPUT/FILES - if (!theSinex.acknowledgements. empty()) {theSinex.ackComments. clear(); theSinex.ackComments. push_back("*AGY ______________________________FULL_DESCRIPTION_____________________________"); } // INPUT/ACKNOWLEDGEMENTS - if (!theSinex.map_siteids. empty()) {theSinex.siteIdcomments. clear(); theSinex.siteIdcomments. push_back("*CODE PT __DOMES__ T _STATION DESCRIPTION__ _LONGITUDE_ _LATITUDE__ HEIGHT_"); } // SITE/ID - if (!theSinex.list_sitedata. empty()) {theSinex.siteDatacomments. clear(); theSinex.siteDatacomments. push_back("*CODE PT SOLN CODE PT SOLN T _DATA START_ _DATA END___ OWN _FILE TIME__"); } // SITE/DATA - if (!theSinex.map_receivers. empty()) {theSinex.receivercomments. clear(); theSinex.receivercomments. push_back("*CODE PT SOLN T _DATA START_ _DATA END___ _RECEIVER TYPE______ _S/N_ _FIRMWARE__"); } // SITE/RECEIVER - if (!theSinex.map_antennas. empty()) {theSinex.antennacomments. clear(); theSinex.antennacomments. push_back("*CODE PT SOLN T _DATA START_ __DATA END__ __ANTENNA TYPE______ _S/N_"); } // SITE/ANTENNA - if (!theSinex.list_gps_pcs. empty()) {theSinex.gps_pc_comments. clear(); theSinex.gps_pc_comments. push_back("________TYPE________ _S/N_ _L1_U_ _L1_N_ _L1_E_ _L2_U_ _L2_N_ _L2_E_ __MODEL___"); } // SITE/GPS_PHASE_CENTER - if (!theSinex.map_eccentricities. empty()) {theSinex.site_ecc_comments. clear(); theSinex.site_ecc_comments. push_back("* _UP_____ _NORTH__ _EAST___\n*CODE PT SOLN T _DATA START_ __DATA END__ TYP __ARP-BENCHMARK (M)_______"); }// SITE/ECCENTRICITY - {theSinex.estimate_comments. clear(); theSinex.estimate_comments. push_back("*INDEX _TYPE_ CODE PT SOLN _REF_EPOCH__ UNIT S ___ESTIMATED_VALUE___ __STD_DEV__"); } // BIAS/EPOCHS|SOLUTION/EPOCHS|SOLUTION/ESTIMATE - if (!theSinex.list_statistics. empty()) {theSinex.statistics_comments. clear(); theSinex.statistics_comments. push_back("*_STATISTICAL PARAMETER________ __VALUE(S)____________"); } // SOLUTION/STATISTICS - if (!theSinex.apriori_map. empty()) {theSinex.apriori_comments. clear(); theSinex.apriori_comments. push_back("*INDEX _TYPE_ CODE PT SOLN _REF_EPOCH__ UNIT S __APRIORI VALUE______ _STD_DEV___"); } // SOLUTION/APRIORI - if (!theSinex.list_normal_eqns. empty()) {theSinex.normal_eqns_comments.clear(); theSinex.normal_eqns_comments. push_back("*INDEX TYPE__ CODE PT SOLN _REF_EPOCH__ UNIT S __RIGHT_HAND_SIDE____"); } // SOLUTION/NORMAL_EQUATION_VECTOR - {theSinex.matrix_comments. clear(); theSinex.matrix_comments. push_back("*PARA1 PARA2 _______PARA2+0_______ _______PARA2+1_______ _______PARA2+2_______"); } // SOLUTION/MATRIX_ESTIMATE|SOLUTION/MATRIX_APRIORI|SOLUTION/NORMAL_EQUATION_MATRIX - if (!theSinex.list_satpcs. empty()) {theSinex.satpc_comments. clear(); theSinex.satpc_comments. push_back("*SITE L SATA_Z SATA_X SATA_Y L SATA_Z SATA_X SATA_Y MODEL_____ T M"); } // SATELLITE/PHASE_CENTER - if (!theSinex.list_satids. empty()) {theSinex.satid_comments. clear(); theSinex.satid_comments. push_back("SATELLITE/ID *SITE PR COSPAR___ T DATA_START__ DATA_END____ ANTENNA_____________"); } // SATELLITE/ID -} - -int write_snx_reference(ofstream& out) -{ - out << "+FILE/REFERENCE" << endl; + theSinex.blockComments["FILE/REFERENCE"]. push_back("*OWN __CREATION__ ___________FILENAME__________ ___________DESCRIPTION__________"); // INPUT/FILES + theSinex.blockComments["INPUT/HISTORY"]. push_back("*_VERSION_ CRE __CREATION__ OWN _DATA_START_ __DATA_END__ T PARAM S ____TYPE____"); // INPUT/HISTORY + theSinex.blockComments["INPUT/ACKNOWLEDGEMENTS"]. push_back("*AGY ______________________________FULL_DESCRIPTION_____________________________"); // INPUT/ACKNOWLEDGEMENTS + theSinex.blockComments["SITE/ID"]. push_back("*CODE PT __DOMES__ T _STATION DESCRIPTION__ _LONGITUDE_ _LATITUDE__ HEIGHT_"); // SITE/ID + theSinex.blockComments["SITE/DATA"]. push_back("*CODE PT SOLN CODE PT SOLN T _DATA START_ _DATA END___ OWN _FILE TIME__"); // SITE/DATA + theSinex.blockComments["SITE/RECEIVER"]. push_back("*CODE PT SOLN T _DATA START_ _DATA END___ _RECEIVER TYPE______ _S/N_ _FIRMWARE__"); // SITE/RECEIVER + theSinex.blockComments["SITE/ANTENNA"]. push_back("*CODE PT SOLN T _DATA START_ __DATA END__ __ANTENNA TYPE______ _S/N_"); // SITE/ANTENNA + theSinex.blockComments["SITE/GPS_PHASE_CENTER"]. push_back("________TYPE________ _S/N_ _L1_U_ _L1_N_ _L1_E_ _L2_U_ _L2_N_ _L2_E_ __MODEL___"); // SITE/GPS_PHASE_CENTER + theSinex.blockComments["SITE/ECCENTRICITY"]. push_back("* _UP_____ _NORTH__ _EAST___\n*CODE PT SOLN T _DATA START_ __DATA END__ TYP __ARP-BENCHMARK (M)_______"); // SITE/ECCENTRICITY + theSinex.blockComments["SOLUTION/ESTIMATE"]. push_back("*INDEX _TYPE_ CODE PT SOLN _REF_EPOCH__ UNIT S ___ESTIMATED_VALUE___ __STD_DEV__"); // BIAS/EPOCHS|SOLUTION/EPOCHS|SOLUTION/ESTIMATE + theSinex.blockComments["SOLUTION/STATISTICS"]. push_back("*_STATISTICAL PARAMETER________ __VALUE(S)____________"); // SOLUTION/STATISTICS + theSinex.blockComments["SOLUTION/APRIORI"]. push_back("*INDEX _TYPE_ CODE PT SOLN _REF_EPOCH__ UNIT S __APRIORI VALUE______ _STD_DEV___"); // SOLUTION/APRIORI + theSinex.blockComments["SOLUTION/NORMAL_EQUATION_VECTOR"]. push_back("*INDEX TYPE__ CODE PT SOLN _REF_EPOCH__ UNIT S __RIGHT_HAND_SIDE____"); // SOLUTION/NORMAL_EQUATION_VECTOR + theSinex.blockComments["SOLUTION/MATRIX_ESTIMATE"]. push_back("*PARA1 PARA2 _______PARA2+0_______ _______PARA2+1_______ _______PARA2+2_______"); // SOLUTION/MATRIX_ESTIMATE|SOLUTION/MATRIX_APRIORI|SOLUTION/NORMAL_EQUATION_MATRIX + theSinex.blockComments["SATELLITE/PHASE_CENTER"]. push_back("*SITE L SATA_Z SATA_X SATA_Y L SATA_Z SATA_X SATA_Y MODEL_____ T M"); // SATELLITE/PHASE_CENTER + theSinex.blockComments["SAT/ID"]. push_back("SATELLITE/ID *SITE PR COSPAR___ T DATA_START__ DATA_END____ ANTENNA_____________"); // SATELLITE/ID +} + +void write_snx_reference(ofstream& out) +{ + Block block(out, "FILE/REFERENCE"); for (auto& refString : theSinex.refstrings) { out << refString << endl; } - - out << "-FILE/REFERENCE" << endl; - - return 0; -} - -void parse_snx_comment(string& s) -{ - theSinex.commentstrings.push_back(s); } -int write_snx_comments(ofstream& out) +void write_snx_comments(ofstream& out) { - out << "+FILE/COMMENT" << endl; + Block block(out, "FILE/COMMENT"); - for (auto& commentstring : theSinex.commentstrings) + for (auto& commentstring : theSinex.blockComments[block.blockName]) { out << commentstring << endl; } - - out << "-FILE/COMMENT" << endl; - - return 0; } void parse_snx_inputHistory(string& s) @@ -841,30 +813,23 @@ void parse_snx_inputHistory(string& s) theSinex.inputHistory.push_back(siht); } - else - { - // add to comment line, user will spot it and fix the error - theSinex.historyComments.push_back(s); - } } } -int write_snx_input_history(ofstream& out) +void write_snx_input_history(ofstream& out) { - out << "+INPUT/HISTORY" << endl; + Block block(out, "INPUT/HISTORY"); - write_as_comments(out, theSinex.historyComments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto it = theSinex.inputHistory.begin(); it != theSinex.inputHistory.end(); it++) { - char line[80]; + char line[81] = {}; + int offset = 0; Sinex_input_history_t siht = *it; int i = 0; - char c; - memset (line, 0, 80); - - sprintf(line, " %cSNX %4.2lf %3s %2.2d:%3.3d:%5.5d %3s %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %c %5d %c", + offset += snprintf(line + offset, sizeof(line) - offset, " %cSNX %4.2lf %3s %2.2d:%3.3d:%5.5d %3s %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %c %5d %c", siht.code, siht.fmt, siht.create_agency.c_str(), @@ -882,31 +847,19 @@ int write_snx_input_history(ofstream& out) siht.num_estimates, siht.constraint); - c = siht.contents[i]; + char c = siht.contents[i]; while (c != ' ') { - char s[3]; - - s[0] = ' '; - s[1] = c; - s[2] = '\0'; - - strcat(line, s); + offset += snprintf(line + offset, sizeof(line) - offset, " %c", c); i++; - if (static_cast(siht.contents.length()) >= i) - c = siht.contents[i]; - else - c = ' '; + if (siht.contents.length() >= i) c = siht.contents[i]; + else c = ' '; } out << line << endl; } - - out << "-INPUT/HISTORY" << endl; - - return 0; } void parse_snx_inputFiles(string& s) @@ -919,30 +872,25 @@ void parse_snx_inputFiles(string& s) int readcount = sscanf(p + 1, "%3s %2d:%3d:%5d", agency, - &sif.epoch[0], - &sif.epoch[1], - &sif.epoch[2]); + &sif.yds[0], + &sif.yds[1], + &sif.yds[2]); if (readcount == 4) { sif.agency = agency; - nearestYear(sif.epoch[0]); + nearestYear(sif.yds[0]); theSinex.inputFiles.push_back(sif); } - else - { - // error on line. Add to comments? user can fix it if they write it out again? - theSinex.filesComments.push_back(s); - } } -int write_snx_input_files(ofstream& out) +void write_snx_input_files(ofstream& out) { - out << "+INPUT/FILES" << endl; + Block block(out, "INPUT/FILES"); - write_as_comments(out, theSinex.filesComments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& inputFile : theSinex.inputFiles) { @@ -950,11 +898,11 @@ int write_snx_input_files(ofstream& out) char line[81]; int len; - sprintf(line, " %3s %2.2d:%3.3d:%5.5d ", + snprintf(line, sizeof(line), " %3s %02d:%03d:%05d ", sif.agency.c_str(), - sif.epoch[0] % 100, - sif.epoch[1], - sif.epoch[2]); + sif.yds[0] % 100, + sif.yds[1], + sif.yds[2]); // if the filename length is greater than 29 (format spec limit) make into a comment line if (sif.file.length() > 29) @@ -967,10 +915,6 @@ int write_snx_input_files(ofstream& out) } out << line << sif.file << " " << sif.description << endl; } - - out << "-INPUT/FILES" << endl; - - return 0; } void parse_snx_acknowledgements(string& s) @@ -983,28 +927,23 @@ void parse_snx_acknowledgements(string& s) theSinex.acknowledgements.push_back(sat); } -int write_snx_acknowledgements(ofstream& out) +void write_snx_acknowledgements(ofstream& out) { - out << "+INPUT/ACKNOWLEDGEMENTS" << endl; + Block block(out, "INPUT/ACKNOWLEDGEMENTS"); - write_as_comments(out, theSinex.ackComments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& acknowledgement : theSinex.acknowledgements) { Sinex_ack_t& ack = acknowledgement; char line[81]; - sprintf(line, " %3s %s", ack.agency.c_str(), ack.description.c_str()); + snprintf(line, sizeof(line), " %3s %s", ack.agency.c_str(), ack.description.c_str()); out << line << endl; } - - out << "-INPUT/ACKNOWLEDGEMENTS" << endl; - - return 0; } - void parse_snx_siteIds(string& s) { const char* p = s.c_str(); @@ -1018,9 +957,9 @@ void parse_snx_siteIds(string& s) int readcount = sscanf(p + 44, "%3d %2d %4lf %3d %2d %4lf %7lf", - &sst.long_deg, - &sst.long_min, - &sst.long_sec, + &sst.lon_deg, + &sst.lon_min, + &sst.lon_sec, &sst.lat_deg, &sst.lat_min, &sst.lat_sec, @@ -1030,17 +969,13 @@ void parse_snx_siteIds(string& s) { theSinex.map_siteids[sst.sitecode] = sst; } - else - { - theSinex.siteIdcomments.push_back(s); - } } -int write_snx_siteids(ofstream& out) +void write_snx_siteids(ofstream& out) { - out << "+SITE/ID" << endl; + Block block(out, "SITE/ID"); - write_as_comments(out, theSinex.siteIdcomments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [id, ssi] : theSinex.map_siteids) { @@ -1055,18 +990,14 @@ int write_snx_siteids(ofstream& out) ssi.domes.c_str(), ssi.typecode, ssi.desc.c_str(), - ssi.long_deg, - ssi.long_min, - ssi.long_sec, + ssi.lon_deg, + ssi.lon_min, + ssi.lon_sec, ssi.lat_deg, ssi.lat_min, ssi.lat_sec, ssi.height); } - - out << "-SITE/ID" << endl; - - return 0; } // compare by the 2 station ids only. @@ -1094,9 +1025,9 @@ void parse_snx_siteData(string& s) sst.sitesoln = s.substr(20, 4); sst.obscode = s[24]; - int start[3]; // yr:doy:sod - int end[3]; //yr:doy:sod - int create[3]; //yr:doy:sod + UYds start; + UYds end; + UYds create; char agency[4]; int readcount; @@ -1116,13 +1047,9 @@ void parse_snx_siteData(string& s) if (readcount == 10) { sst.agency = agency; - - for (int i = 0; i < 3; i++) - { - sst.start[i] = start[i]; - sst.stop[i] = end[i]; - sst.create[i] = create[i]; - } + sst.start = start; + sst.stop = end; + sst.create = create; // see comment at top of file if ( sst.start[0] != 0 @@ -1143,18 +1070,13 @@ void parse_snx_siteData(string& s) theSinex.list_sitedata.push_back(sst); } - else - { - // treat line as a comment. User can fix it if they write it out - theSinex.siteDatacomments.push_back(s); - } } -int write_snx_sitedata(ofstream& out, std::list* pstns) +void write_snx_sitedata(ofstream& out, list* pstns) { - out << "+SITE/DATA" << endl; + Block block(out, "SITE/DATA"); - write_as_comments(out, theSinex.siteDatacomments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& sitedata : theSinex.list_sitedata) { @@ -1162,7 +1084,7 @@ int write_snx_sitedata(ofstream& out, std::list* pstns) bool doit = false; char line[81]; - sprintf(line, " %4s %2s %4s %4s %2s %4s %c %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %3s %2.2d:%3.3d:%5.5d", + snprintf(line, sizeof(line), " %4s %2s %4s %4s %2s %4s %c %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %3s %2.2d:%3.3d:%5.5d", ssd.site.c_str(), ssd.station_pt.c_str(), ssd.soln_id.c_str(), @@ -1187,7 +1109,7 @@ int write_snx_sitedata(ofstream& out, std::list* pstns) { for (auto& stn : *pstns) { - if (ssd.site.compare(stn.sitecode) == 0) + if (ssd.site.compare(stn.id_ptr->sitecode) == 0) { doit = true; break; @@ -1198,9 +1120,6 @@ int write_snx_sitedata(ofstream& out, std::list* pstns) if (doit) out << line << endl; } - - out << "-SITE/DATA" << endl; - return 0; } void parse_snx_receivers(string& s) @@ -1213,51 +1132,45 @@ void parse_snx_receivers(string& s) srt.ptcode = s.substr(6, 2); srt.solnid = s.substr(9, 4); srt.typecode = s[14]; - srt.rectype = s.substr(42, 20); - srt.recsn = s.substr(63, 5); - srt.recfirm = trim(s.substr(69, 11)); + srt.type = s.substr(42, 20); + srt.sn = s.substr(63, 5); + srt.firm = trim(s.substr(69, 11)); int readcount; readcount = sscanf(p + 16, "%2d:%3d:%5d %2d:%3d:%5d", - &srt.recstart[0], - &srt.recstart[1], - &srt.recstart[2], - &srt.recend[0], - &srt.recend[1], - &srt.recend[2]); + &srt.start[0], + &srt.start[1], + &srt.start[2], + &srt.end[0], + &srt.end[1], + &srt.end[2]); if (readcount == 6) { // see comment at top of file - if ( srt.recstart[0] != 0 - || srt.recstart[1] != 0 - || srt.recstart[2] != 0) + if ( srt.start[0] != 0 + || srt.start[1] != 0 + || srt.start[2] != 0) { - nearestYear(srt.recstart[0]); + nearestYear(srt.start[0]); } - if ( srt.recend[0] != 0 - || srt.recend[1] != 0 - || srt.recend[2] != 0) + if ( srt.end[0] != 0 + || srt.end[1] != 0 + || srt.end[2] != 0) { - nearestYear(srt.recend[0]); + nearestYear(srt.end[0]); } - GTime time = yds2time(srt.recstart); - theSinex.map_receivers[srt.sitecode][time] = srt; - } - else - { - // did not read properly. Treat as a comment - theSinex.receivercomments.push_back(s); + theSinex.map_receivers[srt.sitecode][srt.start] = srt; } } -int write_snx_receivers(ofstream& out) +void write_snx_receivers(ofstream& out) { - out << "+SITE/RECEIVER" << endl; + Block block(out, "SITE/RECEIVER"); - write_as_comments(out, theSinex.receivercomments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [site, timemap] : theSinex.map_receivers) for (auto it = timemap.rbegin(); it != timemap.rend(); it++) @@ -1274,19 +1187,16 @@ int write_snx_receivers(ofstream& out) receiver.ptcode .c_str(), receiver.solnid .c_str(), receiver.typecode, - receiver.recstart[0] % 100, - receiver.recstart[1], - receiver.recstart[2], - receiver.recend[0] % 100, - receiver.recend[1], - receiver.recend[2], - receiver.rectype .c_str(), - receiver.recsn .c_str(), - receiver.recfirm .c_str()); - } - - out << "-SITE/RECEIVER" << endl; - return 0; + receiver.start[0] % 100, + receiver.start[1], + receiver.start[2], + receiver.end[0] % 100, + receiver.end[1], + receiver.end[2], + receiver.type .c_str(), + receiver.sn .c_str(), + receiver.firm .c_str()); + } } void parse_snx_antennas(string& s) @@ -1299,49 +1209,44 @@ void parse_snx_antennas(string& s) ant.ptcode = s.substr(6, 2); ant.solnnum = s.substr(9, 4); ant.typecode = s[14]; - ant.anttype = s.substr(42, 20); - ant.antsn = trim(s.substr(63, 5)); + ant.type = s.substr(42, 20); + ant.sn = trim(s.substr(63, 5)); int readcount = sscanf(p + 16, "%2d:%3d:%5d %2d:%3d:%5d", - &ant.antstart[0], - &ant.antstart[1], - &ant.antstart[2], - &ant.antend[0], - &ant.antend[1], - &ant.antend[2]); + &ant.start[0], + &ant.start[1], + &ant.start[2], + &ant.end[0], + &ant.end[1], + &ant.end[2]); if (readcount == 6) { // see comment at top of file - if ( ant.antstart[0] != 0 - || ant.antstart[1] != 0 - || ant.antstart[2] != 0) + if ( ant.start[0] != 0 + || ant.start[1] != 0 + || ant.start[2] != 0) { - nearestYear(ant.antstart[0]); + nearestYear(ant.start[0]); } - if ( ant.antend[0] != 0 - || ant.antend[1] != 0 - || ant.antend[2] != 0) + if ( ant.end[0] != 0 + || ant.end[1] != 0 + || ant.end[2] != 0) { - nearestYear(ant.antend[0]); + nearestYear(ant.end[0]); } - GTime time = yds2time(ant.antstart); - theSinex.map_antennas[ant.sitecode][time] = ant; + + theSinex.map_antennas[ant.sitecode][ant.start] = ant; // theSinex.list_antennas.push_back(ant); } - else - { - // treat as comment. - theSinex.antennacomments.push_back(s); - } } -int write_snx_antennas(ofstream& out) +void write_snx_antennas(ofstream& out) { - out << "+SITE/ANTENNA" << endl; + Block block(out, "SITE/ANTENNA"); - write_as_comments(out, theSinex.antennacomments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [site, antmap] : theSinex.map_antennas) for (auto it = antmap.rbegin(); it != antmap.rend(); it++) @@ -1358,18 +1263,15 @@ int write_snx_antennas(ofstream& out) ant.ptcode .c_str(), ant.solnnum .c_str(), ant.typecode, - ant.antstart[0] % 100, - ant.antstart[1], - ant.antstart[2], - ant.antend[0] % 100, - ant.antend[1], - ant.antend[2], - ant.anttype .c_str(), - ant.antsn .c_str()); + ant.start[0] % 100, + ant.start[1], + ant.start[2], + ant.end[0] % 100, + ant.end[1], + ant.end[2], + ant.type .c_str(), + ant.sn .c_str()); } - - out << "-SITE/ANTENNA" << endl; - return 0; } // compare by antenna type and serial number. @@ -1404,11 +1306,6 @@ void parse_gps_phaseCenters(string& s) { theSinex.list_gps_pcs.push_back(sgpct); } - else - { - // treat as comment line - theSinex.gps_pc_comments.push_back(s); - } } void truncateSomething(char* buf) @@ -1425,11 +1322,11 @@ void truncateSomething(char* buf) } -int write_snx_gps_pcs(ofstream& out, std::list* pstns) +void write_snx_gps_pcs(ofstream& out, list* pstns) { - out << "+SITE/GPS_PHASE_CENTER" << endl; + Block block(out, "SITE/GPS_PHASE_CENTER"); - write_as_comments(out, theSinex.gps_pc_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& gps_pc : theSinex.list_gps_pcs) { @@ -1437,28 +1334,28 @@ int write_snx_gps_pcs(ofstream& out, std::list* pstns) char buf[8]; bool doit = false; - char line[81]; - - sprintf(line, " %20s %5s ", - sgt.antname.c_str(), sgt.serialno.c_str()); + char line[81]; + int offset = 0; + + offset += snprintf(line + offset, sizeof(line) - offset, " %20s %5s ", + sgt.antname.c_str(), + sgt.serialno.c_str()); for (int i = 0; i < 3; i++) { - sprintf(buf, "%6.4lf", sgt.L1[i]); + snprintf(buf, sizeof(buf), "%6.4lf", sgt.L1[i]); truncateSomething(buf); - strcat(line, buf); - strcat(line, " "); + offset += snprintf(line + offset, sizeof(line) - offset, "%s", buf); } for (int i = 0; i < 3; i++) { - sprintf(buf, "%6.4lf", sgt.L2[i]); + snprintf(buf, sizeof(buf), "%6.4lf", sgt.L2[i]); truncateSomething(buf); - strcat(line, buf); - strcat(line, " "); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf); } - strcat(line, sgt.calib.c_str()); + offset += snprintf(line + offset, sizeof(line) - offset, "%s", sgt.calib.c_str()); if (pstns == nullptr) { @@ -1468,7 +1365,7 @@ int write_snx_gps_pcs(ofstream& out, std::list* pstns) { for (auto& stn : *pstns) { - if (sgt.antname.compare(stn.anttype) == 0) + if (sgt.antname == stn.ant_ptr->type) { doit = true; break; @@ -1481,9 +1378,6 @@ int write_snx_gps_pcs(ofstream& out, std::list* pstns) out << line << endl; } } - - out << "-SITE/GPS_PHASE_CENTER" << endl; - return 0; } // compare by antenna type and serial number. return true0 if left < right @@ -1550,18 +1444,14 @@ void parse_gal_phaseCenters(string& s_x) { theSinex.list_gal_pcs.push_back(sgpct); } - else - { - theSinex.gal_pc_comments.push_back(s); - } } -int write_snx_gal_pcs(ofstream& out, std::list* pstns) +void write_snx_gal_pcs(ofstream& out, list* pstns) { - out << "+SITE/GAL_PHASE_CENTER" << endl; + Block block(out, "SITE/GAL_PHASE_CENTER"); - write_as_comments(out, theSinex.gal_pc_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& gal_pc : theSinex.list_gal_pcs) { @@ -1575,7 +1465,7 @@ int write_snx_gal_pcs(ofstream& out, std::list* pstns) { for (auto& stn : *pstns) { - if (sgt.antname.compare(stn.anttype) == 0) + if (sgt.antname == stn.ant_ptr->type) { doit = true; break; @@ -1586,71 +1476,78 @@ int write_snx_gal_pcs(ofstream& out, std::list* pstns) if (!doit) continue; - char line[81]; - - sprintf(line, " %20s %5s ", - sgt.antname.c_str(), sgt.serialno.c_str()); - - for (int i = 0; i < 3; i++) { - sprintf(buf, "%6.4lf", sgt.L1[i]); - truncateSomething(buf); - strcat(line, buf); - strcat(line, " "); - } + char line[81]; + int offset = 0; - for (int i = 0; i < 3; i++) - { - sprintf(buf, "%6.4lf", sgt.L5[i]); - truncateSomething(buf); - strcat(line, buf); - strcat(line, " "); - } + offset += snprintf(line + offset, sizeof(line) - offset, " %20s %5s ", + sgt.antname.c_str(), + sgt.serialno.c_str()); - strcat(line, sgt.calib.c_str()); - out << line << endl; + for (int i = 0; i < 3; i++) + { + snprintf(buf, sizeof(buf), "%6.4lf", sgt.L1[i]); + truncateSomething(buf); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf); + } - sprintf(line, " %20s %5s ", - sgt.antname.c_str(), - sgt.serialno.c_str()); + for (int i = 0; i < 3; i++) + { + snprintf(buf, sizeof(buf), "%6.4lf", sgt.L5[i]); + truncateSomething(buf); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf); + } - for (int i = 0; i < 3; i++) - { - sprintf(buf, "%6.4lf", sgt.L6[i]); - truncateSomething(buf); - strcat(line, buf); - strcat(line, " "); + offset += snprintf(line + offset, sizeof(line) - offset, "%s", sgt.calib.c_str()); + out << line << endl; } - - for (int i = 0; i < 3; i++) + { - sprintf(buf, "%6.4lf", sgt.L7[i]); - truncateSomething(buf); - strcat(line, buf); - strcat(line, " "); - } + char line[81]; + int offset = 0; + + offset += snprintf(line + offset, sizeof(line) - offset, " %20s %5s ", + sgt.antname.c_str(), + sgt.serialno.c_str()); - strcat(line, sgt.calib.c_str()); - out << line << endl; + for (int i = 0; i < 3; i++) + { + snprintf(buf, sizeof(buf), "%6.4lf", sgt.L6[i]); + truncateSomething(buf); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf); + } - sprintf(line, " %20s %5s ", - sgt.antname.c_str(), sgt.serialno.c_str()); + for (int i = 0; i < 3; i++) + { + snprintf(buf, sizeof(buf), "%6.4lf", sgt.L7[i]); + truncateSomething(buf); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf); + } - for (int i = 0; i < 3; i++) - { - sprintf(buf, "%6.4lf", sgt.L8[i]); - truncateSomething(buf); - strcat(line, buf); - strcat(line, " "); + offset += snprintf(line + offset, sizeof(line) - offset, "%s", sgt.calib.c_str()); + + out << line << endl; } + + { + char line[81]; + int offset = 0; + + offset += snprintf(line, sizeof(line), " %20s %5s ", + sgt.antname.c_str(), sgt.serialno.c_str()); - strcat(line, " "); - strcat(line, sgt.calib.c_str()); - out << line << endl; + for (int i = 0; i < 3; i++) + { + snprintf(buf, sizeof(buf), "%6.4lf", sgt.L8[i]); + truncateSomething(buf); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf); + } + + offset += snprintf(line + offset, sizeof(line) - offset, " "); + offset += snprintf(line + offset, sizeof(line) - offset, "%s", sgt.calib.c_str()); + out << line << endl; + } } - - out << "-SITE/GAL_PHASE_CENTER" << endl; - return 0; } @@ -1663,52 +1560,47 @@ void parse_snx_siteEccentricity(string& s) sset.ptcode = s.substr(6, 2); sset.solnnum = s.substr(9, 4); sset.typecode = s[14]; - sset.eccrs = s.substr(42, 3); + sset.rs = s.substr(42, 3); char junk[4]; int readcount = sscanf(p + 16, "%2d:%3d:%5d %2d:%3d:%5d %3s %8lf %8lf %8lf", - &sset.eccstart[0], - &sset.eccstart[1], - &sset.eccstart[2], - &sset.eccend[0], - &sset.eccend[1], - &sset.eccend[2], + &sset.start[0], + &sset.start[1], + &sset.start[2], + &sset.end[0], + &sset.end[1], + &sset.end[2], junk, - &sset.ecc[2], - &sset.ecc[1], - &sset.ecc[0]); + &sset.ecc.u(), + &sset.ecc.n(), + &sset.ecc.e()); if (readcount == 10) { // see comment at top of file - if ( sset.eccstart[0] != 0 - || sset.eccstart[1] != 0 - || sset.eccstart[2] != 0) + if ( sset.start[0] != 0 + || sset.start[1] != 0 + || sset.start[2] != 0) { - nearestYear(sset.eccstart[0]); + nearestYear(sset.start[0]); } - if ( sset.eccend[0] != 0 - || sset.eccend[1] != 0 - || sset.eccend[2] != 0) + if ( sset.end[0] != 0 + || sset.end[1] != 0 + || sset.end[2] != 0) { - nearestYear(sset.eccend[0]); + nearestYear(sset.end[0]); } - GTime time = yds2time(sset.eccstart); - theSinex.map_eccentricities[sset.sitecode][time] = sset; - } - else - { - theSinex.site_ecc_comments.push_back(s); + theSinex.map_eccentricities[sset.sitecode][sset.start] = sset; } } -int write_snx_site_eccs(ofstream& out) +void write_snx_site_eccs(ofstream& out) { - out << "+SITE/ECCENTRICITY" << endl; + Block block(out, "SITE/ECCENTRICITY"); - write_as_comments(out, theSinex.site_ecc_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [id, setMap] : theSinex.map_eccentricities) for (auto it = setMap.rbegin(); it != setMap.rend(); it++) @@ -1725,20 +1617,17 @@ int write_snx_site_eccs(ofstream& out) set.ptcode.c_str(), set.solnnum.c_str(), set.typecode, - set.eccstart[0] % 100, - set.eccstart[1], - set.eccstart[2], - set.eccend[0] % 100, - set.eccend[1], - set.eccend[2], - set.eccrs.c_str(), - set.ecc[2], - set.ecc[1], - set.ecc[0]); - } - - out << "-SITE/ECCENTRICITY" << endl; - return 0; + set.start[0] % 100, + set.start[1], + set.start[2], + set.end[0] % 100, + set.end[1], + set.end[2], + set.rs.c_str(), + set.ecc.u(), + set.ecc.n(), + set.ecc.e()); + } } bool compare_site_epochs(Sinex_solepoch_t& left, Sinex_solepoch_t& right) @@ -1801,20 +1690,17 @@ void parse_snx_epochs(string& s) nearestYear(sst.mean[0]); } } - else - { - theSinex.epochcomments.push_back(s); - } } -int write_snx_epochs(ofstream& out, std::list* pstns) +void write_snx_epochs(ofstream& out, list* pstns) { - if (theSinex.epochs_have_bias) - out << "+BIAS/EPOCHS" << endl; - else - out << "+SOLUTION/EPOCHS" << endl; + string blockName; + if (theSinex.epochs_have_bias) blockName = "BIAS/EPOCHS"; + else blockName = "SOLUTION/EPOCHS"; + + Block block(out, blockName); - write_as_comments(out, theSinex.epochcomments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& solepoch : theSinex.list_solepochs) { @@ -1823,7 +1709,7 @@ int write_snx_epochs(ofstream& out, std::list* pstns) char line[81]; - sprintf(line, " %4s %2s %4s %c %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d", + snprintf(line, sizeof(line), " %4s %2s %4s %c %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d", sst.sitecode.c_str(), sst.ptcode.c_str(), sst.solnnum.c_str(), @@ -1844,7 +1730,7 @@ int write_snx_epochs(ofstream& out, std::list* pstns) { for (auto& stn : *pstns) { - if (sst.sitecode.compare(stn.sitecode) == 0) + if (sst.sitecode.compare(stn.id_ptr->sitecode) == 0) { doit = true; break; @@ -1855,16 +1741,9 @@ int write_snx_epochs(ofstream& out, std::list* pstns) if (doit) out << line << endl; } - - if (theSinex.epochs_have_bias) - out << "-BIAS/EPOCHS" << endl; - else - out << "-SOLUTION/EPOCHS" << endl; - - return 0; } -void parse_snx_statistics(string& s) +void parse_snx_statistics(string& s) //todo aaron, is this type stuff really necessary { string stat = s.substr(1, 30); double dval; @@ -1895,28 +1774,24 @@ void parse_snx_statistics(string& s) theSinex.list_statistics.push_back(sst); } -int write_snx_statistics(ofstream& out) +void write_snx_statistics(ofstream& out) { - out << "+SOLUTION/STATISTICS" << endl; + Block block(out, "SOLUTION/STATISTICS"); - write_as_comments(out, theSinex.statistics_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& statistic : theSinex.list_statistics) { char line[81]; if (statistic.etype == 0) // int - sprintf(line, " %-30s %22d", statistic.name.c_str(), statistic.value.ival); + snprintf(line, sizeof(line), " %-30s %22d", statistic.name.c_str(), statistic.value.ival); if (statistic.etype == 1) // double - sprintf(line, " %-30s %22.15lf", statistic.name.c_str(), statistic.value.dval); + snprintf(line, sizeof(line), " %-30s %22.15lf", statistic.name.c_str(), statistic.value.dval); out << line << endl; } - - out << "-SOLUTION/STATISTICS" << endl; - - return 0; } @@ -1956,35 +1831,35 @@ void parse_snx_solutionEstimates(string& s) nearestYear(sst.refepoch[0]); } - GTime time = yds2time(sst.refepoch); - if (theSinex.primary) theSinex.map_estimates_primary [sst.sitecode][sst.type][time] = sst; - else theSinex.map_estimates [sst.sitecode][sst.type][time] = sst; + if (theSinex.primary) theSinex.map_estimates_primary [sst.sitecode][sst.type][sst.refepoch] = sst; + else theSinex.map_estimates [sst.sitecode][sst.type][sst.refepoch] = sst; - return; - } - else - { - theSinex.estimate_comments.push_back(s); } } -int write_snx_estimates_from_filter(ofstream& out) +void write_snx_estimates_from_filter(ofstream& out) { - out << "+SOLUTION/ESTIMATE" << endl; + Block block(out, "SOLUTION/ESTIMATE"); - write_as_comments(out, theSinex.estimate_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [key, index] : theSinex.kfState.kfIndexMap) { - if (key.type != KF::REC_POS) + if ( key.type != KF::REC_POS + && key.type != KF::REC_POS_RATE + && key.type != KF::STRAIN_RATE) { continue; } string type; - if (key.num == 0) type = "STAX"; - else if (key.num == 1) type = "STAY"; - else if (key.num == 2) type = "STAZ"; + if (key.type == KF::REC_POS) type = "STA?"; + else if (key.type == KF::REC_POS_RATE) type = "VEL?"; + else if (key.type == KF::STRAIN_RATE) type = "VEL?"; //todo aaron, scale is wrong, actually entirely untested + + if (key.num == 0) type[3] = 'X'; + else if (key.num == 1) type[3] = 'Y'; + else if (key.num == 2) type[3] = 'Z'; string ptcode = theSinex.map_siteids[key.str].ptcode; @@ -2002,13 +1877,9 @@ int write_snx_estimates_from_filter(ofstream& out) theSinex.kfState.x(index), sqrt( theSinex.kfState.P(index,index))); } - - out << "-SOLUTION/ESTIMATE" << endl; - - return 0; } -// int write_snx_estimates( +// void write_snx_estimates( // ofstream& out, // std::list* pstns = nullptr) // { @@ -2037,7 +1908,7 @@ int write_snx_estimates_from_filter(ofstream& out) // // char line[82]; // -// sprintf(line, " %5d %6s %4s %2s %4s %2.2d:%3.3d:%5.5d %-4s %c %21.14le %11.5le", +// snprintf(line, sizeof(line), " %5d %6s %4s %2s %4s %2.2d:%3.3d:%5.5d %-4s %c %21.14le %11.5le", // sst.index, // sst.type.c_str(), // sst.sitecode.c_str(), @@ -2055,8 +1926,6 @@ int write_snx_estimates_from_filter(ofstream& out) // } // // out << "-SOLUTION/ESTIMATE" << endl; -// -// return 0; // } @@ -2098,17 +1967,13 @@ void parse_snx_apriori(string& s) theSinex.apriori_map[sst.idx] = sst; } - else - { - theSinex.apriori_comments.push_back(s); - } } -int write_snx_apriori(ofstream& out, std::list* pstns = nullptr) +void write_snx_apriori(ofstream& out, list* pstns = nullptr) { - out << "+SOLUTION/APRIORI" << endl; + Block block(out, "SOLUTION/APRIORI"); - write_as_comments(out, theSinex.apriori_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [index, apriori] : theSinex.apriori_map) { @@ -2118,7 +1983,7 @@ int write_snx_apriori(ofstream& out, std::list* pstns = nullptr if (pstns) for (auto& stn : *pstns) { - if (sst.sitecode.compare(stn.sitecode) == 0) + if (sst.sitecode.compare(stn.id_ptr->sitecode) == 0) { doit = true; break; @@ -2130,7 +1995,7 @@ int write_snx_apriori(ofstream& out, std::list* pstns = nullptr char line[82]; - sprintf(line, " %5d %6s %4s %2s %4s %2.2d:%3.3d:%5.5d %-4s %c %21.14le %11.5le", + snprintf(line, sizeof(line), " %5d %6s %4s %2s %4s %2.2d:%3.3d:%5.5d %-4s %c %21.14le %11.5le", sst.idx, sst.param_type.c_str(), sst.sitecode.c_str(), @@ -2146,23 +2011,24 @@ int write_snx_apriori(ofstream& out, std::list* pstns = nullptr out << line << endl; } - - out << "-SOLUTION/APRIORI" << endl; - - return 0; } -int write_snx_apriori_from_stations( +void write_snx_apriori_from_stations( ofstream& out, map& stationMap) { - out << "+SOLUTION/APRIORI" << endl; + Block block(out, "SOLUTION/APRIORI"); -// write_as_comments(out, theSinex.apriori_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); int index = 1; for (auto& [id, rec] : stationMap) { + if (rec.invalid) + { + continue; + } + auto& sst = rec.snx; for (int i = 0; i < 3; i++) @@ -2174,7 +2040,7 @@ int write_snx_apriori_from_stations( index, type.c_str(), id.c_str(), - sst.ptcode.c_str(), + sst.id_ptr->ptcode.c_str(), 1, //sst.solnnum.c_str(), rec.aprioriTime[0] % 100, rec.aprioriTime[1], @@ -2184,55 +2050,9 @@ int write_snx_apriori_from_stations( rec.aprioriPos(i),// sst.param, rec.aprioriVar(i)); - index ++; - } - } - - out << "-SOLUTION/APRIORI" << endl; - - return 0; -} - -bool compare_normals(Sinex_solneq_t& left, Sinex_solneq_t& right) -{ - int comp = left.site.compare(right.site); - - if (!comp) - { - // compare first on type, then on epoch - if (left.ptype.compare(right.ptype) == 0) - { - comp = time_compare(left.epoch, right.epoch); - } - else - { - int ltype = 0; - int rtype = 0; - string s = trim(left.ptype); - - try - { - ltype = E_Estimate::_from_string(s.c_str()); - } - catch (...) { } - - s = trim(right.ptype); - - try - { - rtype = E_Estimate::_from_string(s.c_str()); - } - catch (...) { } - - - comp = ltype - rtype; + index++; } } - - if (!comp) - comp = left.param - right.param; - - return (comp < 0); } void parse_snx_normals(string& s) @@ -2269,26 +2089,22 @@ void parse_snx_normals(string& s) theSinex.list_normal_eqns.push_back(sst); } - else - { - theSinex.normal_eqns_comments.push_back(s); - } } -int write_snx_normal(ofstream& out, std::list* pstns = nullptr) +void write_snx_normal(ofstream& out, list* pstns = nullptr) { - out << "+SOLUTION/NORMAL_EQUATION_VECTOR" << endl; + Block block(out, "SOLUTION/NORMAL_EQUATION_VECTOR"); - write_as_comments(out, theSinex.normal_eqns_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& sst : theSinex.list_normal_eqns) { - bool doit = (pstns == NULL); + bool doit = (pstns == nullptr); if (pstns) for (auto& stn : *pstns) { - if (sst.site.compare(stn.sitecode) != 0) + if (sst.site.compare(stn.id_ptr->sitecode) != 0) { doit = true; break; @@ -2300,7 +2116,7 @@ int write_snx_normal(ofstream& out, std::list* pstns = nullptr) char line[81]; - sprintf(line, " %5d %6s %4s %2s %4s %2.2d:%3.3d:%5.5d %-4s %c %21.15lf", + snprintf(line, sizeof(line), " %5d %6s %4s %2s %4s %2.2d:%3.3d:%5.5d %-4s %c %21.15lf", sst.param, sst.ptype.c_str(), sst.site.c_str(), @@ -2315,10 +2131,6 @@ int write_snx_normal(ofstream& out, std::list* pstns = nullptr) out << line << endl; } - - out << "-SOLUTION/NORMAL_EQUATION_VECTOR" << endl; - - return 0; } // Just use indices of row and col for the comparison @@ -2373,10 +2185,18 @@ void parse_snx_matrix(string& s)//, matrix_type type, matrix_value value) theSinex.matrix_map[mat_type][mat_value].push_back(smt); } -// else -// { -// theSinex.matrix_comments.push_back(s); -// } +} + +void parseSinexEstimates( + string& s) +{ + +} + +void parseSinexEstimateMatrix( + string& s) +{ + } void write_snx_matrices_from_filter( @@ -2393,13 +2213,20 @@ void write_snx_matrices_from_filter( value_strings[COVARIANCE] = "COVA"; value_strings[INFORMATION] = "INFO"; + // just check we have some values to play with first + if (theSinex.kfState.P.rows() == 0) + return; + for (auto& mt : {ESTIMATE}) for (auto& mv : {COVARIANCE}) { //print header - tracepdeex(0, out, "+%s %c %s\n", type_strings[mt], 'L', mt == NORMAL_EQN ? "" : value_strings[mv]); + char header[128]; + snprintf(header, sizeof(header), "%s %c %s", type_strings[mt], 'L', mt == NORMAL_EQN ? "" : value_strings[mv]); - write_as_comments(out, theSinex.matrix_comments); + Block block(out, header); + + write_as_comments(out, theSinex.blockComments[block.blockName]); MatrixXd& P = theSinex.kfState.P; @@ -2430,13 +2257,60 @@ void write_snx_matrices_from_filter( tracepdeex(0, out, "\n"); } - - //print footer - tracepdeex(0, out, "-%s %c %s\n", type_strings[mt], 'L', mt == NORMAL_EQN ? "" : value_strings[mv]); } } -void parse_snx_precode(string& s) + +void parse_snx_dataHandling(string& s) +{ + Sinex_datahandling_t sdt; + + sdt.sitecode = s.substr(1, 4); //4 - CDP ID + sdt.ptcode = s.substr(6, 2); //2 - physical monument used at the site + sdt.unit = s.substr(9, 4); //4 - units of estimate + sdt.t = s.substr(14, 1); //1 + sdt.m = s.substr(42, 1); //1 + if (s.size() >= 75+4) + sdt.comments = s.substr(75, 4); //4 + + int readcount = sscanf(s.c_str() + 16, "%2d:%3d:%5d", + &sdt.epochstart[0], + &sdt.epochstart[1], + &sdt.epochstart[2]); + readcount += sscanf(s.c_str() + 29, "%2d:%3d:%5d", + &sdt.epochend[0], + &sdt.epochend[1], + &sdt.epochend[2]); + + sscanf(s.c_str() + 44, "%12lf %7lf %9lf", + &sdt.estimate, + &sdt.stddev, + &sdt.estrate); + + if (readcount >= 6) //just need a start & stop time + { + // see comment at top of file + if ( sdt.epochstart[0] != 0 + ||sdt.epochstart[1] != 0 + ||sdt.epochstart[2] != 0) + { + nearestYear(sdt.epochstart[0]); + } + if ( sdt.epochend[0] != 0 + ||sdt.epochend[1] != 0 + ||sdt.epochend[2] != 0) + { + nearestYear(sdt.epochend[0]); + } + + GTime time = sdt.epochstart; + + assert(sdt.m.size() == 1); //todo, aaron whats this doing + theSinex.map_data_handling[sdt.sitecode][sdt.m.front()][time] = sdt; + } +} + +void parse_snx_precode(string& s) { Sinex_precode_t snt; @@ -2446,24 +2320,20 @@ void parse_snx_precode(string& s) theSinex.list_precessions.push_back(snt); } -int write_snx_precodes(ofstream& out) +void write_snx_precodes(ofstream& out) { - out << "+PRECESSION/DATA" << endl; + Block block(out, "PRECESSION/DATA"); - write_as_comments(out, theSinex.precession_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& spt : theSinex.list_precessions) { char line[81]; - sprintf(line, " %8s %s", spt.precesscode.c_str(), spt.comment.c_str()); + snprintf(line, sizeof(line), " %8s %s", spt.precesscode.c_str(), spt.comment.c_str()); out << line << endl; } - - out << "-PRECESSION/DATA" << endl; - - return 0; } void parse_snx_nutcode(string& s) @@ -2476,11 +2346,11 @@ void parse_snx_nutcode(string& s) theSinex.list_nutcodes.push_back(snt); } -int write_snx_nutcodes(ofstream& out) +void write_snx_nutcodes(ofstream& out) { - out << "+NUTATION/DATA" << endl; + Block block(out, "NUTATION/DATA"); - write_as_comments(out, theSinex.nutation_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& nutcode : theSinex.list_nutcodes) { @@ -2488,14 +2358,10 @@ int write_snx_nutcodes(ofstream& out) char line[81]; - sprintf(line, " %8s %s", snt.nutcode.c_str(), snt.comment.c_str()); + snprintf(line, sizeof(line), " %8s %s", snt.nutcode.c_str(), snt.comment.c_str()); out << line << endl; } - - out << "-NUTATION/DATA" << endl; - - return 0; } void parse_snx_sourceids(string& s) @@ -2510,11 +2376,11 @@ void parse_snx_sourceids(string& s) theSinex.list_source_ids.push_back(ssi); } -int write_snx_sourceids(ofstream& out) +void write_snx_sourceids(ofstream& out) { - out << "+SOURCE/ID" << endl; + Block block(out, "SOURCE/ID"); - write_as_comments(out, theSinex.sourceid_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& source_id : theSinex.list_source_ids) { @@ -2522,14 +2388,10 @@ int write_snx_sourceids(ofstream& out) char line[101]; - sprintf(line, " %4s %8s %16s %s", ssi.source.c_str(), ssi.iers.c_str(), ssi.icrf.c_str(), ssi.comments.c_str()); + snprintf(line, sizeof(line), " %4s %8s %16s %s", ssi.source.c_str(), ssi.iers.c_str(), ssi.icrf.c_str(), ssi.comments.c_str()); out << line << endl; } - - out << "-SOURCE/ID" << endl; - - return 0; } bool compare_satids(Sinex_satid_t& left, Sinex_satid_t& right) @@ -2576,23 +2438,19 @@ void parse_snx_satelliteIds(string& s) theSinex.list_satids.push_back(sst); } - else - { - theSinex.satid_comments.push_back(s); - } } -int write_snx_satids(ofstream& out) +void write_snx_satids(ofstream& out) { - out << "+SATELLITE/ID" << endl; + Block block(out, "SATELLITE/ID"); - write_as_comments(out, theSinex.satid_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& ssi : theSinex.list_satids) { char line[101]; - sprintf(line, " %4s %2s %9s %c %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %20s", + snprintf(line, sizeof(line), " %4s %2s %9s %c %2.2d:%3.3d:%5.5d %2.2d:%3.3d:%5.5d %20s", ssi.svn.c_str(), ssi.prn.c_str() + 1, ssi.cospar.c_str(), @@ -2607,31 +2465,11 @@ int write_snx_satids(ofstream& out) out << line << endl; } - - out << "-SATELLITE/ID" << endl; - - return 0; -} - -bool compare_satidents(Sinex_satident_t& left, Sinex_satident_t& right) -{ - char constleft = left.svn[0]; - char constright = right.svn[0]; - int nleft = atoi(left.svn.substr(1).c_str()); - int nright = atoi(right.svn.substr(1).c_str()); - int comp; - - if (constleft == constright) - comp = nleft - nright; - else - comp = constleft - constright; - - return (comp <= 0); } void parse_snx_satelliteIdentifiers(string& s) { - Sinex_satident_t sst; + SinexSatIdentity sst; sst.svn = s.substr(1, 4); sst.cospar = s.substr(6, 9); @@ -2639,20 +2477,22 @@ void parse_snx_satelliteIdentifiers(string& s) sst.blocktype = s.substr(23, 15); sst.comment = s.substr(39); - theSinex.list_satidents.push_back(sst); + theSinex.satIdentityMap[sst.svn] = sst; + + nav.blocktypeMap[sst.svn] = sst.blocktype; } -int write_snx_satidents(ofstream& out) +void write_snx_satidents(ofstream& out) { - out << "+SATELLITE/IDENTIFIER" << endl; + Block block(out, "SATELLITE/IDENTIFIER"); - write_as_comments(out, theSinex.satident_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); - for (auto& ssi : theSinex.list_satidents) + for (auto& [svn, ssi] : theSinex.satIdentityMap) { char line[101]; - sprintf(line, " %4s %9s %6d %-15s %s", + snprintf(line, sizeof(line), " %4s %9s %6d %-15s %s", ssi.svn.c_str(), ssi.cospar.c_str(), ssi.category, @@ -2661,10 +2501,6 @@ int write_snx_satidents(ofstream& out) out << line << endl; } - - out << "-SATELLITE/IDENTIFIER" << endl; - - return 0; } // NB this DOES not compare by PRN!! @@ -2704,24 +2540,22 @@ void parse_snx_satprns(string& s) { // No need to adjust years since for satellites the year is 4 digits ... theSinex.list_satprns.push_back(spt); - } - else - { - theSinex.satprn_comments.push_back(s); + + nav.svnMap[SatSys(spt.prn.c_str())][spt.start] = spt.svn; } } -int write_snx_satprns(ofstream& out) +void write_snx_satprns(ofstream& out) { - out << "+SATELLITE/PRN" << endl; + Block block(out, "SATELLITE/PRN"); - write_as_comments(out, theSinex.satprn_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); char line[101]; for (auto& spt : theSinex.list_satprns) { - sprintf(line, " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %3s %s", + snprintf(line, sizeof(line), " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %3s %s", spt.svn.c_str(), spt.start[0], spt.start[1], @@ -2734,25 +2568,19 @@ int write_snx_satprns(ofstream& out) out << line << endl; } - - out << "-SATELLITE/PRN" << endl; - - return 0; } bool compare_freq_channels(Sinex_satfreqchn_t& left, Sinex_satfreqchn_t& right) { // start by comparing SVN... - char constleft = left.svn[0]; - char constright = right.svn[0]; - int nleft = atoi(left.svn.substr(1).c_str()); + char constleft = left .svn[0]; + char constright = right .svn[0]; + int nleft = atoi(left .svn.substr(1).c_str()); int nright = atoi(right.svn.substr(1).c_str()); int result; - if (constleft == constright) - result = nleft - nright; - else - result = constleft - constright; + if (constleft == constright) result = nleft - nright; + else result = constleft - constright; // then by start time if the same space vehicle for (int i = 0; i < 3; i++) @@ -2783,23 +2611,19 @@ void parse_snx_satfreqchannels(string& s) // No need to adjust years since for satellites the year is 4 digits ... theSinex.list_satfreqchns.push_back(sfc); } - else - { - theSinex.satfreqchn_comments.push_back(s); - } } -int write_snx_satfreqchn(ofstream& out) +void write_snx_satfreqchn(ofstream& out) { - out << "+SATELLITE/FREQUENCY_CHANNEL" << endl; + Block block(out, "SATELLITE/FREQUENCY_CHANNEL"); - write_as_comments(out, theSinex.satfreqchn_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& sfc : theSinex.list_satfreqchns) { char line[101]; - sprintf(line, " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %3d %s", + snprintf(line, sizeof(line), " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %3d %s", sfc.svn.c_str(), sfc.start[0], sfc.start[1], @@ -2812,18 +2636,14 @@ int write_snx_satfreqchn(ofstream& out) out << line << endl; } - - out << "-SATELLITE/FREQUENCY_CHANNEL" << endl; - - return 0; } bool compare_satmass(Sinex_satmass_t& left, Sinex_satmass_t& right) { // start by comparing SVN... - char constleft = left.svn[0]; - char constright = right.svn[0]; - int nleft = atoi(left.svn.substr(1).c_str()); + char constleft = left .svn[0]; + char constright = right .svn[0]; + int nleft = atoi(left .svn.substr(1).c_str()); int nright = atoi(right.svn.substr(1).c_str()); int result; @@ -2859,25 +2679,22 @@ void parse_snx_satelliteMass(string& s) if (readcount == 7) { // No need to adjust years since for satellites the year is 4 digits ... - theSinex.list_satmasses.push_back(ssm); - } - else - { - theSinex.satmass_comments.push_back(s); + theSinex.map_satmasses[ssm.svn][ssm.start] = ssm; } } -int write_snx_satmass(ofstream& out) +void write_snx_satmass(ofstream& out) { - out << "+SATELLITE/MASS" << endl; + Block block(out, "SATELLITE/MASS"); - write_as_comments(out, theSinex.satmass_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); - for (auto& ssm : theSinex.list_satmasses) + for (auto& [svn, ssmMap] : theSinex.map_satmasses) + for (auto& [time, ssm] : ssmMap) { char line[101]; - sprintf(line, " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %9.3lf %s", + snprintf(line, sizeof(line), " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %9.3lf %s", ssm.svn.c_str(), ssm.start[0], ssm.start[1], @@ -2890,10 +2707,6 @@ int write_snx_satmass(ofstream& out) out << line << endl; } - - out << "-SATELLITE/MASS" << endl; - - return 0; } bool compare_satcom(Sinex_satcom_t& left, Sinex_satcom_t& right) @@ -2941,23 +2754,19 @@ void parse_snx_satelliteComs(string& s) // No need to adjust years since for satellites the year is 4 digits ... theSinex.list_satcoms.push_back(sct); } - else - { - theSinex.satcom_comments.push_back(s); - } } -int write_snx_satcom(ofstream& out) +void write_snx_satcom(ofstream& out) { - out << "+SATELLITE/COM" << endl; + Block block(out, "SATELLITE/COM"); - write_as_comments(out, theSinex.satcom_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& sct : theSinex.list_satcoms) { char line[101]; - sprintf(line, " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %9.4lf %9.4lf %9.4lf %s", + snprintf(line, sizeof(line), " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %9.4lf %9.4lf %9.4lf %s", sct.svn.c_str(), sct.start[0], sct.start[1], @@ -2972,10 +2781,6 @@ int write_snx_satcom(ofstream& out) out << line << endl; } - - out << "-SATELLITE/COM" << endl; - - return 0; } bool compare_satecc(Sinex_satecc_t& left, Sinex_satecc_t& right) @@ -3017,23 +2822,19 @@ void parse_snx_satelliteEccentricities(string& s) { theSinex.list_sateccs.push_back(set); } - else - { - theSinex.satecc_comments.push_back(s); - } } -int write_snx_satecc(ofstream& out) +void write_snx_satecc(ofstream& out) { - out << "+SATELLITE/ECCENTRICITY" << endl; + Block block(out, "SATELLITE/ECCENTRICITY"); - write_as_comments(out, theSinex.satecc_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& set : theSinex.list_sateccs) { char line[101]; - sprintf(line, " %4s %-20s %c %9.4lf %9.4lf %9.4lf %s", + snprintf(line, sizeof(line), " %4s %-20s %c %9.4lf %9.4lf %9.4lf %s", set.svn.c_str(), set.equip.c_str(), set.type, @@ -3044,10 +2845,6 @@ int write_snx_satecc(ofstream& out) out << line << endl; } - - out << "-SATELLITE/ECCENTRICITY" << endl; - - return 0; } bool compare_satpower(Sinex_satpower_t& left, Sinex_satpower_t& right) @@ -3091,25 +2888,22 @@ void parse_snx_satellitePowers(string& s) if (readcount == 7) { // No need to adjust years since for satellites the year is 4 digits ... - theSinex.list_satpowers.push_back(spt); - } - else - { - theSinex.satpower_comments.push_back(s); + theSinex.map_satpowers[spt.svn][spt.start] = spt; } } -int write_snx_satpower(ofstream& out) +void write_snx_satpower(ofstream& out) { - out << "+SATELLITE/TX_POWER" << endl; + Block block(out, "SATELLITE/TX_POWER"); - write_as_comments(out, theSinex.satpower_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); - for (auto& spt : theSinex.list_satpowers) + for (auto& [svn, sptmap] : theSinex.map_satpowers) + for (auto& [time, spt] : sptmap) { char line[101]; - sprintf(line, " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %4d %s", + snprintf(line, sizeof(line), " %4s %4.4d:%3.3d:%5.5d %4.4d:%3.3d:%5.5d %4d %s", spt.svn.c_str(), spt.start[0], spt.start[1], @@ -3122,10 +2916,6 @@ int write_snx_satpower(ofstream& out) out << line << endl; } - - out << "-SATELLITE/TX_POWER" << endl; - - return 0; } bool compare_satpc(Sinex_satpc_t& left, Sinex_satpc_t& right) @@ -3181,17 +2971,13 @@ void parse_snx_satellitePhaseCenters(string& s) { theSinex.list_satpcs.push_back(spt); } - else - { - theSinex.satpc_comments.push_back(s); - } } -int write_snx_satpc(ofstream& out) +void write_snx_satpc(ofstream& out) { - out << "+SATELLITE/PHASE_CENTER" << endl; + Block block(out, "SATELLITE/PHASE_CENTER"); - write_as_comments(out, theSinex.satpc_comments); + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& spt : theSinex.list_satpcs) { @@ -3202,13 +2988,13 @@ int write_snx_satpc(ofstream& out) freq2line[22] = '\0'; if (spt.freq2 != ' ') - sprintf(freq2line, "%c %6.4lf %6.4lf %6.4lf", + snprintf(freq2line, sizeof(freq2line), "%c %6.4lf %6.4lf %6.4lf", spt.freq2, spt.zxy2[0], spt.zxy2[1], spt.zxy2[2]); - sprintf(line, " %4s %c %6.4lf %6.4lf %6.4lf %22s %-10s %c %c", + snprintf(line, sizeof(line), " %4s %c %6.4lf %6.4lf %6.4lf %22s %-10s %c %c", spt.svn.c_str(), spt.freq, spt.zxy[0], @@ -3221,10 +3007,31 @@ int write_snx_satpc(ofstream& out) out << line << endl; } +} + +void parseSinexSatYawRates(string& line) +{ + SinexSatYawRate entry; - out << "-SATELLITE/PHASE_CENTER" << endl; + entry.svn = line.substr(1, 4); + entry.comment = line.substr(51); - return 0; + int readCount = sscanf(line.c_str() + 6, "%4d:%3d:%5d %4d:%3d:%5d %c %8lf", + &entry.start[0], + &entry.start[1], + &entry.start[2], + &entry.stop[0], + &entry.stop[1], + &entry.stop[2], + &entry.yawBias, + &entry.maxYawRate); + + entry.maxYawRate *= D2R; + + if (readCount == 8) + { + theSinex.satYawRateMap[entry.svn][entry.start] = entry; + } } void nullFunction(string& s) @@ -3232,7 +3039,7 @@ void nullFunction(string& s) } -int read_sinex( +int readSinex( string filepath, bool primary) { @@ -3260,9 +3067,7 @@ int read_sinex( void (*parseFunction)(string&) = nullFunction; - list* com_ptr = nullptr; string closure = ""; - list comments; while (filestream) { @@ -3282,7 +3087,7 @@ int read_sinex( } else if (line[0] == '*') { - comments.push_back(line); + //comment } else if (line[0] == '-') { @@ -3295,13 +3100,6 @@ int read_sinex( << "Error: Incorrect section closure line encountered: " << closure << " != " << line << endl; } - - if (com_ptr) - { - //merge all comments that came during the block into the block's comment list. - com_ptr->merge(comments); - comments.clear(); - } } else if (line[0] == ' ') { @@ -3315,55 +3113,51 @@ int read_sinex( //prepare closing line for comparison closure = line; closure[0] = '-'; - string lineName = line.substr(0, line.find(' ')); - if (lineName == "+FILE/REFERENCE" ) { parseFunction = parse_snx_reference; com_ptr = nullptr; } - else if (lineName == "+FILE/COMMENT" ) { parseFunction = parse_snx_comment; com_ptr = nullptr; } - else if (lineName == "+INPUT/HISTORY" ) { parseFunction = parse_snx_inputHistory; com_ptr = &theSinex.historyComments; } - else if (lineName == "+INPUT/FILES" ) { parseFunction = parse_snx_inputFiles; com_ptr = &theSinex.filesComments; } - else if (lineName == "+INPUT/ACKNOWLEDGEMENTS" ) { parseFunction = parse_snx_acknowledgements; com_ptr = &theSinex.ackComments; } - else if (lineName == "+INPUT/ACKNOWLEDGMENTS" ) { parseFunction = parse_snx_acknowledgements; com_ptr = &theSinex.ackComments; } - else if (lineName == "+NUTATION/DATA" ) { parseFunction = parse_snx_nutcode; com_ptr = &theSinex.nutation_comments; } - else if (lineName == "+PRECESSION/DATA" ) { parseFunction = parse_snx_precode; com_ptr = &theSinex.precession_comments; } - else if (lineName == "+SOURCE/ID" ) { parseFunction = parse_snx_sourceids; com_ptr = &theSinex.sourceid_comments; } - else if (lineName == "+SITE/ID" ) { parseFunction = parse_snx_siteIds; com_ptr = &theSinex.siteIdcomments; } - else if (lineName == "+SITE/DATA" ) { parseFunction = parse_snx_siteData; com_ptr = &theSinex.siteDatacomments; } - else if (lineName == "+SITE/RECEIVER" ) { parseFunction = parse_snx_receivers; com_ptr = &theSinex.receivercomments; } - else if (lineName == "+SITE/ANTENNA" ) { parseFunction = parse_snx_antennas; com_ptr = &theSinex.antennacomments; } - else if (lineName == "+SITE/GPS_PHASE_CENTER" ) { parseFunction = parse_gps_phaseCenters; com_ptr = &theSinex.gps_pc_comments; } - else if (lineName == "+SITE/GAL_PHASE_CENTER" ) { parseFunction = parse_gal_phaseCenters; com_ptr = &theSinex.gal_pc_comments; } - else if (lineName == "+SITE/ECCENTRICITY" ) { parseFunction = parse_snx_siteEccentricity; com_ptr = &theSinex.site_ecc_comments; } - else if (lineName == "+BIAS/EPOCHS" ) { parseFunction = parse_snx_epochs; com_ptr = &theSinex.epochcomments; } - else if (lineName == "+SOLUTION/EPOCHS" ) { parseFunction = parse_snx_epochs; com_ptr = &theSinex.epochcomments; } - else if (lineName == "+SOLUTION/STATISTICS" ) { parseFunction = parse_snx_statistics; com_ptr = &theSinex.statistics_comments; } - else if (lineName == "+SOLUTION/ESTIMATE" ) { parseFunction = parse_snx_solutionEstimates; com_ptr = &theSinex.estimate_comments; } - else if (lineName == "+SOLUTION/APRIORI" ) { parseFunction = parse_snx_apriori; com_ptr = &theSinex.apriori_comments; } - else if (lineName == "+SOLUTION/NORMAL_EQUATION_VECTOR" ) { parseFunction = parse_snx_normals; com_ptr = &theSinex.normal_eqns_comments; } - else if (lineName == "+SOLUTION/MATRIX_ESTIMATE" ) { parseFunction = parse_snx_matrix; com_ptr = nullptr; } - else if (lineName == "+SOLUTION/MATRIX_APRIORI" ) { parseFunction = parse_snx_matrix; com_ptr = nullptr; } - else if (lineName == "+SOLUTION/NORMAL_EQUATION_MATRIX" ) { parseFunction = parse_snx_matrix; com_ptr = nullptr; } - else if (lineName == "+SATELLITE/IDENTIFIER" ) { parseFunction = parse_snx_satelliteIdentifiers; com_ptr = &theSinex.satident_comments; } - else if (lineName == "+SATELLITE/PRN" ) { parseFunction = parse_snx_satprns; com_ptr = &theSinex.satprn_comments; } - else if (lineName == "+SATELLITE/MASS" ) { parseFunction = parse_snx_satelliteMass; com_ptr = &theSinex.satmass_comments; } - else if (lineName == "+SATELLITE/FREQUENCY_CHANNEL" ) { parseFunction = parse_snx_satfreqchannels; com_ptr = &theSinex.satfreqchn_comments; } - else if (lineName == "+SATELLITE/TX_POWER" ) { parseFunction = parse_snx_satellitePowers; com_ptr = &theSinex.satpower_comments; } - else if (lineName == "+SATELLITE/COM" ) { parseFunction = parse_snx_satelliteComs; com_ptr = &theSinex.satcom_comments; } - else if (lineName == "+SATELLITE/ECCENTRICITY" ) { parseFunction = parse_snx_satelliteEccentricities; com_ptr = &theSinex.satecc_comments; } - else if (lineName == "+SATELLITE/PHASE_CENTER" ) { parseFunction = parse_snx_satellitePhaseCenters; com_ptr = &theSinex.satpc_comments; } - else if (lineName == "+SATELLITE/ID" ) { parseFunction = parse_snx_satelliteIds; com_ptr = &theSinex.satid_comments; } + + trimCut(line); + if (line == "+FILE/REFERENCE" ) { parseFunction = parse_snx_reference; } + else if (line == "+FILE/COMMENT" ) { parseFunction = nullFunction; } + else if (line == "+INPUT/HISTORY" ) { parseFunction = parse_snx_inputHistory; } + else if (line == "+INPUT/FILES" ) { parseFunction = parse_snx_inputFiles; } + else if (line == "+INPUT/ACKNOWLEDGEMENTS" ) { parseFunction = parse_snx_acknowledgements; } + else if (line == "+INPUT/ACKNOWLEDGMENTS" ) { parseFunction = parse_snx_acknowledgements; } + else if (line == "+NUTATION/DATA" ) { parseFunction = parse_snx_nutcode; } + else if (line == "+PRECESSION/DATA" ) { parseFunction = parse_snx_precode; } + else if (line == "+SOURCE/ID" ) { parseFunction = parse_snx_sourceids; } + else if (line == "+SITE/ID" ) { parseFunction = parse_snx_siteIds; } + else if (line == "+SITE/DATA" ) { parseFunction = parse_snx_siteData; } + else if (line == "+SITE/RECEIVER" ) { parseFunction = parse_snx_receivers; } + else if (line == "+SITE/ANTENNA" ) { parseFunction = parse_snx_antennas; } + else if (line == "+SITE/GPS_PHASE_CENTER" ) { parseFunction = parse_gps_phaseCenters; } + else if (line == "+SITE/GAL_PHASE_CENTER" ) { parseFunction = parse_gal_phaseCenters; } + else if (line == "+SITE/ECCENTRICITY" ) { parseFunction = parse_snx_siteEccentricity; } + else if (line == "+BIAS/EPOCHS" ) { parseFunction = parse_snx_epochs; } + else if (line == "+SOLUTION/EPOCHS" ) { parseFunction = parse_snx_epochs; } + else if (line == "+SOLUTION/STATISTICS" ) { parseFunction = parse_snx_statistics; } + else if (line == "+SOLUTION/ESTIMATE" ) { parseFunction = parse_snx_solutionEstimates; } + else if (line == "+SOLUTION/APRIORI" ) { parseFunction = parse_snx_apriori; } + else if (line == "+SOLUTION/NORMAL_EQUATION_VECTOR" ) { parseFunction = parse_snx_normals; } + else if (line == "+SOLUTION/MATRIX_ESTIMATE" ) { parseFunction = parse_snx_matrix; } + else if (line == "+SOLUTION/MATRIX_APRIORI" ) { parseFunction = parse_snx_matrix; } + else if (line == "+SOLUTION/NORMAL_EQUATION_MATRIX" ) { parseFunction = parse_snx_matrix; } + else if (line == "+SOLUTION/DATA_HANDLING" ) { parseFunction = parse_snx_dataHandling; } + else if (line == "+SATELLITE/IDENTIFIER" ) { parseFunction = parse_snx_satelliteIdentifiers; } + else if (line == "+SATELLITE/PRN" ) { parseFunction = parse_snx_satprns; } + else if (line == "+SATELLITE/MASS" ) { parseFunction = parse_snx_satelliteMass; } + else if (line == "+SATELLITE/FREQUENCY_CHANNEL" ) { parseFunction = parse_snx_satfreqchannels; } + else if (line == "+SATELLITE/TX_POWER" ) { parseFunction = parse_snx_satellitePowers; } + else if (line == "+SATELLITE/COM" ) { parseFunction = parse_snx_satelliteComs; } + else if (line == "+SATELLITE/ECCENTRICITY" ) { parseFunction = parse_snx_satelliteEccentricities;} + else if (line == "+SATELLITE/PHASE_CENTER" ) { parseFunction = parse_snx_satellitePhaseCenters; } + else if (line == "+SATELLITE/ID" ) { parseFunction = parse_snx_satelliteIds; } + else if (line == "+SATELLITE/YAW_BIAS_RATE" ) { parseFunction = parseSinexSatYawRates; } else { BOOST_LOG_TRIVIAL(error) - << "Error: error unknown header line: " << line << endl; + << "Error: unknown header line: " << line << endl; failure = 1; } - - if (com_ptr) - { - //merge all comments that came before the block into the block's comment list. - com_ptr->merge(comments); - comments.clear(); - } // int i; // failure = read_snx_matrix (filestream, NORMAL_EQN, INFORMATION, c); break; @@ -3432,6 +3226,7 @@ int read_sinex( } else if (line[0] == '%') { + trimCut(line); if (line != "%ENDSNX") { // error in file. report it. @@ -3449,16 +3244,12 @@ int read_sinex( } theSinex.list_satpcs. sort(compare_satpc); - theSinex.list_satpowers. sort(compare_satpower); theSinex.list_sateccs. sort(compare_satecc); theSinex.list_solepochs. sort(compare_site_epochs); - theSinex.list_normal_eqns. sort(compare_normals); theSinex.list_sitedata. sort(compare_sitedata); theSinex.list_gps_pcs. sort(compare_gps_pc); theSinex.list_satids. sort(compare_satids); - theSinex.list_satidents. sort(compare_satidents); theSinex.list_satfreqchns. sort(compare_freq_channels); - theSinex.list_satmasses. sort(compare_satmass); theSinex.list_satprns. sort(compare_satprns); theSinex.list_satcoms. sort(compare_satcom); theSinex.list_gal_pcs. sort(compare_gal_pc); @@ -3470,14 +3261,9 @@ int read_sinex( } - - - -int write_sinex( +bool writeSinex( string filepath, - map* stationMap_ptr, - Sinex_sat_snx_t* psat, - bool comm_override) + map& stationMap) { ofstream filestream(filepath); @@ -3485,60 +3271,44 @@ int write_sinex( { return 1; } - int failure = 0; - bool domatrices = false; - // theSinex.estimate_comments. ; - - // bool comm_override = true; - - if (comm_override) - comments_override(); - write_snx_header(filestream); if (comm_override) write_pretty_line(filestream); - - if (!theSinex.refstrings. empty()) {failure += write_snx_reference (filestream); if (comm_override) write_pretty_line(filestream);} - if (!theSinex.commentstrings. empty()) {failure += write_snx_comments (filestream); if (comm_override) write_pretty_line(filestream);} - if (!theSinex.inputHistory. empty()) {failure += write_snx_input_history (filestream); if (comm_override) write_pretty_line(filestream);} - if (!theSinex.inputFiles. empty()) {failure += write_snx_input_files (filestream); if (comm_override) write_pretty_line(filestream);} - if (!theSinex.acknowledgements. empty()) {failure += write_snx_acknowledgements (filestream); if (comm_override) write_pretty_line(filestream);} - - if (psat == NULL) - { - if (!theSinex.map_siteids. empty()) {failure += write_snx_siteids (filestream); if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.list_sitedata. empty()) {failure += write_snx_sitedata (filestream); if (comm_override) write_pretty_line(filestream);} - if (!theSinex.map_receivers. empty()) {failure += write_snx_receivers (filestream); if (comm_override) write_pretty_line(filestream);} - if (!theSinex.map_antennas. empty()) {failure += write_snx_antennas (filestream); if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.list_gps_pcs. empty()) {failure += write_snx_gps_pcs (filestream); if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.list_gal_pcs. empty()) {failure += write_snx_gal_pcs (filestream); if (comm_override) write_pretty_line(filestream);} - if (!theSinex.map_eccentricities. empty()) {failure += write_snx_site_eccs (filestream); if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.list_solepochs. empty()) {failure += write_snx_epochs (filestream); if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.list_statistics. empty()) {failure += write_snx_statistics(filestream); if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.estimates_map. empty()) failure += write_snx_estimates (filestream); - write_snx_estimates_from_filter (filestream); if (comm_override) write_pretty_line(filestream); -// if (!theSinex.apriori_map. empty()) {failure += write_snx_apriori (filestream);if (comm_override) write_pretty_line(filestream);} - write_snx_apriori_from_stations (filestream, *stationMap_ptr); -// if (!theSinex.list_normal_eqns. empty()) {failure += write_snx_normal (filestream); if (comm_override) write_pretty_line(filestream);} - - -// for (int i = 0; i < 3; i++) -// domatrices |= !theSinex.matrix_map[i].empty(); -// -// if (domatrices) - { -// write_snx_matrices(filestream, stationListPointer); - write_snx_matrices_from_filter(filestream); if (comm_override) write_pretty_line(filestream); - } - } - - if (psat == nullptr) - { -// if (!theSinex.list_source_ids. empty()) {failure += write_snx_sourceids (filestream);if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.list_nutcodes. empty()) {failure += write_snx_nutcodes (filestream);if (comm_override) write_pretty_line(filestream);} -// if (!theSinex.list_precessions. empty()) {failure += write_snx_precodes (filestream);if (comm_override) write_pretty_line(filestream);} + + comments_override(); + + write_snx_header(filestream); + + if (!theSinex.refstrings. empty()) { write_snx_reference (filestream);} + if (!theSinex.blockComments["FILE/COMMENT"].empty()) { write_snx_comments (filestream);} + if (!theSinex.inputHistory. empty()) { write_snx_input_history (filestream);} + if (!theSinex.inputFiles. empty()) { write_snx_input_files (filestream);} + if (!theSinex.acknowledgements. empty()) { write_snx_acknowledgements (filestream);} + + if (!theSinex.map_siteids. empty()) { write_snx_siteids (filestream);} +// if (!theSinex.list_sitedata. empty()) { write_snx_sitedata (filestream);} + if (!theSinex.map_receivers. empty()) { write_snx_receivers (filestream);} + if (!theSinex.map_antennas. empty()) { write_snx_antennas (filestream);} +// if (!theSinex.list_gps_pcs. empty()) { write_snx_gps_pcs (filestream);} +// if (!theSinex.list_gal_pcs. empty()) { write_snx_gal_pcs (filestream);} + if (!theSinex.map_eccentricities. empty()) { write_snx_site_eccs (filestream);} +// if (!theSinex.list_solepochs. empty()) { write_snx_epochs (filestream);} +// if (!theSinex.list_statistics. empty()) { write_snx_statistics (filestream);} +// if (!theSinex.estimates_map. empty()) write_snx_estimates (filestream); + write_snx_estimates_from_filter (filestream); +// if (!theSinex.apriori_map. empty()) { write_snx_apriori (filestream);} + write_snx_apriori_from_stations (filestream, stationMap); +// if (!theSinex.list_normal_eqns. empty()) { write_snx_normal (filestream);} + + { +// write_snx_matrices (filestream, stationListPointer); + write_snx_matrices_from_filter (filestream); } +// if (!theSinex.list_source_ids. empty()) { write_snx_sourceids (filestream);} +// if (!theSinex.list_nutcodes. empty()) { write_snx_nutcodes (filestream);} +// if (!theSinex.list_precessions. empty()) { write_snx_precodes (filestream);} + filestream << "%ENDSNX" << endl; - return failure; + return false; } @@ -3604,55 +3374,32 @@ int sinex_check_add_ga_reference(string solType, string peaVer, bool isTrop) struct utsname buf; char line[81]; - sprintf(line, " %-18s %s", "DESCRIPTION", "Geoscience Australia"); - theSinex.refstrings.push_back(line); - - sprintf(line, " %-18s %s", "OUTPUT", solType.c_str()); - theSinex.refstrings.push_back(line); - - sprintf(line, " %-18s %s", "CONTACT", "npi@ga.gov.au"); - theSinex.refstrings.push_back(line); - - sprintf(line, " %-18s %s", "SOFTWARE", ("Ginan PEA Version " + peaVer).c_str()); - theSinex.refstrings.push_back(line); + snprintf(line, sizeof(line), " %-18s %s", "DESCRIPTION", "Geoscience Australia"); theSinex.refstrings.push_back(line); + snprintf(line, sizeof(line), " %-18s %s", "OUTPUT", solType.c_str()); theSinex.refstrings.push_back(line); + snprintf(line, sizeof(line), " %-18s %s", "CONTACT", "npi@ga.gov.au"); theSinex.refstrings.push_back(line); + snprintf(line, sizeof(line), " %-18s %s", "SOFTWARE", ("Ginan PEA Version " + peaVer).c_str()); theSinex.refstrings.push_back(line); int result = uname(&buf); if (result == 0) { - int len; - sprintf(line, " %-18s ", "HARDWARE"); - len = strlen(line); + int offset = 0; - if ((len + strlen(buf.sysname)) < 80) - { - strcat(line, buf.sysname); - strcat(line, " "); - len = strlen(line); - } - - if ((len + strlen(buf.release)) < 80) - { - strcat(line, buf.release); - strcat(line, " "); - len = strlen(line); - } - - if ((len + strlen(buf.version)) < 80) - { - strcat(line, buf.version); - strcat(line, " "); - } + offset += snprintf(line + offset, sizeof(line) - offset, " %-18s ", "HARDWARE"); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf.sysname); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf.release); + offset += snprintf(line + offset, sizeof(line) - offset, "%s ", buf.version); + theSinex.refstrings.push_back(line); } - sprintf(line, " %-18s %s", "INPUT", "RINEX"); + snprintf(line, sizeof(line), " %-18s %s", "INPUT", "RINEX"); theSinex.refstrings.push_back(line); - if(isTrop) + if (isTrop) { - sprintf(line, " %-18s %03d", "VERSION NUMBER", 1); //note: increment if the processing is modified in a way that might lead to a different error characteristics of the product - see trop snx specs + snprintf(line, sizeof(line), " %-18s %03d", "VERSION NUMBER", 1); //note: increment if the processing is modified in a way that might lead to a different error characteristics of the product - see trop snx specs theSinex.refstrings.push_back(line); } return 0; @@ -3670,95 +3417,21 @@ void sinex_add_acknowledgement(const string& who, const string& description) void sinex_add_comment(const string what) { - theSinex.commentstrings.push_back(what); + theSinex.blockComments["FILE/COMMENT"].push_back(what); } -void sinex_add_file(const string& who, const GTime& when, const string& filename, const string& description) +void sinex_add_file(const string& who, const GTime& time, const string& filename, const string& description) { - double ep[6]; - int yds[3]; Sinex_input_file_t sif; - time2epoch(when, ep); - epoch2yds(ep, yds); - - - for (int i = 0; i < 3; i++) - sif.epoch[i] = yds[i]; - - sif.agency = who; - sif.file = filename; - sif.description = description; + sif.yds = time; + sif.agency = who; + sif.file = filename; + sif.description = description; theSinex.inputFiles.push_back(sif); } -void sinex_report( - Trace& trace) -{ - trace << "count of refstrings = " << theSinex.refstrings .size() << endl; - trace << "count of comments = " << theSinex.commentstrings .size() << endl; - trace << "count of history comments = " << theSinex.historyComments .size() << endl; - trace << "count of input histories = " << theSinex.inputHistory .size() << endl; - trace << "count of file comments = " << theSinex.filesComments .size() << endl; - trace << "count of input files = " << theSinex.inputFiles .size() << endl; - trace << "count of acknowledgement comments = " << theSinex.ackComments .size() << endl; - trace << "count of acknowledgements = " << theSinex.acknowledgements .size() << endl; - - trace << "count of site id comments = " << theSinex.siteIdcomments .size() << endl; - trace << "count of site ids = " << theSinex.map_siteids .size() << endl; - trace << "count of site data comments = " << theSinex.siteDatacomments .size() << endl; - trace << "count of site datas = " << theSinex.list_sitedata .size() << endl; - trace << "count of receiver comments = " << theSinex.receivercomments .size() << endl; - trace << "count of receivers = " << theSinex.map_receivers .size() << endl; - trace << "count of antenna comments = " << theSinex.antennacomments .size() << endl; - trace << "count of antenna sites = " << theSinex.map_antennas .size() << endl; - trace << "count of site eccentricity comments = " << theSinex.site_ecc_comments .size() << endl; - trace << "count of site eccentricities = " << theSinex.map_eccentricities .size() << endl; - trace << "count of GPS phase centre comments = " << theSinex.gps_pc_comments .size() << endl; - trace << "count of GPS phase centres = " << theSinex.list_gps_pcs .size() << endl; - trace << "count of GAL phase cnetre comments = " << theSinex.gal_pc_comments .size() << endl; - trace << "count of GAL phase centres = " << theSinex.list_gal_pcs .size() << endl; - - trace << "solutions have bias = " << theSinex.epochs_have_bias << endl; - trace << "count of epoch comments = " << theSinex.epochcomments .size() << endl; - trace << "count of solution epochs = " << theSinex.list_solepochs .size() << endl; - trace << "count of statistics comments = " << theSinex.statistics_comments .size() << endl; - trace << "count of statistics = " << theSinex.list_statistics .size() << endl; - trace << "count of estimate comments = " << theSinex.estimate_comments .size() << endl; - trace << "count of estimates = " << theSinex.map_estimates .size() << endl; - trace << "count of apriori comments = " << theSinex.apriori_comments .size() << endl; - trace << "count of aprioris = " << theSinex.apriori_map .size() << endl; - trace << "count of normal equation comments = " << theSinex.normal_eqns_comments.size() << endl; - trace << "count of normal equations = " << theSinex.list_normal_eqns .size() << endl; - trace << "count of matrix comments = " << theSinex.matrix_comments .size() << endl; - - trace << "count of satid comments = " << theSinex.satid_comments .size() << endl; - trace << "count of sat IDs = " << theSinex.list_satids .size() << endl; - trace << "count of satident comments = " << theSinex.satident_comments .size() << endl; - trace << "count of sat idents = " << theSinex.list_satidents .size() << endl; - trace << "count of prn comments = " << theSinex.satprn_comments .size() << endl; - trace << "count of prns = " << theSinex.list_satprns .size() << endl; - trace << "count of freq channel comments = " << theSinex.satfreqchn_comments .size() << endl; - trace << "count of freq channels = " << theSinex.list_satfreqchns .size() << endl; - trace << "count of mass comments = " << theSinex.satmass_comments .size() << endl; - trace << "count of satmasses = " << theSinex.list_satmasses .size() << endl; - trace << "count of COM comments = " << theSinex.satcom_comments .size() << endl; - trace << "count of sat COMs = " << theSinex.list_satcoms .size() << endl; - trace << "count of sat ecc comments = " << theSinex.satecc_comments .size() << endl; - trace << "count of sat eccentricities = " << theSinex.list_sateccs .size() << endl; - trace << "count of sat power comments = " << theSinex.satpower_comments .size() << endl; - trace << "count of sat powers = " << theSinex.list_satpowers .size() << endl; - trace << "count of sat phase centre comments = " << theSinex.satpc_comments .size() << endl; - trace << "count of sat phase centres = " << theSinex.list_satpcs .size() << endl; - trace << "count of source ID comments = " << theSinex.sourceid_comments .size() << endl; - trace << "count of source IDs = " << theSinex.list_source_ids .size() << endl; - trace << "count of nutation comments = " << theSinex.nutation_comments .size() << endl; - trace << "count of nutations = " << theSinex.list_nutcodes .size() << endl; - trace << "count of precession_comments = " << theSinex.precession_comments .size() << endl; - trace << "count of precessions = " << theSinex.list_precessions .size() << endl; -} - int sinex_site_count() { return theSinex.map_siteids.size(); @@ -3766,7 +3439,7 @@ int sinex_site_count() int sinex_sat_count() { - int result = theSinex.list_satidents.size(); + int result = theSinex.satIdentityMap.size(); if (result == 0) result = theSinex.list_satids.size(); @@ -3775,182 +3448,143 @@ int sinex_sat_count() } void setRestrictiveEndTime( - int current[3], - int potential[3]) + UYds& current, + UYds& potential) { - static int zeros[3] = {}; - - if (time_compare(current, zeros) == 0) - { - //current is zero, just use the new version for the end time - for (int i = 0; i < 3; i++) - { - current[i] = potential[i]; - } - - return; - } - - if (time_compare(potential, zeros) == 0) - { - //potential time is zero, thats not restrictive, keep the current time - - return; - } + UYds zeros; - if (time_compare(potential, current) < 0) - { - //potential end time is more restrictive - for (int i = 0; i < 3; i++) - { - current[i] = potential[i]; - } - - return; - } + if (time_compare(current, zeros) == 0) { current = potential; return; } //current is zero, just use the new version for the end time + if (time_compare(potential, zeros) == 0) { return; } //potential time is zero, thats not restrictive, keep the current time + if (time_compare(potential, current) < 0) { current = potential; return; } //potential end time is more restrictive } -// return value is 0 for success. Otherwise the value indicates the section where data was not found. -// 1 = siteid -// 2 = recevier -// 3 = antenna -// 4 = eccentricity -// 5 = gps phase center -// 6 = estimate -E_SnxDataMissing getstnsnx( - string station, - int yds[3], - Sinex_stn_snx_t& stn_snx) +GetSnxResult getStnSnx( + string station, + GTime time, + SinexRecData& recSnx) { - bool found = false; - E_SnxDataMissing retval = E_SnxDataMissing::NONE_MISSING; + recSnx = SinexRecData(); + recSnx.start = time; - stn_snx = {}; + GetSnxResult result; + + bool found = false; - for (int i = 0; i < 3; i++) - { - stn_snx.start[i] = yds[i]; - } - // search siteids for station (not time dependent) auto siteIdIt = theSinex.map_siteids.find(station); if (siteIdIt != theSinex.map_siteids.end()) { - auto& siteId = siteIdIt->second; + auto& [dummy, siteId] = *siteIdIt; + + recSnx.id_ptr = &siteId; + siteId.used = true; - stn_snx.sitecode = station; - stn_snx.ptcode = siteId.ptcode; - stn_snx.monuid = siteId.domes; - stn_snx.typecode = siteId.typecode; - stn_snx.desc = siteId.desc; - stn_snx.long_deg = siteId.long_deg; - stn_snx.long_min = siteId.long_min; - stn_snx.long_sec = siteId.long_sec; - stn_snx.lat_deg = siteId.lat_deg; - stn_snx.lat_min = siteId.lat_min; - stn_snx.lat_sec = siteId.lat_sec; - stn_snx.height = siteId.height; - found = true; } - - if (!found) - return E_SnxDataMissing::SITE_ID; - - found = false; - - - GTime time = yds2time(yds); + else + { + result.failureSiteId = true; + } auto receiverIt = theSinex.map_receivers.find(station); if (receiverIt != theSinex.map_receivers.end()) { - auto& recTimeMap = receiverIt->second; + auto& [dummy, recTimeMap] = *receiverIt; - auto timeRec_it = recTimeMap.lower_bound(time); - if (timeRec_it != recTimeMap.end()) + auto timeRecIt = recTimeMap.lower_bound(time); + if (timeRecIt != recTimeMap.end()) { - auto& receiver = timeRec_it->second; + auto& [dummy, receiver] = *timeRecIt; receiver.used = true; - stn_snx.rectype = receiver.rectype; - stn_snx.recsn = receiver.recsn; - stn_snx.recfirm = receiver.recfirm; + recSnx.rec_ptr = &receiver; + found = true; // get next next start time as end time for this aspect - if (timeRec_it != recTimeMap.begin()) + if (timeRecIt != recTimeMap.begin()) { - timeRec_it--; - auto& nextReceiver = timeRec_it->second; + timeRecIt--; + auto& nextReceiver = timeRecIt->second; - setRestrictiveEndTime(receiver.recend, nextReceiver.recstart); + setRestrictiveEndTime(receiver.end, nextReceiver.start); } - setRestrictiveEndTime(stn_snx.start, receiver.recend); + setRestrictiveEndTime(recSnx.start, receiver.end); } } if (!found) - retval = E_SnxDataMissing::RECEIVER; + result.failureReceiver = true; found = false; - auto ant_it = theSinex.map_antennas[station].lower_bound(time); - if (ant_it != theSinex.map_antennas[station].end()) + auto antIt = theSinex.map_antennas.find(station); + if (antIt != theSinex.map_antennas.end()) { - auto& antenna = ant_it->second; - found = true; - antenna.used = true; - - stn_snx.anttype = antenna.anttype; - stn_snx.antsn = antenna.antsn; + auto& [dummy, antTimeMap] = *antIt; - // get next next start time as end time for this aspect - if (ant_it != theSinex.map_antennas[station].begin()) + auto antIt2 = theSinex.map_antennas[station].lower_bound(time); + if (antIt2 != theSinex.map_antennas[station].end()) { - ant_it--; - auto& nextAntenna = ant_it->second; + auto& [dummy, antenna] = *antIt2; + + found = true; + antenna.used = true; + + recSnx.ant_ptr = &antenna; + + // get next next start time as end time for this aspect + if (antIt2 != theSinex.map_antennas[station].begin()) + { + antIt2--; + auto& [dummy, nextAntenna] = *antIt2; + + setRestrictiveEndTime(antenna.end, nextAntenna.start); + } - setRestrictiveEndTime(antenna.antend, nextAntenna.antstart); + setRestrictiveEndTime(recSnx.start, antenna.end); } - - setRestrictiveEndTime(stn_snx.start, antenna.antend); } if (!found) - retval = E_SnxDataMissing::ANTENNA; + result.failureAntenna = true; found = false; - auto ecc_it = theSinex.map_eccentricities[station].lower_bound(time); - if (ecc_it != theSinex.map_eccentricities[station].end()) + auto eccIt = theSinex.map_eccentricities.find(station); + if (eccIt != theSinex.map_eccentricities.end()) { - auto& eccentricity = ecc_it->second; - found = true; - eccentricity.used = true; + auto& [dummy, eccMap] = *eccIt; - stn_snx.eccrs = eccentricity.eccrs; - - for (int i = 0; i < 3; i++) - stn_snx.ecc[i] = eccentricity.ecc[i]; - - // get next next start time as end time for this aspect - if (ecc_it != theSinex.map_eccentricities[station].begin()) + auto eccIt2 = eccMap.lower_bound(time); + if (eccIt2 != theSinex.map_eccentricities[station].end()) { - ecc_it--; - auto& nextEcc = ecc_it->second; + auto& [dummy, ecc] = *eccIt2; + + found = true; - setRestrictiveEndTime(eccentricity.eccend, nextEcc.eccstart); + ecc.used = true; + + recSnx.ecc_ptr = &ecc; + + // get next next start time as end time for this aspect + if (eccIt2 != theSinex.map_eccentricities[station].begin()) + { + eccIt2--; + auto& [dummy, nextEcc] = *eccIt2; + + setRestrictiveEndTime(ecc.end, nextEcc.start); + } + + setRestrictiveEndTime(recSnx.stop, ecc.end); } - - setRestrictiveEndTime(stn_snx.stop, eccentricity.eccend); } - + if (!found) - retval = E_SnxDataMissing::ECCENTRICITY; + result.failureEccentricity = true; -// found = false; + found = false; // // for (auto& gps_pcs : theSinex.list_gps_pcs) // { @@ -3970,7 +3604,7 @@ E_SnxDataMissing getstnsnx( // } if (!found) - retval = E_SnxDataMissing::GPS_PHASE_CENTRE; + result.failurePhaseCentre = true; for (auto estMap_ptr : { &theSinex.map_estimates_primary, @@ -3980,9 +3614,9 @@ E_SnxDataMissing getstnsnx( found = true; auto& estMap_ = *estMap_ptr; + for (string type : {"STA? ", "VEL? "}) for (int i = 0; i < 3; i++) { - string type = "STA? "; type[3] = 'X' + i; auto& estMap = estMap_[station][type]; @@ -3990,9 +3624,11 @@ E_SnxDataMissing getstnsnx( Sinex_solestimate_t* estimate_ptr = nullptr; auto est_it = estMap.lower_bound(time); + GTime refEpoch = {}; if (est_it != estMap.end()) { estimate_ptr = &est_it->second; + refEpoch = est_it->first; // get next next start time as end time for this aspect if (est_it != estMap.begin()) @@ -4000,7 +3636,7 @@ E_SnxDataMissing getstnsnx( est_it--; auto& nextEst = est_it->second; - setRestrictiveEndTime(stn_snx.stop, nextEst.refepoch); + setRestrictiveEndTime(recSnx.stop, nextEst.refepoch); } } else @@ -4010,16 +3646,26 @@ E_SnxDataMissing getstnsnx( if (est_Rit == estMap.rend()) { //actually theres no estimate for this thing - found = false; + if (type.substr(0,3) == "STA") + found = false; break; } estimate_ptr = &est_Rit->second; + refEpoch = est_Rit->first; } estimate_ptr->used = true; - stn_snx.pos(i) = estimate_ptr->estimate; - stn_snx.primary = estimate_ptr->primary; + if (type.substr(0,3) == "STA") + { + recSnx.pos(i) = estimate_ptr->estimate; + recSnx.primary = estimate_ptr->primary; + recSnx.refEpoch= refEpoch; + } + else if (type.substr(0,3) == "VEL") + { + recSnx.vel(i) = estimate_ptr->estimate; + } } if (found) @@ -4029,11 +3675,252 @@ E_SnxDataMissing getstnsnx( } } - + recSnx.pos += recSnx.vel * (time - recSnx.refEpoch).to_double() / 86400 / 365.25; //meters per year + if (found == false) { - retval = E_SnxDataMissing::ESTIMATE; + result.failureEstimate = true; + } + + return result; +} + +GetSnxResult getSatSnx( + string prn, + GTime time, + SinexSatSnx& satSnx) +{ + bool found = false; + + GetSnxResult result; + + satSnx = SinexSatSnx(); + satSnx.start = time; + + // search satprns for prn and svn (not time dependent) + for (auto& satPrn : theSinex.list_satprns) + { + GTime startTime = satPrn.start; + GTime stopTime = satPrn.stop; + + if ( satPrn.prn == prn + && (time - startTime) .to_double() >= 0 + &&( (time - stopTime) .to_double() <= 0 + ||satPrn.stop[0] == 0)) + { + satSnx.prn = prn; + satSnx.svn = satPrn.svn; + //todo: start and stop time + found = true; + break; + } + } + + if (!found) + result.failurePRN = true; + + // sat identifiers + auto itr = theSinex.satIdentityMap.find(satSnx.svn); + if (itr != theSinex.satIdentityMap.end()) + { + auto& [dummy, satId] = *itr; + + satSnx.id_ptr = &satId; + + } + else + { + result.failureSatId = true; + } + + + //todo: add other sections for satellite in theSinex + + // sat com + found = false; + for (auto& satCom : theSinex.list_satcoms) + { + GTime startTime = satCom.start; + GTime stopTime = satCom.stop; + + if ( satCom.svn == satSnx.svn + && (time - startTime) .to_double() >= 0 + &&( (time - stopTime) .to_double() <= 0 + ||satCom.stop[0] == 0)) + { + for (int i = 0; i < 3; i++) + satSnx.com[i] = satCom.com[i]; + //todo: start and stop time + found = true; + } + } + + if (!found) + result.failureCOM = true;; + + found = false; + + // sat eccentricities + for (auto& satEcc : theSinex.list_sateccs) + { + if (satEcc.svn == satSnx.svn) + { + E_EccType eccType; + switch (satEcc.type) + { + case 'P': { found = true; satSnx.ecc_ptrs[E_EccType::P_ANT] = &satEcc; break; } + case 'L': { found = true; satSnx.ecc_ptrs[E_EccType::L_LRA] = &satEcc; break; } + default: + { + BOOST_LOG_TRIVIAL(error) << "Unknown satellite eccentricity type"; + break; + } + } + } + } + + if (!found) + result.failureEccentricity = true; + + //todo: add other sections for satellite in theSinex + + return result; +} + +void getRecBias( + string station, + UYds yds, + map& stationBias) +{ + GTime time = yds; + + // Loop through "M" models codes - Ref: https://ilrs.dgfi.tum.de/fileadmin/data_handling/ILRS_Data_Handling_File.snx + const std::vector codes = {'R', 'T', 'X', 'E', 'H', 'P', 'U', 'N', 'Q', 'V'}; + for (auto code : codes) + { + bool excludeFlag = false; + auto it = theSinex.map_data_handling[station][code].lower_bound(time); + if (it == theSinex.map_data_handling[station][code].end()) + { + continue; + } + + double unitsFactor = 1; + auto& dataHandling = it->second; //todo aaron + + const GTime stopTime = dataHandling.epochend; + + if (time >= stopTime) + { + continue; + } + + switch (code) + { + case 'R': // Range bias to be applied, no estimation of bias + if (dataHandling.unit == "mm ") unitsFactor = 1e-3; + else + BOOST_LOG_TRIVIAL(error) << "Error: unhandled units in " << __FUNCTION__ << ", model code R : " << dataHandling.unit << endl; + break; + case 'T': // Time bias in ms or µs & µs/d (T2L2) to be applied, NOT estimated + if (dataHandling.unit == "ms ") unitsFactor = 1e-3; + else if (dataHandling.unit == "us ") unitsFactor = 1e-6; + else + BOOST_LOG_TRIVIAL(error) << "Error: unhandled units in " << __FUNCTION__ << ", model code T: " << dataHandling.unit << endl; + break; + case 'E': // Estimation of range bias, known a priori values are given + if (dataHandling.unit == "mm ") unitsFactor = 1e-3; + else + BOOST_LOG_TRIVIAL(error) << "Error: unhandled units in " << __FUNCTION__ << ", model code R: " << dataHandling.unit << endl; + break; + case 'H': // humidity error (correction in %) + if (dataHandling.unit == "% ") unitsFactor = 1e-3; + else + BOOST_LOG_TRIVIAL(error) << "Error: unhandled units in " << __FUNCTION__ << ", model code H: " << dataHandling.unit << endl; + break; + case 'P': // pressure bias (correction in mB) + if (dataHandling.unit == "mB ") unitsFactor = 1; + else + BOOST_LOG_TRIVIAL(error) << "Error: unhandled units in " << __FUNCTION__ << ", model code P: " << dataHandling.unit << endl; + break; + case 'U': // Estimation of time bias in ms + if (dataHandling.unit == "ms ") unitsFactor = 1e-3; + else if (dataHandling.unit == "us ") unitsFactor = 1e-6; + else + BOOST_LOG_TRIVIAL(error) << "Error: unhandled units in " << __FUNCTION__ << ", model code U: " << dataHandling.unit << endl; + break; + // Equivalent to 'E': + case 'C': // Target signature bias, correction different from standard + case 'S': // Stanford event counter bias + unitsFactor = 0; + break; + // Data to be excluded: + case 'X': // Exclude/delete data + case 'N': // unreliable station, should not be used in routine processing + case 'Q': // Station with data in quarantine, not to be used in official products + case 'V': // Station with not validated coordinates, not solving for biases + excludeFlag = true; + break; + } + + if (excludeFlag) + { + stationBias[code] = 1; // non-zero = true + } + else if (dataHandling.ptcode == "--") + { + stationBias[code] = dataHandling.estimate * unitsFactor; + + if ( code == 'T' + &&dataHandling.comments == "drif") // comments only read in first 4 characters + { + GTime end = dataHandling.epochend; + GTime start = dataHandling.epochstart; + + double interval = (end - start).to_double(); + GTime midInterval = start + interval / 2; + + double numDays = (time - midInterval).to_double() / S_IN_DAY; + + stationBias[code] += dataHandling.estrate * numDays * 1e-6; // estrate units in us/day + } + } + else + { + BOOST_LOG_TRIVIAL(error) << "Error: unhandled ptcode in getRecBias: " << dataHandling.ptcode << endl; + } } +} - return retval; + +/** Get yaw rate sinex entry for sat + */ +bool getSnxSatMaxYawRate( + string svn, + GTime& time, + double& maxYawRate) +{ + auto itr = theSinex.satYawRateMap[svn].lower_bound(time); + if (itr == theSinex.satYawRateMap[svn].end()) + return false; + + auto& [dummy, entry] = *itr; + maxYawRate = entry.maxYawRate; + + return true; +} + +bool getSnxSatBlockType( + string svn, + string& blockType) +{ + auto itr = theSinex.satIdentityMap.find(svn); + if (itr == theSinex.satIdentityMap.end()) + return false; + + auto& [dummy, entry] = *itr; + blockType = entry.blocktype; + + return true; } + diff --git a/src/cpp/common/sinex.hpp b/src/cpp/common/sinex.hpp index df67790dd..fc8266d3c 100644 --- a/src/cpp/common/sinex.hpp +++ b/src/cpp/common/sinex.hpp @@ -1,6 +1,5 @@ -#ifndef NEWSNX_H -#define NEWSNX_H +#pragma once #include @@ -29,76 +28,70 @@ struct Sinex_input_history_t char code; // '+' for input, '-' for output double fmt; // format (d4.2) string create_agency; // 3 - int create_time[3]; // yr:doy:sod + UYds create_time; string data_agency; // 3 - int start[3]; //yr::doy:sod - int stop[3]; //yr:doy:sod + UYds start; + UYds stop; char obs_tech; // int num_estimates; char constraint; string contents; // S/O/E/T/C/A separated characters may have trailing blanks -} ; +}; -//=============================================================================== /* files structure (optional) * ------------------------------------------------------------------------------ +INPUT/FILES *AGC EPOCH_______ FILE_NAME____________________ _FILE_DESCRIPTION_______________ -XXX YR:DOY:SOD.. ABCDEFGHIJKLMNOPQRSTUVWXYZABC ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF + XXX YR:DOY:SOD.. ABCDEFGHIJKLMNOPQRSTUVWXYZABC ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF */ struct Sinex_input_file_t { - string agency; // 3 - int epoch[3]; // yr:doy:sod - string file; // 29 - name of file - string description; // 32 - description of file -} ; + string agency; // 3 + UYds yds; + string file; // 29 - name of file + string description; // 32 - description of file +}; -//=============================================================================== /* acknowledgements structure (optional) * ------------------------------------------------------------------------------ +INPUT/ACKNOWLEDGEMENTS *AGC DESCRIPTION_________________________________________________________________ -XXX BLAH BLAH BLAH ... + XXX BLAH BLAH BLAH ... */ struct Sinex_ack_t { string agency; // 3 string description; // 75 -} ; +}; -//=============================================================================== /* nut-data structure (mandatory when VLBI) * ------------------------------------------------------------------------------ +NUTATION/DATA *CODE____ COMMENTS_______________________________________________________________ -NUTCODE BLAH BLAH BLAH ... + NUTCODE BLAH BLAH BLAH ... */ struct Sinex_nutcode_t { string nutcode; // 8 - one of IAU1980/IERS1996/IAU2000a/IAU2000b string comment; // 70 - description of model -} ; +}; -//=============================================================================== /* precess-data structure (mandatory when VLBI) * ------------------------------------------------------------------------------ +PRECESSION/DATA *CODE____ COMMENTS_______________________________________________________________ -PRECODE BLAH BLAH BLAH ... + PRECODE BLAH BLAH BLAH ... */ struct Sinex_precode_t { string precesscode; // 8 - one of IAU1976/IERS1996 string comment; // 70 - description of model -} ; +}; -//=============================================================================== /* source id structure (mandatory when VLBI) -* ------------------------------------------------------------------------------ +SOURCE/ID *CODE IERSDESC ICRF_DESCRIPTION COMMENTS_________________________________________ -CCCC DESCRIPT DESCRIPTION BLAH BLAH BLAH ... + CCCC DESCRIPT DESCRIPTION BLAH BLAH BLAH ... */ struct Sinex_source_id_t { @@ -106,115 +99,103 @@ struct Sinex_source_id_t string iers; // 8 - 8 char designation string icrf; // 16 - 16 char designation string comments; // 58 -} ; +}; -//=============================================================================== // site/id block structurea (mandatory for GNSS) /* -*------------------------------------------------------------------------------- +SITE/ID *CODE PT __DOMES__ T _STATION DESCRIPTION__ _LONGITUDE_ _LATITUDE__ HEIGHT_ */ -//=============================================================================== struct Sinex_siteid_t { - string sitecode; // station (4) - string ptcode; // physical monument used at the site (2) - char typecode; // observation technique {C,D,L,M,P,or R} - string domes; // domes number unique monument num (9) - string desc; // site description eg town/city (22) - int long_deg; // longitude degrees (uint16_t) east is positive - int long_min; // - double long_sec; // - int lat_deg; // latitude degrees north is positive - int lat_min; // uint8_t - double lat_sec; // float - double height; // - bool used = false; -} ; + string sitecode; // station (4) + string ptcode; // physical monument used at the site (2) + char typecode; // observation technique {C,D,L,M,P,or R} + string domes; // domes number unique monument num (9) + string desc; // site description eg town/city (22) + int lon_deg; // longitude degrees (uint16_t) east is positive + int lon_min; // + double lon_sec; // + int lat_deg; // latitude degrees north is positive + int lat_min; // uint8_t + double lat_sec; // float + double height; // + bool used = false; +}; -//=============================================================================== // site/data block structure (optional) /* -*------------------------------------------------------------------------------- +SITE/DATA *CODE PT SOLN CODE PT SOLN O START___ STOP____ AGC CREATE___ */ -//=============================================================================== struct Sinex_sitedata_t { - string site; // 4 call sign for solved parameters - string station_pt; // 2 physical - string soln_id; // 4 solution number to which this input is referred to (int?) - string sitecode; // 4 call sign from input sinex file - string site_pt; // 2 physical from above - string sitesoln; // 4 solution number for site/pt from input sinex file - char obscode; // - int start[3]; // yr:doy:sod - int stop[3]; // yr:doy:sod - string agency; // 3 - code agency of creation - int create[3]; // yr:doy:sod -} ; + string site; // 4 call sign for solved parameters + string station_pt; // 2 physical + string soln_id; // 4 solution number to which this input is referred to (int?) + string sitecode; // 4 call sign from input sinex file + string site_pt; // 2 physical from above + string sitesoln; // 4 solution number for site/pt from input sinex file + char obscode; // + UYds start; + UYds stop; + string agency; // 3 - code agency of creation + UYds create; +}; -//============================================================================= /* receiver block structre (mandatory for GNSS) +SITE/RECEIVER *CODE PT SOLN T _DATA START_ __DATA_END__ ___RECEIVER_TYPE____ _S/N_ _FIRMWARE__ -ALBH A ---- C 93:327:70260 94:016:15540 ROGUE SNR-8C 313 Meenix 7.4 -ALBH A ---- C 94:016:15540 95:011:80100 ROGUE SNR-8000 168 SFG2 0.0 lk + ALBH A ---- C 93:327:70260 94:016:15540 ROGUE SNR-8C 313 Meenix 7.4 + ALBH A ---- C 94:016:15540 95:011:80100 ROGUE SNR-8000 168 SFG2 0.0 lk */ -//============================================================================= struct Sinex_receiver_t { - string sitecode; // station (4) - string ptcode; // physical monument used at the site (2) - string solnid; // solution number (4) or '----' - char typecode; - int recstart[3]; /* receiver start time YY:DOY:SOD */ - int recend[3]; /* receiver end time YY:DOY:SOD */ - string rectype; // receiver type (20) - string recsn; // receiver serial number (5) - string recfirm; // receiver firmware (11) + string sitecode; // station (4) + string ptcode; // physical monument used at the site (2) + string solnid; // solution number (4) or '----' + char typecode; + UYds start; // receiver start time + UYds end; // receiver end time + string type; // receiver type (20) + string sn; // receiver serial number (5) + string firm; // receiver firmware (11) bool used = false; -} ; +}; -//============================================================================= /* antenna block structure (mandatory for GNSS) +SITE/ANTENNA *CODE PT SOLN T _DATA START_ __DATA_END__ ____ANTENNA_TYPE____ _S/N_ -ALBH A ---- C 92:125:00000 94:104:74100 AOAD/M_B EMRA 91119 -ALBH A ---- C 94:104:74100 95:011:80100 AOAD/M_T EMRA 92172 + ALBH A ---- C 92:125:00000 94:104:74100 AOAD/M_B EMRA 91119 + ALBH A ---- C 94:104:74100 95:011:80100 AOAD/M_T EMRA 92172 */ -//============================================================================= struct Sinex_antenna_t { - string sitecode; - string ptcode; // physical monument used at the site (2) - string solnnum; - string calibModel; - char typecode; - int antstart[3]; /* antenna start time YY:DOY:SOD */ - int antend[3]; /* antenna end time YY:DOY:SOD */ - string anttype; /* receiver type (20)*/ - string antsn; /* receiver serial number (5)*/ + string sitecode; + string ptcode; // physical monument used at the site (2) + string solnnum; + string calibModel; + char typecode; + UYds start; /* antenna start time */ + UYds end; /* antenna end time */ + string type; /* receiver type (20)*/ + string sn; /* receiver serial number (5)*/ bool used = false; -} ; +}; -//============================================================================= /* gps phase centre block structure (mandatory for GPS) +SITE/GPS_PHASE_CENTER *ANT_TYPE_AND_MODEL__ SERNO L1UOFF L1NOFF L1EOFF L2UOFF L2NOFF L2EOFF CALIBMODEL */ struct Sinex_gps_phase_center_t { - string antname; // 20 name and model - string serialno; // 5 - double L1[3]; // UNE d6.4*3 - double L2[3]; // UNE d6.4*3 - string calib; // 10 calibration model -} ; + string antname; // 20 name and model + string serialno; // 5 + Vector3d L1; // UNE d6.4*3 + Vector3d L2; // UNE d6.4*3 + string calib; // 10 calibration model +}; -//============================================================================= /* gal phase centre block structure (mandatory for Gallileo) * NB 3 lines for each one! +SITE/GAL_PHASE_CENTER @@ -224,56 +205,51 @@ struct Sinex_gps_phase_center_t */ struct Sinex_gal_phase_center_t { - string antname; // 20 name and model - string serialno; // 5 - double L1[3]; // UNE d6.4*3 - double L5[3]; // UNE d6.4*3 - double L6[3]; // UNE d6.4*3 - double L7[3]; // UNE d6.4*3 - double L8[3]; // UNE d6.4*3 - string calib; // 10 calibration model -} ; + string antname; // 20 name and model + string serialno; // 5 + Vector3d L1; // UNE d6.4*3 + Vector3d L5; // UNE d6.4*3 + Vector3d L6; // UNE d6.4*3 + Vector3d L7; // UNE d6.4*3 + Vector3d L8; // UNE d6.4*3 + string calib; // 10 calibration model +}; -//============================================================================= /* +SITE/ECCENTRICITY *CODE PT SOLN T _DATA START_ __DATA_END__ REF __DX_U__ __DX_N__ __DX_E__ -ALBH A ---- C 92:146:00000 94:104:74100 UNE 0.1260 0.0000 0.0000 + ALBH A ---- C 92:146:00000 94:104:74100 UNE 0.1260 0.0000 0.0000 */ -//============================================================================= struct Sinex_site_ecc_t { - string sitecode; //4 - string ptcode; //2 - physical monument used at the site - string solnnum; - char typecode; - int eccstart[3]; /* ecc start time YY:DOY:SOD */ - int eccend[3]; /* ecc end time YY:DOY:SOD */ - string eccrs; /* 3 - reference system UNE (0) or XYZ (1) */ - double ecc[3]; /* eccentricity UNE or XYZ (m) d8.4*3 */ - bool used = false; -} ; + string sitecode; //4 + string ptcode; //2 - physical monument used at the site + string solnnum; + char typecode; + UYds start; /* ecc start time */ + UYds end; /* ecc end time */ + string rs; /* 3 - reference system UNE (0) or XYZ (1) */ + VectorEnu ecc; /* eccentricity UNE or XYZ (m) d8.4*3 */ + bool used = false; +}; -//============================================================================= /* +SOLUTION/EPOCHS (mandatory) *OR* +BIAS/EPOCHS (mandatory when biases are included) *CODE PT SOLN T _DATA_START_ __DATA_END__ _MEAN_EPOCH_ -ALBH A 1 C 94:002:00000 94:104:00000 94:053:00000 + ALBH A 1 C 94:002:00000 94:104:00000 94:053:00000 */ -//============================================================================= struct Sinex_solepoch_t { - string sitecode; //4 - string ptcode; //2 - physical monument used at the site - string solnnum; - char typecode; - int start[3]; //yr:doy:sod - int end[3]; //yr:doy:sod - int mean[3]; //yr:doy:sod -} ; + string sitecode; //4 + string ptcode; //2 - physical monument used at the site + string solnnum; + char typecode; + UYds start; + UYds end; + UYds mean; +}; -//============================================================================= /* +SOLUTION/STATISTICS *STAT_NAME (30 chars) value (22char double) @@ -282,14 +258,14 @@ struct Sinex_solstatistic_t { string name; short etype; // 0 = int, 1 = double - union { - int ival; - double dval; + union + { + int ival; + double dval; } value; -} ; +}; -//============================================================================= /* +SOLUTION/ESTIMATE *INDEX _TYPE_ CODE PT SOLN _REF_EPOCH__ UNIT S ___ESTIMATED_VALUE___ __STD_DEV__ @@ -300,31 +276,28 @@ struct Sinex_solstatistic_t 5 VELY ALBH A 1 10:001:00000 m/y 2 -8.46787398931193e-04 2.12080e-05 6 VELZ ALBH A 1 10:001:00000 m/y 2 -4.85721729753769e-03 2.39140e-05 */ -//============================================================================= struct Sinex_solestimate_t { - int index; - string type; //6 - string sitecode; //4 - string ptcode; //2 - physical monument used at the site - string solnnum; - int refepoch[3]; //yr:doy:sod - string unit; //4 - char constraint; - double estimate; - double stddev; + int index; + string type; //6 + string sitecode; //4 + string ptcode; //2 - physical monument used at the site + string solnnum; + UYds refepoch; + string unit; //4 + char constraint; + double estimate; + double stddev; bool primary; ///< First sinex file ever read is considered the primary source of apriori data, to be used for minimum constraints etc. bool used = false; -} ; +}; -//============================================================================= /* +SOLUTION/APRIORI *INDEX PARAMT SITE PT SOLN EPOCH_____ UNIT C PARAM________________ STD_DEV____ -12345 AAAAAA XXXX YY NNNN YR:DOY:SOD UUUU A 12345.123456789ABCDEF 1234.123456 + 12345 AAAAAA XXXX YY NNNN YR:DOY:SOD UUUU A 12345.123456789ABCDEF 1234.123456 */ -//============================================================================= struct Sinex_solapriori_t { int idx; @@ -332,20 +305,18 @@ struct Sinex_solapriori_t string sitecode; // 4 string ptcode; // 2 string solnnum; - int epoch[3]; // yr:doy:sod + UYds epoch; string unit; // 4 - select from char constraint; // for inner constraints, choose 1 double param; // d21.15 apriori parameter double stddev; // std deviation of parameter -} ; +}; -//============================================================================= /* +SOLUTION/NORMAL_EQUATION_VECTOR *PARAM PTYPE_ SITE PT SOLN EPOCH_____ UNIT C NORMAL______________ -12345 AAAAAA XXXX YY NNNN YR:DOY:SOD UUUU A 12345.123456789ABCDEF + 12345 AAAAAA XXXX YY NNNN YR:DOY:SOD UUUU A 12345.123456789ABCDEF */ -//============================================================================= struct Sinex_solneq_t { int param; // 5 index of estimated parameters @@ -353,13 +324,12 @@ struct Sinex_solneq_t string site; // 4 - station string pt; // 2 - point code string solnnum; // 4 solution number - int epoch[3]; // yr:doy:sod + UYds epoch; string unit; // 4 char constraint; // double normal; // right hand side of normal equation -} ; +}; -//============================================================================= /* +SOLUTION/MATRIX_ESTIMATE C TYPE (mandatory) +SOLUTION/MATRIX_APRIORI C TYPE (recommended) @@ -370,13 +340,38 @@ struct Sinex_solneq_t * APRIORI VALUES are 21.16lf, estimates and normal_equations are 21.14lf! *ROW__ COL__ ELEM1________________ ELEM2________________ ELEM3________________ */ -//============================================================================= struct Sinex_solmatrix_t { int row; // 5 - must match the solution/estimate row int col; // 5 - must match the solution/estimate col int numvals; double value[3]; // each d21.14 cols col, col+1, col+2 of the row +}; + + +//============================================================================= +/* ++SOLUTION/DATA_HANDLING +*CODE PT UNIT T _DATA_START_ __DATA_END__ M __E-VALUE___ STD_DEV _E-RATE__ CMNTS + 7090 -- ms A 09:344:31560 09:345:70200 T 0.90920 + 7840 -- % A 95:358:00000 95:358:86400 H -20.00 HER + 7080 -- mB A 95:065:00000 96:026:00000 P -2.10 + 1873 -- mm A 95:001:00000 00:001:00000 R -270.00 +*/ +//============================================================================= +struct Sinex_datahandling_t +{ + string sitecode; //4 - CDP ID + string ptcode; //2 - satellites these biases apply to (-- = all) + string unit; //4 - units of estimate + string t; //1 + UYds epochstart; //yr:doy:sod + UYds epochend; //yr:doy:sod + string m; //1 + double estimate; + double stddev; + double estrate; + string comments; //4 } ; typedef enum @@ -395,138 +390,128 @@ typedef enum MAX_MATRIX_VALUE } matrix_value; +typedef enum +{ + P_ANT, // P: antenna //todo: check the meaning of 'P' + L_LRA // L: laser retroreflector array +} E_EccType; + //============================================================================= // TODO: satid and satident/satprn need to be checked for consistency ... /* +SATELLITE/ID (recommmended for GNSS) *SVN_ PR COSPAR_ID O TSL TUD ANTENNA_RCV_TYPE_______________ -G001 04 1978-020A A yy:doy:sod yy:doy:sod BLAH BLAH BLAH ... + G001 04 1978-020A A yy:doy:sod yy:doy:sod BLAH BLAH BLAH ... */ -//============================================================================= struct Sinex_satid_t { string svn; // 4 string prn; // 2 string cospar; // 9 char obsCode; // - int timeSinceLaunch[3]; // yy:doy:sod a value of 0 everywhere means launched before file epoch start - int timeUntilDecom[3]; // yy:doy:sod a value of 0 everywhere mean still in commission after file epoch end + UYds timeSinceLaunch; // yy:doy:sod a value of 0 everywhere means launched before file epoch start + UYds timeUntilDecom; // yy:doy:sod a value of 0 everywhere mean still in commission after file epoch end string antRcvType; // 20 - satellite antenna receiver type -} ; +}; -//============================================================================= /* +SATELLITE/IDENTIFIER *SVN_ COSPAR_ID SatCat Block__________ Comment__________________________________ -G001 1978-020A 10684 GPS-I Launched 1978-02-22; NAVSTAR 1 + G001 1978-020A 10684 GPS-I Launched 1978-02-22; NAVSTAR 1 */ -//============================================================================= -struct Sinex_satident_t +struct SinexSatIdentity { string svn; // 4 string cospar; // 9 int category; // 6 string blocktype; // 15 string comment; // 42 -} ; +}; -//============================================================================= /* +SATELLITE/PRN *SVN_ Valid_From____ Valid_To______ PRN Comment_________________________________ -G001 1978:053:00000 1985:199:00000 G04 + G001 1978:053:00000 1985:199:00000 G04 */ -//============================================================================= struct Sinex_satprn_t { string svn; // 4 - int start[3]; //yr:doy:sod - int stop[3]; //yr:doy:sod + UYds start; //yr:doy:sod + UYds stop; //yr:doy:sod string prn; //3 string comment; // 40 -} ; +}; -//============================================================================= /* ONLY FOR GLONASS! +SATELLITE/FREQUENCY_CHANNEL *SVN_ Valid_From____ Valid_To______ chn Comment________________________________ -R701 2003:344:00000 2009:258:86399 1 [FC10] + R701 2003:344:00000 2009:258:86399 1 [FC10] */ -//============================================================================= struct Sinex_satfreqchn_t { string svn; // 4 - int start[3]; //yr:doy:sod - int stop[3]; //yr:doy:sod + UYds start; + UYds stop; int channel; string comment; // 40? -} ; +}; -//============================================================================= /* +SATELLITE/MASS *SVN_ Valid_From____ Valid_To______ Mass_[kg] Comment___________________________ -G001 1978:053:00000 0000:000:00000 455.000 GPS-I; [MA01] + G001 1978:053:00000 0000:000:00000 455.000 GPS-I; [MA01] */ -//============================================================================= struct Sinex_satmass_t { string svn; // 4 - int start[3]; //yr:doy:sod - int stop[3]; //yr/doy:sod + UYds start; + UYds stop; double mass; // kg string comment; // 40 -} ; +}; -//============================================================================= /* +SATELLITE/COM (Centre of Mass) *SVN_ Valid_From____ Valid_To______ ____X_[m] ____Y_[m] ___ Z_[m] Comment___________________________ -G001 1978:053:00000 0000:000:00000 0.0000 0.0000 0.0000 GPS-I; [CM02] + G001 1978:053:00000 0000:000:00000 0.0000 0.0000 0.0000 GPS-I; [CM02] */ -//============================================================================= struct Sinex_satcom_t { string svn; // 4 - int start[3]; //yr:doy:sod - int stop[3]; //yr:doy:sod - double com[3]; //x/y/z (metres) + UYds start; + UYds stop; + Vector3d com; //x/y/z (metres) string comment; // 40 -} ; +}; -//============================================================================= /* +SATELLITE/ECCENTRICITY *SVN_ Equipment___________ T ____X_[m] ____Y_[m] ____Z_[m] Comment___________________________ -G001 BLOCK I P 0.0000 0.0000 0.0000 GPS-I; [EG02] + G001 BLOCK I P 0.0000 0.0000 0.0000 GPS-I; [EG02] */ -//============================================================================= struct Sinex_satecc_t { - string svn; // 4 - string equip; // 20 - char type; // L or P - both can exist for the same satellite - double ecc[3]; //x/y/z - string comment; // 40 -} ; + string svn; // 4 + string equip; // 20 + char type; // L or P - both can exist for the same satellite + VectorEnu ecc; + string comment; // 40 +}; -//============================================================================= /* +SATELLITE/TX_POWER *SVN_ Valid_From____ Valid_To______ P[W] Comment________________________________ -G001 1978:053:00000 0000:000:00000 50 GPS-I; same as GPS-II/IIA; [TP04] + G001 1978:053:00000 0000:000:00000 50 GPS-I; same as GPS-II/IIA; [TP04] */ -//============================================================================= struct Sinex_satpower_t { string svn; // 4 - int start[3]; //yr:doy:sod - int stop[3]; //yr:doy:sod + UYds start; //yr:doy:sod + UYds stop; //yr:doy:sod int power; // watts string comment; // 40 -} ; +}; -//============================================================================= /* +SATELLITE/PHASE_CENTER *NB Can have more than one line if satellite transmits on more than 2 frequencies @@ -536,23 +521,37 @@ struct Sinex_satpc_t { string svn; // 4 char freq; // 1/2/5 for GPS & GLONASS, 1/5/6/7/8 for Gallileo - double zxy[3]; // metres offset from COM in the order given 3* d6.4 + Vector3d zxy; // metres offset from COM in the order given 3* d6.4 char freq2; // as above - double zxy2[3]; // as above + Vector3d zxy2; // as above string antenna; // 10 - model of antenna char type; // Phase Center Variation A(bsolute)/R(elative) char model; // F(ull)/E(levation model only) -} ; +}; + +/* ++SATELLITE/YAW_BIAS_RATE +*SVN_ Valid_From____ Valid_To______ YB Yaw Rate Comment________________________________ + G001 1978:053:00000 1985:199:00000 U 0.1999 Launched 1978-02-22; NAVSTAR 1; mass 453800. in previous svnav.dat.allgnss +*/ +struct SinexSatYawRate +{ + string svn; ///< SVN + UYds start; ///< valid from (yr:doy:sod) + UYds stop; ///< valid until (yr:doy:sod) + char yawBias; ///< yaw bias + double maxYawRate; ///< maximum yaw rate for SV (rad/s) + string comment; ///< comment field +}; -//============================================================================= /* +TROP/DESCRIPTION *_________KEYWORD_____________ __VALUE(S)_______________________________________ -ELEVATION CUTOFF ANGLE 7 -SAMPLING INTERVAL 300 -SAMPLING TROP 300 -TROP MAPPING FUNCTION WET GMF -SOLUTION_FIELDS_1 TROTOT STDDEV TGNTOT STDDEV TGETOT STDDEV + ELEVATION CUTOFF ANGLE 7 + SAMPLING INTERVAL 300 + SAMPLING TROP 300 + TROP MAPPING FUNCTION WET GMF + SOLUTION_FIELDS_1 TROTOT STDDEV TGNTOT STDDEV TGETOT STDDEV */ struct SinexTropDesc { @@ -564,16 +563,15 @@ struct SinexTropDesc bool isEmpty = true; }; -//============================================================================= /* +TROP/SOLUTION *SITE ____EPOCH___ TROTOT STDDEV TGNTOT STDDEV TGETOT STDDEV -WIDC 21:014:00000 2270.0 2.8 -0.186 0.376 0.788 0.464 + WIDC 21:014:00000 2270.0 2.8 -0.186 0.376 0.788 0.464 */ struct SinexTropSol { string site; - int epoch[3]; //yr:doy:sod + UYds yds; struct TropSolutionEntry //first Sinex_tropsol_t entry also used in TROP/DESCRIPTION block { string type; @@ -587,94 +585,72 @@ struct SinexTropSol struct Sinex { /* header block */ - string snxtype; /* SINEX file type */ - double ver; /* version */ - string create_agc; /* file creation agency */ - int filedate[3]; /* file create date as yr:doy:sod */ - string data_agc; /* data source agency */ - int solution_start_date[3]; // start date of solution as yr:doy:sod - int solution_end_date[3]; // as yr:doy:sod - char ObsCode; /* observation code */ - int numparam; /* number of estimated parameters */ - char ConstCode; /* constraint code */ - string solcont; /* solution types S O E T C A */ + string snxtype; /* SINEX file type */ + double ver; /* version */ + string create_agc; /* file creation agency */ + UYds filedate; /* file create date as yr:doy:sod */ + string data_agc; /* data source agency */ + UYds solution_start_date; // start date of solution + UYds solution_end_date; + char ObsCode; /* observation code */ + int numparam; /* number of estimated parameters */ + char ConstCode; /* constraint code */ + string solcont; /* solution types S O E T C A */ string markerName; KFState kfState; - KFState tropKFState; - list historyComments; - list filesComments; - list ackComments; + + map> blockComments; list refstrings; - list commentstrings; list inputHistory; list inputFiles; list acknowledgements; /* site stuff */ - list siteIdcomments; - list siteDatacomments; - list receivercomments; - list antennacomments; - list site_ecc_comments; - list gps_pc_comments; - list gal_pc_comments; map map_siteids; list list_sitedata; map>> map_receivers; - map>> map_antennas; + map>> map_antennas; map>> map_eccentricities; list list_gps_pcs; list list_gal_pcs; /* solution stuff - tied to sites */ - bool epochs_have_bias; - list epochcomments; - list statistics_comments; - list estimate_comments; - list apriori_comments; - list normal_eqns_comments; - list matrix_comments; - list list_solepochs; - list list_statistics; + bool epochs_have_bias; + list list_solepochs; + list list_statistics; map>>> map_estimates_primary; map>>> map_estimates; - map apriori_map; - list list_normal_eqns; + map apriori_map; + list list_normal_eqns; map> matrix_map[MAX_MATRIX_TYPE]; + map>>> map_data_handling; /* satellite stuff */ - list satpc_comments; - list satid_comments; - list satident_comments; - list satprn_comments; - list satfreqchn_comments; - list satmass_comments; - list satcom_comments; - list satecc_comments; - list satpower_comments; - list list_satpcs; - list list_satids; - list list_satidents; - list list_satprns; - list list_satfreqchns; - list list_satmasses; - list list_satcoms; - list list_sateccs; - list list_satpowers; + list list_satpcs; + list list_satids; + map satIdentityMap; + + map> map_satmasses; + map> map_satpowers; + + list list_satprns; + list list_satfreqchns; + list list_satcoms; + list list_sateccs; + map>> satYawRateMap; /* VLBI - ignored for now */ - list sourceid_comments; - list nutation_comments; - list precession_comments; - list list_source_ids; - list list_nutcodes; - list list_precessions; + list list_source_ids; + list list_nutcodes; + list list_precessions; // constructor - Sinex(bool t = false) : epochs_have_bias(t) + Sinex(bool t = false) + : epochs_have_bias(t) { + }; bool primary = false; ///< Set true while a primary sinex file is being read. @@ -682,13 +658,6 @@ struct Sinex // Troposphere Sinex data map tropSiteCoordBodyFPosMap; map tropSolFootFPosMap; - list tropSiteIdCommentList; - list tropSiteRecCommentList; - list tropSiteAntCommentList; - list tropSiteCoordCommentList; - list tropSiteEccCommentList; - list tropDescCommentList; - list tropSolCommentList; SinexTropDesc tropDesc = {}; map> tropSiteCoordMapMap; //indexed by station ID, then axis # list tropSolList; @@ -700,105 +669,72 @@ struct Sinex_stn_soln_t string unit = ""; /* parameter units */ double pos = 0; /* real position (ecef) (m)*/ double pstd = 0; /* position std (m) */ - int yds[3] = {}; /* epoch when valid */ -} ; + UYds yds; /* epoch when valid */ +}; -struct Sinex_stn_snx_t /* station-wise information */ -{ - /* ID block */ - string sitecode = ""; /* site code */ - string ptcode = ""; /* point code */ - string monuid = ""; /* monument identification */ - char typecode = 0; - string desc = ""; // site description eg town/city (22) - int long_deg = 0; // longitude degrees (uint16_t) east is positive - int long_min = 0; // - double long_sec = 0; // - int lat_deg = 0; // latitude degrees north is positive - int lat_min = 0; // uint8_t - double lat_sec = 0; // float - double height = 0; // - - int start[3] = {}; /* yr:doy:sod */ - int stop[3] = {-1,-1,-1}; /* yr:doy:sod */ - - /* receiver block */ - string rectype; // receiver type (20) - string recsn; // receiver serial number (5) - string recfirm; // receiver firmware (11) - - /* anntenna block */ - string anttype = ""; /* antenna type */ - string antsn = ""; /* antenna serial number */ - - /* phase_center block (GPS/Galileo only) */ - bool has_gps_pc = false; - double gpsl1[3] = {}; /* GPS L1 PCO UNE (m) */ - double gpsl2[3] = {}; /* GPS L2 PCO UNE (m) */ - bool has_gal_pc = false; - double gall1[3] = {}; /* GAL L1 PCO UNE (m) */ - double gall5[3] = {}; /* GAL L5 PCO UNE (m) */ - double gall6[3] = {}; /* GAL L6 PCO UNE (m) */ - double gall7[3] = {}; /* GAL L7 PCO UNE (m) */ - double gall8[3] = {}; /* GAL L8 PCO UNE (m) */ - - /* eccentricity block */ - bool has_ecc = false; - string eccrs = ""; /* reference system UNE or XYZ */ - Vector3d ecc = Vector3d::Zero(); /* eccentricity UNE or XYZ (m) */ - - - bool primary = false; ///< this position estimate is considered to come from a primary source - Vector3d pos = Vector3d::Zero(); -}; - -struct Sinex_sat_snx_t /* satellite meta data */ -{ - string svn; - string prn; - string cospar; - string blocktype; - int category; - double mass; /* kg */ - int channel; /* GLONASS ONLY */ - double com[3]; /* centre of mass offsets (m) */ - int power; /* Tx Power (watts); */ - int numeccs; /* number of eccentricities */ - char ecctype[2]; /* L or P - seems can have both */ - string eccequip[2]; /* equipment can be diff for each one */ - double eccentricity[2][3]; /* x/y/z in m */ - string antenna; - int numfreqs; /* number of phase center frequencies */ - char freq[5]; /* 1/2/5/6/7/8 (up to 5 freqs allowed) */ - double zxy[5][3]; /* phase offsets, order given by var name! */ - char pctype; - char pcmodel; - - int start[3]; /* yr:doy:sod */ - int stop[3]; /* yr:doy:sod */ -}; - -typedef map> station_map; -typedef map> satellite_map; - -int read_sinex( + +extern SinexSatIdentity dummySinexSatIdentity; +extern Sinex_satecc_t dummySinexSatEcc; + +struct SinexSatSnx /* satellite meta data */ +{ + string svn; + string prn; + SinexSatIdentity* id_ptr = &dummySinexSatIdentity; + Sinex_satecc_t* ecc_ptrs[2] ={&dummySinexSatEcc, &dummySinexSatEcc}; + double mass; /* kg */ + int channel; /* GLONASS ONLY */ + Vector3d com; /* centre of mass offsets (m) */ + int power; /* Tx Power (watts); */ + + string antenna; + int numfreqs; /* number of phase center frequencies */ + char freq[5]; /* 1/2/5/6/7/8 (up to 5 freqs allowed) */ + Vector3d zxy[5]; /* phase offsets, order given by var name! */ + char pctype; + char pcmodel; + + UYds start; + UYds stop; +}; + + +void nearestYear( + int& year); + +int readSinex( string filepath, bool primary); -int write_sinex( - string filepath, - map* stationMap = nullptr, - Sinex_sat_snx_t* psat = nullptr, - bool comm_override = true); - -E_SnxDataMissing getstnsnx (string station, int yds[3], Sinex_stn_snx_t& snx); -int getsatsnx (string prn, int yds[3], Sinex_sat_snx_t&snx); -void sinex_report(Trace& trace); -int sinex_sat_count(); -int sinex_site_count(); -long int time_compare(int left[3], int right[3]); -void sinex_update_estimate(const Sinex_stn_snx_t& station, E_Estimate e, double val, double std, int yds[3], int newidx, double defstd); -void sinex_update_matrix (matrix_type mt, matrix_value mv, int row, int col, int nvals, double val[3]); +bool writeSinex( + string filepath, + map& stationMap); + +struct SinexRecData; + +union GetSnxResult +{ + const unsigned int failure = 0; + struct + { + unsigned failureSiteId : 1; + unsigned failureReceiver : 1; + unsigned failureAntenna : 1; + unsigned failureEccentricity : 1; + unsigned failurePhaseCentre : 1; + unsigned failureEstimate : 1; + unsigned failurePRN : 1; + unsigned failureSatId : 1; + unsigned failureCOM : 1; + }; +}; + + +GetSnxResult getStnSnx (string rec, GTime time, SinexRecData& snx); +GetSnxResult getSatSnx (string prn, GTime time, SinexSatSnx& snx); + +void getRecBias (string station, UYds yds, map& stn_bias); +long int time_compare(UYds& left, UYds& right); void sinex_add_statistic(const string& what, const int value); void sinex_add_statistic(const string& what, const double value); int sinex_check_add_ga_reference(string solType, string peaVer, bool isTrop); @@ -806,12 +742,11 @@ void sinex_add_acknowledgement(const string& who, const string& description); void sinex_add_comment(const string what); void sinex_add_file(const string& who, const GTime& when, const string& filename, const string& description); -void sinex_update_header( +void updateSinexHeader( string& create_agc, - int create_date[3], string& data_agc, - int soln_start[3], - int soln_end[3], + UYds soln_start, + UYds soln_end, const char obsCode, const char constCode, string& contents, @@ -831,7 +766,7 @@ void sinexPerEpochPerStation( void outputTropSinex( string filename, GTime time, - map& stationMap, + KFState& netKfState, string markerName = "MIX", bool isSmoothed = false); @@ -840,11 +775,17 @@ void write_as_comments( std::ofstream& out, list& comments); -void write_pretty_line( +void write_snx_reference( std::ofstream& out); -int write_snx_reference( - std::ofstream& out); +bool getSnxSatMaxYawRate( + string prn, + GTime& time, + double& maxYawRate); + +bool getSnxSatBlockType( + string svn, + string& blockType); extern Sinex theSinex; // the one and only sinex object. @@ -852,4 +793,3 @@ void getStationsFromSinex( map& stationMap, KFState& kfState); -#endif diff --git a/src/cpp/common/sinexParser.cpp b/src/cpp/common/sinexParser.cpp new file mode 100644 index 000000000..50e1cf432 --- /dev/null +++ b/src/cpp/common/sinexParser.cpp @@ -0,0 +1,163 @@ + +// #pragma GCC optimize ("O0") + +#include "sinexParser.hpp" + +#include + +using std::string; + +extern map stationMap; + +void SinexParser::parseSinexEstimates( + string& s) +{ + KFKey kfKey; + + string type = s.substr(7, 6); + + if (type == "STAX ") { kfKey.num = 0; kfKey.type = KF::REC_POS; } + else if (type == "STAY ") { kfKey.num = 1; kfKey.type = KF::REC_POS; } + else if (type == "STAZ ") { kfKey.num = 2; kfKey.type = KF::REC_POS; } + + if (kfKey.type != KF::REC_POS) + { + return; + } + + kfKey.str = s.substr(14, 4); + kfKey.rec_ptr = &stationMap[kfKey.str]; + + int parameterNumber = atoi(s.substr(1, 5).c_str()); + + UYds yds; + int readcount; + readcount = sscanf(s.c_str() + 27, "%2d:%3d:%5d", + &yds[0], + &yds[1], + &yds[2]); + + if (readcount != 3) + { + return; + } + + if ( yds[0] != 0 + ||yds[1] != 0 + ||yds[2] != 0) + { + nearestYear(yds[0]); + } + + double x; + double P0; + + readcount = sscanf(s.c_str() + 47, "%21lf %11lf", + &x, + &P0); + + if (readcount != 2) + { + return; + } + + GTime time = yds; + + parameterMap[parameterNumber] = {time, kfKey}; + + auto& [value, covMap] = valueMap[time][kfKey]; + + value = x; + covMap[kfKey] = P0; +} + +void SinexParser::parseSinexEstimateMatrix( + string& s) +{ + int row; + int col0; + double values[3]; + int readcount = sscanf(s.c_str(), " %5d %5d %21lf %21lf %21lf", + &row, + &col0, + &values[0], + &values[1], + &values[2]); + + if (readcount < 3) + { + return; + } + + int covars = readcount - 2; + + for (int i = 0; i < covars; i++) + { + auto& [timeA, kfKeyA] = parameterMap[row]; + auto& [timeB, kfKeyB] = parameterMap[col0 + i]; + + if (row != col0 + i) + { +// continue; + } + + if ( timeA.bigTime == 0 + || timeB.bigTime == 0) + { + continue; + } + + auto& [valueA, covMapA] = valueMap[timeA][kfKeyA]; covMapA[kfKeyB] = values[i]; + auto& [valueB, covMapB] = valueMap[timeB][kfKeyB]; covMapB[kfKeyA] = values[i]; + } +} + +void SinexParser::parseSinexDiscontinuities( + string& s) +{ + // 0194 A 1 P 00:000:00000 03:160:00000 P - antenna change + DiscontinuityObject dObj; + + dObj.sitecode = s.substr(1, 4); + dObj.monuid = s[7]; + dObj.solution = atoi(s.substr(9, 4).c_str()); + dObj.isVelocity = s[42] == 'V'; + + UYds startYds; + UYds endYds; + + int readcount; + readcount = sscanf(s.c_str() + 16, "%2d:%3d:%5d %2d:%3d:%5d", + &startYds[0], + &startYds[1], + &startYds[2], + &endYds[0], + &endYds[1], + &endYds[2]); + + if (readcount != 6) + { + return; + } + + if ( startYds[0] != 0 + ||startYds[1] != 0 + ||startYds[2] != 0) + { + nearestYear(startYds[0]); + } + + if ( endYds[0] != 0 + ||endYds[1] != 0 + ||endYds[2] != 0) + { + nearestYear(endYds[0]); + } + + dObj.start = startYds; + dObj.end = endYds; + + GTime time = startYds; + + discontinuityMap[time][dObj.sitecode] = dObj; +} diff --git a/src/cpp/common/sinexParser.hpp b/src/cpp/common/sinexParser.hpp new file mode 100644 index 000000000..531c9e90c --- /dev/null +++ b/src/cpp/common/sinexParser.hpp @@ -0,0 +1,219 @@ + +#pragma once + + +#include +#include +#include +#include + +#include + +#include "eigenIncluder.hpp" +#include "streamObs.hpp" +#include "algebra.hpp" +#include "gTime.hpp" +#include "trace.hpp" + +using std::getline; +using std::ifstream; +using std::string; +using std::tuple; + +struct DiscontinuityObject +{ + string sitecode = ""; // site code + string monuid = ""; // monument identification + int solution = 0; // valid solution number + // a P letter, no idea what it stands for ... + UYds start; + UYds end; + bool isVelocity = false; // position/velocity switch +}; + +struct SinexParser : Parser, ObsLister +{ + map> parameterMap; + map>>> valueMap; + map> discontinuityMap; + + // Sinex 2.02 documentation indicates 2 digit years. >50 means 1900+N. <=50 means 2000+N + // To achieve this, when we read years, if >50 add 1900 else add 2000. This source will + // cease to work safely around 2045! + // when we write years, write out modulo 100 + // This only applies to site data, for satellites it is using 4 digit years + void nearestYear( + int& year) + { + if (year > 50) year += 1900; + else year += 2000; + } + + void nullFunction( + string& s) + { + + } + + void parseSinexEstimates( + string& s); + + void parseSinexEstimateMatrix( + string& s); + + void parseSinexDiscontinuities( + string& s); + + void parse( + std::istream& inputStream) + { + string closure = ""; + void (SinexParser::*parseFunction)(string&) = &SinexParser::nullFunction; + + if (!inputStream) + { + return; + } + + while (inputStream) + { + string line; + + getline(inputStream, line); + + // test below empty line (ie continue if something on the line) + if (!inputStream) + { + // error - did not find closure line. Report and clean up. + BOOST_LOG_TRIVIAL(error) + << "Error: Closure line not found before end." << std::endl; + + break; + } + + if (line[0] == '*') + { + //comment + continue; + } + + if (line[0] == '-') + { + //end of block + parseFunction = &SinexParser::nullFunction; + + if (line != closure) + { + BOOST_LOG_TRIVIAL(error) + << "Error: Incorrect section closure line encountered: " + << closure << " != " << line << std::endl; + } + + closure = ""; + + continue; + } + + if (line[0] == ' ') + { + //this probably needs specialty parsing - use a prepared function pointer. + (this->*parseFunction)(line); + + continue; + } + + if (line[0] == '+') + { + string mvs; + + //prepare closing line for comparison + closure = line; + closure[0] = '-'; + string lineName = line.substr(0, line.find(' ')); + if (lineName == "+SOLUTION/ESTIMATE" ) { parseFunction = &SinexParser::parseSinexEstimates; } + else if (lineName == "+SOLUTION/DISCONTINUITY" ) { parseFunction = &SinexParser::parseSinexDiscontinuities; } + else if (lineName == "+SOLUTION/MATRIX_ESTIMATE" ) { parseFunction = &SinexParser::parseSinexEstimateMatrix; } + else + { + // BOOST_LOG_TRIVIAL(error) + // << "Error: error unknown header line: " << line << endl; + } + + continue; + } + + if (line[0] == '%') + { + if (line.substr(0, 5) == "%=SNX") + { + continue; + } + + if (line != "%ENDSNX") + { + // error in file. report it. + BOOST_LOG_TRIVIAL(error) + << "Error: line starting '%' met not final line" << std::endl << line << std::endl; + + return; + } + + continue; + } + } + + //aggregate all maps into an obsList type entity + for (auto& [time, someMap] : valueMap) + { + //make an Observation. + FObs obs; + obs.time = time; + + int index = 0; + + obs.obsState.kfIndexMap[KFState::oneKey] = index; + + index++; + + for (auto& [key, tuplet] : someMap) + { + obs.obsState.kfIndexMap[key] = index; + obs.obsState.stateTransitionMap[key][key][0] = 1; + + index++; + } + + obs.obsState.x = VectorXd::Zero(index); +// obs.obsState.Z = MatrixXd::Zero(index,index); + obs.obsState.P = MatrixXd::Zero(index,index); + + for (auto& [keyA, tuplet] : someMap) + { + auto indexA = obs.obsState.kfIndexMap[keyA]; + + auto& [value, covMap] = tuplet; + + obs.obsState.x(indexA) = value; + + for (auto& [keyB, cov] : covMap) + { + auto indexB = obs.obsState.kfIndexMap[keyB]; + + obs.obsState.P(indexA, indexB) = cov; + } + } + + ObsList obsList; + + obsList.push_back((shared_ptr)obs); + + std::cout << "Got obs for " << obs.time << std::endl; + obsListList.push_back(std::move(obsList)); + } + } + + string parserType() + { + return "SinexParser"; + } +}; diff --git a/src/cpp/common/sp3.cpp b/src/cpp/common/sp3.cpp index 7eee7951e..f15ee9b8d 100644 --- a/src/cpp/common/sp3.cpp +++ b/src/cpp/common/sp3.cpp @@ -10,14 +10,15 @@ using std::string; #include "eigenIncluder.hpp" -#include "streamTrace.hpp" #include "navigation.hpp" -#include "gTime.hpp" #include "common.hpp" +#include "trace.hpp" +#include "gTime.hpp" #include "enums.h" -/* satellite code to satellite system ----------------------------------------*/ +/** satellite code to satellite system +*/ E_Sys code2sys(char code) { if (code=='G'||code==' ') return E_Sys::GPS; @@ -29,14 +30,13 @@ E_Sys code2sys(char code) return E_Sys::NONE; } - /** read an epoch of data from an sp3 precise ephemeris file */ bool readsp3( std::istream& fileStream, ///< stream to read content from - list& pephList, ///< list of precise ephemerides for one epoch + vector& pephList, ///< vector of precise ephemerides for one epoch int opt, ///< options options (1: only observed + 2: only predicted + 4: not combined) - bool& isUTC, ///< reported utc state in header + E_TimeSys& tsys, ///< time system double* bfact) ///< bfact values from header { GTime time = {}; @@ -80,9 +80,12 @@ bool readsp3( return false; } - if (isUTC) + if (tsys == +E_TimeSys::UTC) { - time = utc2gpst(time); /* utc->gpst */ + UtcTime utcTime; + utcTime.bigTime = time.bigTime; + + time = utcTime; } continue; } @@ -96,12 +99,7 @@ bool readsp3( E_Sys sys = code2sys(buff[1]); int prn = (int)str2num(buff, 2, 2); - if (sys == +E_Sys::SBS) prn += 100; - else if (sys == +E_Sys::QZS) prn += 192; /* extension to sp3-c */ - - SatSys Sat; - Sat.sys = sys; - Sat.prn = prn; + SatSys Sat(sys, prn); if (!Sat) continue; @@ -130,10 +128,9 @@ bool readsp3( if (buff[0]=='P') { /* position */ - if ( val != 0 - &&fabs(val - 999999.999999) >= 1E-6) + if ( val != 0) { - peph.Pos[j] = val * 1000; + peph.pos[j] = val * 1000; } else { @@ -144,23 +141,22 @@ bool readsp3( if ( base > 0 && std > 0) { - peph.PosStd[j] = pow(base, std) * 1E-3; + peph.posStd[j] = pow(base, std) * 1E-3; } } else if (valid) { // /* velocity */ -// if ( val !=0 -// &&fabs(val - 999999.999999) >= 1E-6) +// if ( val !=0) // { -// peph.Vel[j] = val * 0.1; +// peph.vel[j] = val * 0.1; // } // // double base = bfact[j < 3 ? 0 : 1]; // if ( base > 0 // && std > 0) // { -// peph.VelStd[j] = pow(base, std) * 1E-7; +// peph.velStd[j] = pow(base, std) * 1E-7; // } } } @@ -172,19 +168,22 @@ bool readsp3( if (j == 3 && (opt&1) && pred_c) continue; if (j == 3 && (opt&2) && !pred_c) continue; + string checkValue; + checkValue.assign(buff + 4 + j * 14, 7); double val = str2num(buff, 4 + j * 14, 14); double std = str2num(buff,61 + j * 3, 3); if (buff[0] == 'P') { - /* position */ + /* clock */ if ( val != 0 - &&fabs(val - 999999.999999) >= 1E-6) + &&checkValue != " 999999") { - peph.Clk = val * 1E-6; + peph.clk = val * 1E-6; } else { + peph.clk = INVALID_CLOCK_VALUE; // valid = false; //allow clocks to be invalid } @@ -192,14 +191,14 @@ bool readsp3( if ( base > 0 && std > 0) { - peph.ClkStd = pow(base, std) * 1E-12; + peph.clkStd = pow(base, std) * 1E-12; } } else if (valid) { -// /* velocity */ +// /* clock rate */ // if ( val !=0 -// &&fabs(val - 999999.999999) >= 1E-6) +// &&fabs(val) < NO_SP3_CLK) // { // peph.dCk = val * 1E-10; // } @@ -216,12 +215,22 @@ bool readsp3( if (valid) { pephList.push_back(peph); -// nav->pephMap[peph.Sat][peph.time] = peph; //todo aaron, why doing this? } continue; } - + /* + Quick and dirty read of the velocities + @todo change later. + */ + if (buff[0] == 'V') + { + for (int i=0; i < 3; i++) + { + double val = str2num(buff, 4 + i * 14, 14); + pephList.back().vel[i] = val * 0.1; + } + } if (buff[0] == '#') { hashCount++; @@ -272,14 +281,28 @@ bool readsp3( if (cCount == 1) { - char tsys[4] = ""; - strncpy(tsys, buff+9,3); - tsys[3] = '\0'; + string timeSysStr = line.substr(9, 3); - if (!strcmp(tsys, "UTC")) + if (timeSysStr == "GPS") tsys = E_TimeSys::GPST; + else if (timeSysStr == "GLO") tsys = E_TimeSys::GLONASST; + else if (timeSysStr == "GAL") tsys = E_TimeSys::GST; + else if (timeSysStr == "QZS") tsys = E_TimeSys::QZSST; + else if (timeSysStr == "TAI") tsys = E_TimeSys::TAI; + else if (timeSysStr == "UTC") tsys = E_TimeSys::UTC; + else { - isUTC = true; -// time = utc2gpst(time); /* utc->gpst */ + BOOST_LOG_TRIVIAL(error) + << "Unknown sp3 time system: " << timeSysStr << std::endl; + return false; + } + + // currently only GPST and UTC are supported + if ( tsys != +E_TimeSys::GPST + &&tsys != +E_TimeSys::UTC) + { + BOOST_LOG_TRIVIAL(error) + << "Unsupported time system: " << timeSysStr << std::endl; + return false; } } continue; @@ -320,16 +343,16 @@ void readSp3ToNav( printf("\nSp3 file open error %s\n", file.c_str()); } - list pephList; + vector pephList; - bool isUTC = false; + E_TimeSys tsys = E_TimeSys::NONE; double bfact[2] = {}; - while (readsp3(fileStream, pephList, opt, isUTC, bfact)) + while (readsp3(fileStream, pephList, opt, tsys, bfact)) { //keep reading until it fails for (auto& peph : pephList) { - nav->pephMap[peph.Sat][peph.time] = peph; + nav->pephMap[peph.Sat.id()][peph.time] = peph; } pephList.clear(); } @@ -339,12 +362,9 @@ void readSp3ToNav( void orb2sp3( Navigation& nav) { - for (auto& [SatId, satNav] : nav.satNavMap) + for (auto& [Sat, satNav] : nav.satNavMap) for (auto& [time, orbitInfo] : satNav.satOrbit.orbitInfoMap) { - SatSys Sat; - Sat.fromHash(SatId); - Peph peph = {}; peph.index = 0; @@ -352,12 +372,9 @@ void orb2sp3( peph.Sat = Sat; /* copy itrf coordinates */ - for (int k = 0; k < 3; k++) - { - peph.Pos [k] = orbitInfo.xtrf[k]; - peph.PosStd [k] = 0.1; //default value for POD orbits precision - } + peph.pos = orbitInfo.posEcef; + peph.posStd = Vector3d::Ones() * 0.1;//default value for POD orbits precision - nav.pephMap[Sat][time] = peph; + nav.pephMap[Sat.id()][time] = peph; } } diff --git a/src/cpp/common/sp3Write.cpp b/src/cpp/common/sp3Write.cpp index c8f87326a..5ac63b675 100644 --- a/src/cpp/common/sp3Write.cpp +++ b/src/cpp/common/sp3Write.cpp @@ -7,11 +7,13 @@ #include "rinexObsWrite.hpp" #include "rinexClkWrite.hpp" +#include "coordinates.hpp" #include "GNSSambres.hpp" #include "navigation.hpp" #include "ephemeris.hpp" #include "acsConfig.hpp" #include "constants.hpp" +#include "mongoRead.hpp" #include "sp3Write.hpp" #include "station.hpp" #include "algebra.hpp" @@ -22,28 +24,34 @@ struct Sp3Entry { - SatSys sat = {}; - Vector3d satPos = Vector3d::Zero(); // Satellite position. - Vector3d satVel = Vector3d::Zero(); // Satellite velocity. - double clock[2] = {}; // Mean clock delta reference. + SatSys sat; + Vector3d satPos = Vector3d::Zero(); // Satellite position. + Vector3d satVel = Vector3d::Zero(); // Satellite velocity. + double satClk = INVALID_CLOCK_VALUE / 1e6; + double satClkVel = INVALID_CLOCK_VALUE / 1e6; double sigma = 0; + bool predicted = false; }; -typedef map Sp3SatList; +struct Sp3FileData +{ + set sats; + long numEpoch = 0; + long numEpoch_pos = 0; +}; Sp3FileData sp3CombinedFileData; -map sp3SytemFileData; +Sp3FileData predictedSp3CombinedFileData; void writeSp3Header( std::fstream& sp3Stream, - Sp3SatList& entryList, + map& entryList, GTime time, - OutSys outSys, + map& outSys, Sp3FileData& outFileDat) { - double ep[6] = {}; - time2epoch(time, ep); + GEpoch ep = time; outFileDat = {}; outFileDat.numEpoch = 1; @@ -57,21 +65,26 @@ void writeSp3Header( //TODO Check, coordinate system and Orbit Type from example product file. tracepdeex(0, sp3Stream, "%7d ORBIT IGS14 HLM %4s\n", outFileDat.numEpoch, acsConfig.analysis_agency.c_str()); - int week; - double tow_sec = time2gpst(time, &week); - double mjdate = 7.0 * week + tow_sec / 86400.0 + 44244.0; + GWeek week = time; + GTow tow = time; + double mjdate = 7.0 * week + tow / 86400.0 + 44244.0; //todo aaron ew. tracepdeex(0, sp3Stream, "## %4d %15.8f %14.8f %5.0f %15.13f\n", week, - tow_sec, - acsConfig.epoch_interval, + tow, + acsConfig.orbits_output_interval, mjdate, mjdate - floor(mjdate)); for (auto sys : {E_Sys::GPS, E_Sys::GLO, E_Sys::GAL, E_Sys::BDS}) { if (outSys[sys]) - for (auto Sat : getSysSats(E_Sys::GPS)) + for (auto Sat : getSysSats(sys)) { + auto satOpts = acsConfig.getSatOpts(Sat); + + if (satOpts.exclude) + continue; + outFileDat.sats.insert(Sat); } } @@ -195,22 +208,19 @@ void writeSp3Header( tracepdeex(0, sp3Stream, "%%i 0 0 0 0 0 0 0 0 0\n"); // There is a minimum of four comment lines. - tracepdeex(0, sp3Stream, "/* Created using Ginan at: %s.\n", timeget().to_string(0).c_str()); - tracepdeex(0, sp3Stream, "/* WARNING: For Geoscience Australia's internal use only\n"); + tracepdeex(0, sp3Stream, "/* Created using Ginan at: %s.\n", ((GTime)timeGet()).to_string().c_str()); + tracepdeex(0, sp3Stream, "/* WARNING: Not for operational use\n"); tracepdeex(0, sp3Stream, "/*\n"); tracepdeex(0, sp3Stream, "/*\n"); } void updateSp3Body( - string& filename, ///< Path to output file. - Sp3SatList& entryList, ///< List of data to print. + string filename, ///< Path to output file. + map& entryList, ///< List of data to print. GTime time, ///< Epoch time. - OutSys outSys, ///< Systems to include in file. + map& outSys, ///< Systems to include in file. Sp3FileData& outFileDat) ///< Current file editing information. { - double ep[6] = {}; - time2epoch(time, ep); - //first create if non existing { std::fstream maker(filename, std::ios::app); @@ -244,6 +254,7 @@ void updateSp3Body( sp3Stream.seekp(-4, std::ios::end); } + GEpoch ep = time; tracepdeex(0, sp3Stream, "* %4.0f %2.0f %2.0f %2.0f %2.0f %11.8f\n", ep[0], ep[1], ep[2], ep[3], ep[4], ep[5]); // Note position is in kilometers and clock values microseconds. @@ -255,36 +266,44 @@ void updateSp3Body( { auto& [key, entry] = *it; + char predictedChar; + if (entry.predicted) predictedChar = 'P'; + else predictedChar = ' '; + { - tracepdeex(0, sp3Stream, "P%s%14.6f%14.6f%14.6f%14.6f\n", + tracepdeex(0, sp3Stream, "P%s%14.6f%14.6f%14.6f%14.6f%19s%c\n", entry.sat.id().c_str(), entry.satPos.x() / 1000, entry.satPos.y() / 1000, entry.satPos.z() / 1000, - entry.clock[0] * 1e6); + entry.satClk * 1e6, + "", + predictedChar); } if (acsConfig.output_orbit_velocities) { - tracepdeex(0, sp3Stream, "V%s%14.6f%14.6f%14.6f%14.6f\n", + tracepdeex(0, sp3Stream, "V%s%14.6f%14.6f%14.6f%14.6f%19s%c\n", entry.sat.id().c_str(), entry.satVel.x(), entry.satVel.y(), entry.satVel.z(), - entry.clock[1] * 1e6); + entry.satClkVel * 1e6, + "", + predictedChar); } } else { { tracepdeex(0, sp3Stream, "P%s%14.6f%14.6f%14.6f%14.6f\n", - sat.id().c_str(), 0, 0, 0, 999999.999999); + sat.id().c_str(), 0, 0, 0, NO_SP3_CLK); } if (acsConfig.output_orbit_velocities) { tracepdeex(0, sp3Stream, "V%s%14.6f%14.6f%14.6f%14.6f\n", - sat.id().c_str(), 0, 0, 0, 999999.999999); + sat.id().c_str(), 0, 0, 0, NO_SP3_CLK); } } } @@ -293,31 +312,30 @@ void updateSp3Body( } void writeSysSetSp3( - string filename, - GTime time, - OutSys outSys, - Sp3FileData& outFileDat, - E_Ephemeris sp3DataSrc, - KFState* kfState_ptr) + string filename, + GTime time, + map& outSys, + Sp3FileData& outFileDat, + vector sp3DataSrcs, + KFState* kfState_ptr, + bool predicted) { - Sp3SatList entryList; + map entryList; - for (auto& [satId, satNav] : nav.satNavMap) + for (auto& [Sat, satNav] : nav.satNavMap) { - SatSys Sat; - Sat.fromHash(satId); - - if (!outSys[Sat.sys]) + if (outSys[Sat.sys] == false) continue; // Create a dummy observation - Obs obs; - obs.Sat = Sat; - obs.satNav_ptr = &nav.satNavMap[Sat]; + GObs obs; + obs.Sat = Sat; + obs.satNav_ptr = &nav.satNavMap[Sat]; - GTime teph = time; - - bool pass = satpos(nullStream, time, teph, obs, acsConfig.orbits_data_source, E_OffsetType::COM, nav, false, kfState_ptr); + bool pass = true; + pass &= satclk(nullStream, time, time, obs, sp3DataSrcs, nav, kfState_ptr); + pass &= satpos(nullStream, time, time, obs, sp3DataSrcs, E_OffsetType::COM, nav, kfState_ptr); + if (pass == false) { BOOST_LOG_TRIVIAL(warning) << "Warning: Writing SP3 file, failed to get data for satellite " << Sat.id(); @@ -326,11 +344,20 @@ void writeSysSetSp3( Sp3Entry entry; entry.sat = Sat; - entry.satPos = obs.rSat; - entry.satVel = obs.satVel; - entry.clock[0] = obs.dtSat[0]; - entry.clock[1] = obs.dtSat[1]; - entry.sigma = sqrt(obs.ephVar); + if (acsConfig.output_inertial_orbits) + { + entry.satPos = obs.rSatEci0; + entry.satVel = obs.vSatEci0; + } + else + { + entry.satPos = obs.rSat; + entry.satVel = obs.satVel; + } + entry.satClk = obs.satClk; + entry.satClkVel = obs.satClkVel; + entry.sigma = sqrt(obs.satClkVar); + entry.predicted = predicted; entryList[Sat] = entry; } @@ -340,14 +367,89 @@ void writeSysSetSp3( void outputSp3( - GTime time, - E_Ephemeris sp3DataSrc, - KFState* kfState_ptr) + string filename, + GTime time, + vector sp3DataSrcs, + KFState* kfState_ptr, + bool predicted) { - auto sysFilenames = getSysOutputFilenames(acsConfig.orbits_filename, time); + time = time.floorTime(1); + + GTow tow = time; + if (int(tow) % acsConfig.orbits_output_interval != 0) + return; + + auto sysFilenames = getSysOutputFilenames(filename, time); for (auto [filename, sysMap] : sysFilenames) { - writeSysSetSp3(filename, time, sysMap, sp3CombinedFileData, sp3DataSrc, kfState_ptr); + writeSysSetSp3(filename, time, sysMap, sp3CombinedFileData, sp3DataSrcs, kfState_ptr, predicted); + } +} + +void outputMongoOrbits() +{ + map> entryListMap; + + auto orbitMapMap = mongoReadOrbits(); + auto clockMapMap = mongoReadClocks(); + + map outSys; + + auto sysFilenames = getSysOutputFilenames(acsConfig.predicted_orbits_filename, tsync); + + for (auto [filename, sysMap] : sysFilenames) + { + for (auto& [Sat, timeMap] : orbitMapMap) + for (auto& [time, state] : timeMap) + { + ERPValues erpv = geterp(nav.erp, time); + + FrameSwapper frameSwapper(time, erpv); + + auto& entry = entryListMap[time][Sat]; + + entry.sat = Sat; + + if (acsConfig.output_inertial_orbits) + { + entry.satPos = state.head(3); + entry.satVel = state.tail(3); + } + else + { + VectorEci rSat = (Vector3d) state.head(3); + VectorEci vSat = (Vector3d) state.tail(3); + + VectorEcef vSatEcef; + entry.satPos = frameSwapper(rSat, &vSat, &vSatEcef); + entry.satVel = vSatEcef; + } + + auto timeMapIt = clockMapMap.find(Sat.id()); + if (timeMapIt == clockMapMap.end()) + { + continue; + } + + auto& [dummy1, timeClkMap] = *timeMapIt; + + auto timeIt = timeClkMap.find(time); + if (timeIt == timeClkMap.end()) + { + continue; + } + + auto& [dummy2, clockTuple] = *timeIt; + auto& [clock, drift] = clockTuple; + + entry.satClk = clock; + entry.satClkVel = drift; + } + + for (auto& [time, entryList] : entryListMap) + { + updateSp3Body(filename, entryList, time, sysMap, predictedSp3CombinedFileData); + } } } diff --git a/src/cpp/common/sp3Write.hpp b/src/cpp/common/sp3Write.hpp index be9150500..a46082ace 100644 --- a/src/cpp/common/sp3Write.hpp +++ b/src/cpp/common/sp3Write.hpp @@ -1,5 +1,5 @@ -#ifndef __WRITEPOSCLKSP3_HPP -#define __WRITEPOSCLKSP3_HPP + +#pragma once #include #include @@ -10,26 +10,15 @@ using std::set; #include "rinexClkWrite.hpp" struct GTime; -class E_Ephemeris; +class E_Source; struct KFState; -struct Sp3FileData -{ - set sats = {}; - long numEpoch = 0; - long numEpoch_pos = 0; -}; - -void writeSysSetSp3( - string filename, - GTime time, - OutSys outSys, - Sp3FileData& outFileDat, - E_Ephemeris sp3DataSrc, - KFState* kfState_ptr = nullptr); - void outputSp3( - GTime time, - E_Ephemeris sp3DataSrc, - KFState* kfState_ptr = nullptr); -#endif + string filename, + GTime time, + vector sp3DataSrcs, + KFState* kfState_ptr = nullptr, + bool predicted = false); + +void outputMongoOrbits(); + diff --git a/src/cpp/common/ssr.hpp b/src/cpp/common/ssr.hpp index 125b1e1c5..43882014d 100644 --- a/src/cpp/common/ssr.hpp +++ b/src/cpp/common/ssr.hpp @@ -1,113 +1,256 @@ -#ifndef __SSR_H__ -#define __SSR_H__ +#pragma once +#include #include "eigenIncluder.hpp" +#include "gTime.hpp" +#include "trace.hpp" +const double ura_ssr[] = +{ + 0, + 0.25, + 0.5, + 0.75, + 1, + 1.25, + 1.5, + 1.75, + 2, + 2.75, + 3.5, + 4.25, + 5, + 5.75, + 6.5, + 7.25, + 8, + 10.25, + 12.5, + 14.75, + 17, + 19.25, + 21.5, + 23.75, + 26, + 32.75, + 39.5, + 46.25, + 53, + 59.75, + 66.5, + 73.25, + 80, + 100.25, + 120.5, + 140.75, + 161, + 181.25, + 201.5, + 221.75, + 242, + 302.75, + 363.5, + 424.25, + 485, + 545.75, + 606.5, + 667.25, + 728, + 910.25, + 1092.5, + 1274.75, + 1457, + 1639.25, + 1821.5, + 2003.75, + 2186, + 2732.75, + 3279.5, + 3826.25, + 4373, + 4919.75, + 5466.5, + 6013.25 +}; + // SSR message metadata struct SSRMeta { - int epochTime1s = 0; - int ssrUpdateIntIndex = -1; - int multipleMessage = 0; - unsigned int referenceDatum = 0; - unsigned int provider = 0; - unsigned int solution = 0; + int epochTime1s = 0; + GTime receivedTime = {}; + int updateIntIndex = -1; + int multipleMessage = 0; + unsigned int referenceDatum = 0; + unsigned int provider = 0; + unsigned int solution = 0; + unsigned int numSats = 0; }; struct SSREph { - SSRMeta ssrMeta; - GTime t0 = {}; - double udi = 0; ///< update interval - int iod = -1; - int iode = -1; ///< issue of data - int iodcrc = -1; - Vector3d deph = Vector3d::Zero(); ///< delta orbit {radial,along,cross} (m) - Vector3d ddeph = Vector3d::Zero(); ///< dot delta orbit {radial,along,cross} (m/s) + SSRMeta ssrMeta = {}; + GTime t0 = {}; + double udi = 0; ///< update interval + int iod = -1; + int iode = -1; ///< issue of data + int iodcrc = -1; + Vector3d deph = Vector3d::Zero(); ///< delta orbit {radial,along,cross} (m) + Vector3d ddeph = Vector3d::Zero(); ///< dot delta orbit {radial,along,cross} (m/s) }; struct SSRClk { - SSRMeta ssrMeta = {}; - GTime t0 = {}; - double udi = 0; ///< update interval - int iod = -1; - double dclk[3] = {}; ///< delta clock {c0,c1,c2} (m,m/s,m/s^2) + SSRMeta ssrMeta = {}; + GTime t0 = {}; + double udi = 0; ///< update interval + int iod = -1; + double dclk[3] = {}; ///< delta clock {c0,c1,c2} (m,m/s,m/s^2) +}; + +struct SSRUra +{ + SSRMeta ssrMeta = {}; + GTime t0 = {}; + double udi = 0; ///< update interval + int iod = -1; + int ura = 0; ///< URA indicator }; struct SSRHRClk { - SSRMeta ssrMeta = {}; - GTime t0 = {}; - double udi = 0; ///< update interval - int iod = -1; - double hrclk = 0; ///< high-rate clock corection (m) + SSRMeta ssrMeta = {}; + GTime t0 = {}; + double udi = 0; ///< update interval + int iod = -1; + double hrclk = 0; ///< high-rate clock corection (m) }; -struct SSRUra +struct BiasVar +{ + double bias = 0; ///< biases (m) + double var = 0; ///< biases variance (m^2) +}; + +struct SSRBias +{ + SSRMeta ssrMeta = {}; + GTime t0 = {}; + double udi = 0; ///< update interval + int iod = -1; + unsigned int nbias = 0; + map obsCodeBiasMap; +}; + +struct SSRCodeBias : SSRBias { - GTime t0 = {}; - double udi = 0; ///< update interval - int iod = -1; - int ura = 0; ///< URA indicator + //just inherit. }; struct SSRPhase { - int dispBiasConistInd = -1; - int MWConistInd = -1; - unsigned int nbias = 0; - double yawAngle = 0; - double yawRate = 0; + int dispBiasConistInd = -1; + int MWConistInd = -1; + double yawAngle = 0; + double yawRate = 0; }; struct SSRPhaseCh { - unsigned int signalIntInd = -1; - unsigned int signalWidIntInd = -1; - unsigned int signalDisconCnt = -1; + unsigned int signalIntInd = -1; + unsigned int signalWLIntInd = -1; + unsigned int signalDisconCnt = -1; }; -struct BiasVar +struct SSRPhasBias : SSRBias { - double bias = 0; ///< biases (m) - double var = 0; ///< biases variance (m^2) + SSRPhase ssrPhase; ///< Additional data for SSR phase messages + map ssrPhaseChs; ///< Additional data for SSR phase messages, for each channel }; +struct SphComp +{ + int hind; + int order; + int degree; + bool parity; + double coeffc; + double variance; +}; -struct SSRBias +struct SSRVTEClayer { - SSRMeta ssrMeta; - - GTime t0 = {}; - double udi = 0; ///< update interval - int iod = -1; - - map obsCodeBiasMap; + double height = 0; + int maxOrder = 0; + int maxDegree = 0; + map sphHarmonic; }; -struct SSRCodeBias : SSRBias +struct SSRAtmGlobal { - //just inherit. + GTime time; + int numberLayers; + map layers; + double vtecQuality; + int iod; }; -struct SSRPhasBias : SSRBias +struct SSRSTECData { - SSRPhase ssrPhase; ///< Additional data for SSR phase messages - map ssrPhaseChs; ///< Additional data for SSR phase messages, for each channel + int iod; + double accr; + map poly; + map grid; +}; + +struct SSRTropData +{ + double acc; + map poly; + map gridDry; + map gridWet; +}; + +struct SSRAtmRegion +{ + int regionDefIOD = -1; + map gridLat; + map gridLon; + + double minLat = 0; + double maxLat = 0; + double intLat = 0; + + double minLon = 0; + double maxLon = 0; + double intLon = 0; + + int tropPolySize = 0; + int ionoPolySize = 0; + + map> tropData; + map>> stecData; +}; + +struct SSRAtm +{ + SSRMeta ssrMeta; + map> atmosGlobalMap; + map atmosRegionsMap; }; struct EphValues { GTime time; - unsigned int iode = 0; - Vector3d brdcPos = Vector3d::Zero(); - Vector3d brdcVel = Vector3d::Zero(); - Vector3d precPos = Vector3d::Zero(); - Vector3d precVel = Vector3d::Zero(); + unsigned int iode = 0; + Vector3d brdcPos = Vector3d::Zero(); + Vector3d brdcVel = Vector3d::Zero(); + Vector3d precPos = Vector3d::Zero(); + Vector3d precVel = Vector3d::Zero(); + + double ephVar = 0; }; struct ClkValues @@ -137,15 +280,13 @@ struct SSRMaps map> ssrPhasBias_map; map> ssrClk_map; map> ssrEph_map; - map> ssrHRClk_map; //todo aaron missing implementation? + map> ssrHRClk_map; map> ssrUra_map; int refd_; ///< sat ref datum (0:ITRF,1:regional) - unsigned char update_; /// sats); -#endif + +bool ssrPosDelta( + GTime time, + GTime ephTime, + SatPos& satPos, + const SSRMaps& ssrMaps, + Vector3d& dPos, + int& iodPos, + int& iodEph, + GTime& validStart, + GTime& validStop); + +bool ssrClkDelta( + GTime time, + GTime ephTime, + SatPos& satPos, + const SSRMaps& ssrMaps, + double& dclk, + int& iodClk, + GTime& validStart, + GTime& validStop); diff --git a/src/cpp/common/station.cpp b/src/cpp/common/station.cpp new file mode 100644 index 000000000..bdf04e43f --- /dev/null +++ b/src/cpp/common/station.cpp @@ -0,0 +1,12 @@ + +#include "sinex.hpp" + +Sinex_siteid_t dummySiteid; +Sinex_receiver_t dummyReceiver; +Sinex_antenna_t dummyAntenna; +Sinex_gps_phase_center_t dummyGps_phase_center; +Sinex_gal_phase_center_t dummyGal_phase_center; +Sinex_site_ecc_t dummySite_ecc; + +SinexSatIdentity dummySinexSatIdentity; +Sinex_satecc_t dummySinexSatEcc; diff --git a/src/cpp/common/station.hpp b/src/cpp/common/station.hpp index 3086cc6fa..e307fc776 100644 --- a/src/cpp/common/station.hpp +++ b/src/cpp/common/station.hpp @@ -1,13 +1,35 @@ -#ifndef __STATION__HPP -#define __STATION__HPP + +#pragma once #include "eigenIncluder.hpp" +#include "attitude.hpp" #include "common.hpp" -#include "gTime.hpp" #include "sinex.hpp" +#include "cache.hpp" +#include "gTime.hpp" #include "ppp.hpp" #include "vmf3.h" +/** Solution of user mode processing functinos +*/ +struct Solution +{ + /* solution type */ + GTime time; ///< time (GPST) + map dtRec_m; ///< receiver clock bias to time systems (m) + map dtRec_m_ppp_old; ///< previous receiver clock bias to time systems (m) + map dtRec_m_pppp_old; ///< previous receiver clock bias to time systems (m) + map deltaDt_net_old; ///< previous receiver clock bias to time systems (m) + map pppdtRec_m; ///< receiver clock bias to time systems (s) + E_Solution status; ///< solution status + int numMeas = 0; ///< number of valid satellites + KFState sppState; ///< SPP filter object + double dop[4]; + VectorEcef sppRRec; ///< Position vector from spp + VectorEcef pppRRec; ///< Position vector from ppp + VectorEcef pppVRec; ///< Velocity vector from ppp +}; + struct RinexStation { string id; ///< marker name @@ -24,8 +46,8 @@ struct RinexStation struct StationLogs { - GTime firstEpoch = GTime::noTime(); - GTime lastEpoch = GTime::noTime(); + PTime firstEpoch = GTime::noTime(); + PTime lastEpoch = GTime::noTime(); int epochCount = 0; int obsCount = 0; int slipCount = 0; @@ -36,37 +58,72 @@ struct StationLogs struct Rtk { - KFState pppState; - Solution sol; ///< RTK solution - string antType; - string antId; - map satStatMap; - double otlDisplacement[6*11] = {}; ///< ocean tide loading parameters - Vector3d antDelta = Vector3d::Zero(); ///< antenna delta {rov_e,rov_n,rov_u} + KFState pppState; + Solution sol; ///< RTK solution + string antennaType; + string receiverType; + string antennaId; + map satStatMap; + double otlDisplacement[6*11] = {}; ///< ocean tide loading parameters + VectorEnu antDelta; ///< antenna delta {rov_e,rov_n,rov_u} + AttStatus attStatus; }; +extern Sinex_siteid_t dummySiteid; +extern Sinex_receiver_t dummyReceiver; +extern Sinex_antenna_t dummyAntenna; +extern Sinex_gps_phase_center_t dummyGps_phase_center; +extern Sinex_gal_phase_center_t dummyGal_phase_center; +extern Sinex_site_ecc_t dummySite_ecc; + +struct SinexRecData +{ + Sinex_siteid_t* id_ptr = &dummySiteid; + Sinex_receiver_t* rec_ptr = &dummyReceiver; + Sinex_antenna_t* ant_ptr = &dummyAntenna; + Sinex_gps_phase_center_t* gpsPCO_ptr = &dummyGps_phase_center; + Sinex_gal_phase_center_t* galPCO_ptr = &dummyGal_phase_center; + Sinex_site_ecc_t* ecc_ptr = &dummySite_ecc; + + UYds start; + UYds stop = UYds(-1,-1,-1); + + bool primary = false; ///< this position estimate is considered to come from a primary source + VectorEcef pos; + VectorEcef vel; + GTime refEpoch = {}; +}; + /** Object to maintain receiver station data */ struct Station : StationLogs, Rtk { - RinexStation rnxStation; - Sinex_stn_snx_t snx; ///< Antenna information + bool invalid = false; + SinexRecData snx; ///< Antenna information ObsList obsList; ///< Observations available for this station at this epoch - PseudoObsList pseudoObsList; ///< PseudoObservations available for this station at this epoch string id; ///< Unique name for this station (4 characters) bool primaryApriori = false; - int aprioriTime[3] = {}; + UYds aprioriTime; Vector3d aprioriPos = Vector3d::Zero(); ///< station position (ecef) (m) Vector3d aprioriVar = Vector3d::Zero(); + Vector3d minconApriori = Vector3d::Zero(); + + VectorPos pos; + bool ready = false; - string traceFilename; + Vector3d antBoresight = {0,0,1}; + Vector3d antAzimuth = {0,1,0}; + string traceFilename; + map> recClockCodes; map savedSlips; + + Cache> pppTideCache; }; using StationMap = map; ///< Map of all stations @@ -79,5 +136,3 @@ struct Network KFState kfState = {}; }; - -#endif diff --git a/src/cpp/common/streamFile.hpp b/src/cpp/common/streamFile.hpp index 1e69cf3db..4d32e0cff 100644 --- a/src/cpp/common/streamFile.hpp +++ b/src/cpp/common/streamFile.hpp @@ -1,113 +1,99 @@ -#ifndef __ACS_FILESTREAM_HPP -#define __ACS_FILESTREAM_HPP +#pragma once -/** Interface to be used for file streams -*/ -struct ACSFileStream +#include +#include +#include + +using std::make_unique; +using std::unique_ptr; +using std::string; + +#include "streamParser.hpp" + + +struct FileState : std::ifstream { - struct FileState + long int& filePos; + + FileState( + string path, + long int& filePos, + std::ifstream::openmode mode = std::ifstream::in) + : filePos {filePos} { - long int& filePos; - std::ifstream inputStream; + if (filePos < 0) + { +// BOOST_LOG_TRIVIAL(error) << "Error seeking to negative position in file at " << path << " to " << filePos << std::endl; + close(); + return; + } + + open(path, mode); - FileState( - string path, - long int& filePos, - std::ifstream::openmode mode = std::ifstream::in) - : filePos {filePos} + if (!*this) { - if (filePos < 0) - { -// BOOST_LOG_TRIVIAL(error) << "Error seeking to negative position in file at " << path << " to " << filePos -// << std::endl; - return; - } - -// std::cout << "Opening" << std::endl; - inputStream.open(path, mode); - - if (!inputStream) - { - BOOST_LOG_TRIVIAL(error) << "Error opening file at " << path - << std::endl << " - " << strerror(errno); - filePos = -1; - return; - } - -// std::cout << "Seeking" << std::endl; - inputStream.seekg(filePos); - -// std::cout << "Using" << std::endl; - - if (!inputStream) - { - BOOST_LOG_TRIVIAL(error) << "Error seeking in file at " << filePos << " in " << path - << std::endl << " - " << strerror(errno); - - filePos = -1; - return; - } + BOOST_LOG_TRIVIAL(error) << "Error opening file at " << path + << std::endl << " - " << strerror(errno); + filePos = -1; + return; } - ~FileState() + seekg(filePos); + + if (!*this) { -// std::cout << "Closed" << std::endl; - if (inputStream) - { - filePos = inputStream.tellg(); - - if (!inputStream) - { - BOOST_LOG_TRIVIAL(error) << "Error telling in file at " << filePos - << std::endl << " - " << strerror(errno); - - filePos = -1; - return; - } - - if (filePos < 0) - { - BOOST_LOG_TRIVIAL(error) << "Error: Negative file pos in file at " << filePos - << std::endl << " - " << strerror(errno); - return; - } - } - else - { -// BOOST_LOG_TRIVIAL(error) << "InputStream is dead before destruction " -// << std::endl; - - if (inputStream.eof()) - { -// BOOST_LOG_TRIVIAL(error) << "InputStream has end of file " -// << std::endl; - } - filePos = -1; - return; - } + BOOST_LOG_TRIVIAL(error) << "Error seeking in file at " << filePos << " in " << path + << std::endl << " - " << strerror(errno); + + filePos = -1; + return; } - }; + } + ~FileState() + { + filePos = streamPos(*this); + } +}; + +struct FileStream : Stream +{ string path; long int filePos = 0; - - ACSFileStream() + + FileStream( + string path) + : path (path) { - + } - - void setPath(const string& path) + + unique_ptr getIStream_ptr() override { - this->path = path; +// std::cout << "Getting FileStream" << std::endl; + + return make_unique(path, filePos); } - - FileState openFile() + + bool isDead() override { - return FileState(path, filePos); + if (filePos < 0) + { + return true; + } + + auto iStream_ptr = this->getIStream_ptr(); + + if (*iStream_ptr) + { + return false; + } + else + { + return true; + } } }; - -#endif diff --git a/src/cpp/common/streamNav.hpp b/src/cpp/common/streamNav.hpp deleted file mode 100644 index afc8b4ae2..000000000 --- a/src/cpp/common/streamNav.hpp +++ /dev/null @@ -1,15 +0,0 @@ - -#ifndef __ACSNAVSTREAM_HPP__ -#define __ACSNAVSTREAM_HPP__ - -/** Interface for objects that provide navigation data -*/ -struct NavStream -{ - virtual void getNav() - { - - } -}; - -#endif diff --git a/src/cpp/common/streamNtrip.cpp b/src/cpp/common/streamNtrip.cpp index e5d2849fe..962d9fa47 100644 --- a/src/cpp/common/streamNtrip.cpp +++ b/src/cpp/common/streamNtrip.cpp @@ -2,30 +2,40 @@ // #pragma GCC optimize ("O0") #include "streamNtrip.hpp" - +#include "trace.hpp" void NtripStream::getData() { - receivedDataBufferMtx.lock(); + lock_guard guard(receivedDataBufferMtx); + + const int reserve = 8192; + + receivedData.reserve(reserve); + + for (auto it = chunkList.begin(); it != chunkList.end(); ) { - //if ( receivedDataBuffer.size() > 0 ) - // BOOST_LOG_TRIVIAL(debug) << "NtripStream::getData(), receivedDataBuffer.size() = " << receivedDataBuffer.size() << std::endl; - receivedData.insert(receivedData.end(), receivedDataBuffer.begin(), receivedDataBuffer.end()); - receivedDataBuffer.clear(); + auto& chunk = *it; + + if (receivedData.size() + chunk.size() > reserve) + { + break; + } + +// std::cout << "\nCHUNK"; +// printHex(std::cout, chunk); + + receivedData.insert(receivedData.end(), chunk.begin(), chunk.end()); + + it = chunkList.erase(it); } - receivedDataBufferMtx.unlock(); } -bool NtripStream::dataChunkDownloaded( - vector dataChunk) +void NtripStream::dataChunkDownloaded( + vector& dataChunk) { - receivedDataBufferMtx.lock(); - { - receivedDataBuffer.insert(receivedDataBuffer.end(), dataChunk.begin(), dataChunk.end()); - } - receivedDataBufferMtx.unlock(); + lock_guard guard(receivedDataBufferMtx); - return false; + chunkList.push_back(std::move(dataChunk)); } void NtripStream::connected() diff --git a/src/cpp/common/streamNtrip.hpp b/src/cpp/common/streamNtrip.hpp index 01fe6a988..1f4d4ed3c 100644 --- a/src/cpp/common/streamNtrip.hpp +++ b/src/cpp/common/streamNtrip.hpp @@ -1,8 +1,7 @@ -#ifndef __ACS_NTRIPSTREAM_HPP -#define __ACS_NTRIPSTREAM_HPP +#pragma once -#include "ntripTrace.hpp" +#include "streamSerial.hpp" #include "ntripSocket.hpp" @@ -10,17 +9,15 @@ -struct NtripStream : NtripSocket +struct NtripStream : NtripSocket, SerialStream { + private: - // This mutex ensures that the main thread and the io_service thread do - // not alter the receivedDataBuffer buffer at the same time. - std::mutex receivedDataBufferMtx; - vector receivedDataBuffer; + + std::mutex receivedDataBufferMtx; //< This mutex ensures that the main thread and the io_service thread dont alter the receivedDataBuffer buffer at the same time. + vector> chunkList; public: - vector receivedData; - NtripStream( const string& url_str) : @@ -40,20 +37,20 @@ struct NtripStream : NtripSocket request_stream << "\r\n"; request_string = request_stream.str(); - chunked_message_length = 0; connect(); } /** Retrieve data from the stream and store it for later removal */ - void getData(); + void getData() + override; void connected() override; - bool dataChunkDownloaded( - vector dataChunk) + void dataChunkDownloaded( + vector& dataChunk) override; @@ -65,7 +62,7 @@ struct NtripStream : NtripSocket * As it is detached there is no need for a join, there is one worker thread * for all the NtripStream objects. */ + + virtual ~NtripStream() = default; }; - -#endif diff --git a/src/cpp/common/streamObs.hpp b/src/cpp/common/streamObs.hpp index 27a1a6914..343e8b468 100644 --- a/src/cpp/common/streamObs.hpp +++ b/src/cpp/common/streamObs.hpp @@ -1,26 +1,107 @@ -#ifndef __ACSOBSSTREAM_HPP__ -#define __ACSOBSSTREAM_HPP__ +#pragma once +#include "streamParser.hpp" +#include "acsConfig.hpp" #include "station.hpp" #include "enums.h" -//interfaces -/** Interface for streams that supply observations -*/ -struct ObsStream + +struct ObsLister { - RinexStation rnxStation = {}; list obsListList; - string sourceString; - E_ObsWaitCode obsWaitCode = E_ObsWaitCode::OK; +}; - /** Return a list of observations from the stream. - * This function may be overridden by objects that use this interface - */ - virtual ObsList getObs(); +struct ObsStream : StreamParser +{ + E_ObsWaitCode obsWaitCode = E_ObsWaitCode::OK; + + ObsStream( + unique_ptr stream_ptr, + unique_ptr parser_ptr) + : StreamParser(std::move(stream_ptr), std::move(parser_ptr)) + { + + } + + ObsList getObs() + { + try + { + auto& obsLister = dynamic_cast(parser); + + if (obsLister.obsListList.size() < 2) + { + parse(); + } + + if (obsLister.obsListList.empty()) + { + return ObsList(); + } + + ObsList& obsList = obsLister.obsListList.front(); + + for (auto& obs : only(obsList)) + for (auto& [ftype, sigsList] : obs.SigsLists) + { + E_Sys sys = obs.Sat.sys; + + if (sys == +E_Sys::GPS) + { + double dirty_C1W_phase = 0; + for (auto& sig : sigsList) + if ( sig.code == +E_ObsCode::L1C) + { + dirty_C1W_phase = sig.L; + break; + } + + for (auto& sig : sigsList) + if ( sig.code == +E_ObsCode::L1W + && sig.L == 0) + { + sig.L = dirty_C1W_phase; + break; + } + } + + sigsList.sort([sys](Sig& a, Sig& b) + { + auto iterA = std::find(acsConfig.code_priorities[sys].begin(), acsConfig.code_priorities[sys].end(), a.code); + auto iterB = std::find(acsConfig.code_priorities[sys].begin(), acsConfig.code_priorities[sys].end(), b.code); + + if (a.L == 0) return false; + if (b.L == 0) return true; + if (a.P == 0) return false; + if (b.P == 0) return true; + if (iterA < iterB) return true; + else return false; + }); + + if (sigsList.empty()) + { + continue; + } + + Sig firstOfType = sigsList.front(); + + //use first of type as representative if its in the priority list + auto iter = std::find(acsConfig.code_priorities[sys].begin(), acsConfig.code_priorities[sys].end(), firstOfType.code); + if (iter != acsConfig.code_priorities[sys].end()) + { + obs.Sigs[ftype] = Sig(firstOfType); + } + } + return obsList; + } + catch(...){} + + return ObsList(); + } + /** Return a list of observations from the stream, with a specified timestamp. * This function may be overridden by objects that use this interface */ @@ -37,20 +118,20 @@ struct ObsStream obsWaitCode = E_ObsWaitCode::NO_DATA_WAIT; return obsList; } - + if (time == GTime::noTime()) { obsWaitCode = E_ObsWaitCode::OK; return obsList; } - if (obsList.front().time < time - delta) + if (obsList.front()->time < time - delta) { obsWaitCode = E_ObsWaitCode::EARLY_DATA; return obsList; } - else if (obsList.front().time > time + delta) + else if (obsList.front()->time > time + delta) { obsWaitCode = E_ObsWaitCode::NO_DATA_EVER; return ObsList(); @@ -62,91 +143,39 @@ struct ObsStream } } } - - - /** Check to see if this stream has run out of data - */ - virtual bool isDead() - { - return false; - } - + /** Remove some observations from memory */ void eatObs() { - if (obsListList.size() > 0) + try { - obsListList.pop_front(); + auto& obsLister = dynamic_cast(parser); + + if (obsLister.obsListList.size() > 0) + { + obsLister.obsListList.pop_front(); + } } + catch(...){} } -}; - -/** Interface for streams that supply observations -*/ -struct PseudoObsStream -{ - list obsListList; - string sourceString; - - /** Return a list of observations from the stream. - * This function may be overridden by objects that use this interface - */ - virtual PseudoObsList getObs(); - - /** Return a list of observations from the stream, with a specified timestamp. - * This function may be overridden by objects that use this interface - */ - PseudoObsList getObs( - GTime time, ///< Timestamp to get observations for - double delta = 0.5) ///< Acceptable tolerance around requested time + + bool hasObs() { - while (1) + try { - PseudoObsList pseudoObsList = getObs(); - - if (pseudoObsList.size() == 0) - { - return pseudoObsList; - } - - if (time == GTime::noTime()) - { - return pseudoObsList; - } - - if (pseudoObsList.front().time < time - delta) + auto& obsLister = dynamic_cast(parser); + + if (obsLister.obsListList.empty()) { - eatObs(); - } - else if (pseudoObsList.front().time > time + delta) - { - return PseudoObsList(); - } - else - { - return pseudoObsList; + return false; } + + return true; } - } - - - /** Check to see if this stream has run out of data - */ - virtual bool isDead() - { - return false; - } - - /** Remove some observations from memory - */ - void eatObs() - { - if (obsListList.size() > 0) + catch(...) { - obsListList.pop_front(); + return false; } } }; - -#endif diff --git a/src/cpp/common/streamParser.cpp b/src/cpp/common/streamParser.cpp new file mode 100644 index 000000000..5dd4c99f7 --- /dev/null +++ b/src/cpp/common/streamParser.cpp @@ -0,0 +1,51 @@ + +// #pragma GCC optimize ("O0") + +#include + +#include "streamParser.hpp" + + +multimap streamParserMultimap; +map streamDOAMap; + + + + + +long int streamPos( + std::istream& stream) +{ +// std::cout << "Closed" << std::endl; + if (stream) + { + long int filePos = stream.tellg(); + + if (!stream) + { + BOOST_LOG_TRIVIAL(error) << "Error telling in file at " << filePos << std::endl << " - " << strerror(errno); + + return -1; + } + + if (filePos < 0) + { + BOOST_LOG_TRIVIAL(error) << "Error: Negative file pos in file at " << filePos << std::endl << " - " << strerror(errno); + + return -1; + } + + return filePos; + } + else + { +// BOOST_LOG_TRIVIAL(error) << "InputStream is dead before destruction " << std::endl; + + if (stream.eof()) + { +// BOOST_LOG_TRIVIAL(error) << "InputStream has end of file " << std::endl; + } + return -1; + } +} + diff --git a/src/cpp/common/streamParser.hpp b/src/cpp/common/streamParser.hpp new file mode 100644 index 000000000..a388660ec --- /dev/null +++ b/src/cpp/common/streamParser.hpp @@ -0,0 +1,137 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + +using std::multimap; +using std::string; +using std::tuple; +using std::pair; +using std::map; + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace B_io = boost::iostreams; +namespace B_asio = boost::asio; + +using boost::asio::ip::tcp; + + + + + +long int streamPos( + std::istream& stream); + + + + + + + + + + +#include +#include + +using std::unique_ptr; +using std::make_unique; + + + +struct Stream +{ + string sourceString; + + virtual unique_ptr getIStream_ptr() = 0; + + /** Check to see if this stream has run out of data + */ + virtual bool isDead() + { + return false; + } + + virtual ~Stream() = default; +}; + +struct Parser +{ + virtual void parse(std::istream& inputStream) = 0; + + virtual string parserType() = 0; + + virtual ~Parser() = default; +}; + + +struct SerialStream; + +struct StreamParser +{ +private: + unique_ptr stream_ptr; + unique_ptr parser_ptr; + + //for debugging access only + SerialStream* serialStream_ptr; + +public: + Stream& stream; + Parser& parser; + + StreamParser( + unique_ptr stream_ptr, + unique_ptr parser_ptr) + : stream_ptr (std::move(stream_ptr)), + parser_ptr (std::move(parser_ptr)), + stream (*this->stream_ptr), + parser (*this->parser_ptr) + { + serialStream_ptr = (SerialStream*) &stream; + } + + operator Stream&() + { + return stream; + } + + operator Parser&() + { + return parser; + } + + void parse() + { +// BOOST_LOG_TRIVIAL(debug) << "parsing " << stream.sourceString << " as " << parser.parserType() << std::endl; + + auto iStream_ptr = stream.getIStream_ptr(); + parser.parse(*iStream_ptr); + } + + virtual ~StreamParser() = default; +}; + +typedef std::shared_ptr StreamParserPtr; + +extern multimap streamParserMultimap; +extern map streamDOAMap; diff --git a/src/cpp/common/streamRinex.hpp b/src/cpp/common/streamRinex.hpp index 3ccca859b..c981eaa56 100644 --- a/src/cpp/common/streamRinex.hpp +++ b/src/cpp/common/streamRinex.hpp @@ -1,44 +1,36 @@ -#ifndef __RINEX_STREAM__HPP -#define __RINEX_STREAM__HPP +#pragma once #include "streamObs.hpp" -#include "streamNav.hpp" #include "rinex.hpp" -/** Interface for rinex streams -*/ -struct RinexStream : ObsStream, NavStream + +struct RinexParser : Parser, ObsLister { char ctype; double version; E_Sys nav_system; - int time_system; - map> sysCodeTypes; + E_TimeSys time_system; + map> sysCodeTypes; ObsList tempObsList; - - RinexStream() - { - - } - - void parseRINEX(std::istream& inputStream) + RinexStation rnxStation = {}; + + void parse( + std::istream& inputStream) { //read some of the input,(up to next epoch header?) //save outputs to member variables. //eg. header metadata //eg. list of (ObsLists) with multiple sats, signals combined for each epoch. - //dont parse all, just some. - //this structure to match real-time architecture. int stat = 0; // account for rinex comment in the middle of the file - while ( stat<=0 - &&inputStream) + while ( stat <= 0 + && inputStream) { - stat = readrnx(inputStream, ctype, tempObsList, nav, nullptr, version, nav_system, time_system, sysCodeTypes); + stat = readRnx(inputStream, ctype, tempObsList, nav, &rnxStation, version, nav_system, time_system, sysCodeTypes); } if (tempObsList.size() > 0) @@ -46,29 +38,9 @@ struct RinexStream : ObsStream, NavStream obsListList.push_back(std::move(tempObsList)); } } - - int readRinexHeader(std::istream& inputStream) + + string parserType() { - bool pass = (bool) inputStream; - - if (pass == false) - { - BOOST_LOG_TRIVIAL(error) - << "ERROR: Failed to get good inputStream for RINEX file "; - - return EXIT_FAILURE; - } - - pass = readrnx(inputStream, ctype, tempObsList, nav, &rnxStation, version, nav_system, time_system, sysCodeTypes); - if (pass == false) - { - BOOST_LOG_TRIVIAL(error) - << "ERROR: Failed to read header from RINEX file "; - - return EXIT_FAILURE; - } - return EXIT_SUCCESS; + return "RinexParser"; } }; - -#endif diff --git a/src/cpp/common/streamRtcm.hpp b/src/cpp/common/streamRtcm.hpp index 99c9401c6..7d7835fdd 100644 --- a/src/cpp/common/streamRtcm.hpp +++ b/src/cpp/common/streamRtcm.hpp @@ -1,127 +1,111 @@ -#ifndef __ACSRTCMSTREAM__HPP -#define __ACSRTCMSTREAM__HPP +#pragma once #include -#include - -using std::map; -using std::pair; +#include "streamParser.hpp" #include "rtcmDecoder.hpp" -#include "ntripTrace.hpp" #include "streamObs.hpp" -#include "streamNav.hpp" -struct LockTimeInfo -{ - boost::posix_time::ptime epoch; - map, uint16_t> lock_time_indicators; +#define CLEAN_UP_AND_RETURN_ON_FAILURE \ + \ + if (inputStream.fail()) \ + { \ + inputStream.clear(); \ + inputStream.seekg(pos); \ + return; \ + } - LockTimeInfo(){} - LockTimeInfo(const boost::posix_time::ptime& epoch, - const map, uint16_t>& lockTimeIndicators) - : epoch(epoch), - lock_time_indicators(lockTimeIndicators) - { - } - - pair get_lock_time_and_coefficient( - pair cell) - { - uint32_t b; - uint32_t n; - if (lock_time_indicators.count(cell) > 0) +struct RtcmParser : Parser, RtcmDecoder +{ + void parse( + std::istream& inputStream) + { +// std::cout << "Parsing rtcm" << std::endl; + + while (inputStream) { - auto lock = lock_time_indicators.at(cell); - - if (lock < 64) {b = 1; n = b * lock; } - else if (lock < 96) {b = 2; n = b * lock - 64; } - else if (lock < 128){b = 4; n = b * lock - 256; } - else if (lock < 160){b = 8; n = b * lock - 768; } - else if (lock < 192){b = 16; n = b * lock - 2048; } - else if (lock < 224){b = 32; n = b * lock - 5120; } - else if (lock < 256){b = 64; n = b * lock - 12288; } - else if (lock < 288){b = 128; n = b * lock - 28672; } - else if (lock < 320){b = 256; n = b * lock - 65536; } - else if (lock < 352){b = 512; n = b * lock - 147456; } - else if (lock < 384){b = 1024; n = b * lock - 327680; } - else if (lock < 416){b = 2048; n = b * lock - 720896; } - else if (lock < 448){b = 4096; n = b * lock - 1572864; } - else if (lock < 480){b = 8192; n = b * lock - 3407872; } - else if (lock < 512){b = 16384; n = b * lock - 7340032; } - else if (lock < 544){b = 32768; n = b * lock - 15728640; } - else if (lock < 576){b = 65536; n = b * lock - 33554432; } - else if (lock < 608){b = 131072; n = b * lock - 71303168; } - else if (lock < 640){b = 262144; n = b * lock - 150994944; } - else if (lock < 672){b = 524288; n = b * lock - 318767104; } - else if (lock < 704){b = 1048576; n = b * lock - 671088640; } - else if (lock == 704){b = 2097152; n = b * lock - 1409286144; } + int byteCnt = 0; + int pos; + while (true) + { + // Skip to the start of the frame - marked by preamble character 0xD3 + pos = inputStream.tellg(); + + unsigned char c; + inputStream.read((char*)&c, 1); CLEAN_UP_AND_RETURN_ON_FAILURE; + + if (inputStream) + { + if (c == RTCM_PREAMBLE) + { + break; + } + } + else + { + printf("."); + return; + } + + nonFrameByteFound(c); + } + CLEAN_UP_AND_RETURN_ON_FAILURE; + + preambleFound(); + + // Read the frame length - 2 bytes big endian only want 10 bits + char buf[2]; inputStream.read((char*)buf, 2); CLEAN_UP_AND_RETURN_ON_FAILURE; + + // Message length is 10 bits starting at bit 6 + auto messageLength = getbitu((uint8_t*)buf, 6, 10); + auto dataFrameLength = messageLength + 3; + + // Read the frame data (include the header) + vector data(dataFrameLength); inputStream.read((char*)data.data() + 3, messageLength); CLEAN_UP_AND_RETURN_ON_FAILURE; + + // Read the frame CRC + unsigned int crcRead = 0; inputStream.read((char*)&crcRead, 3); CLEAN_UP_AND_RETURN_ON_FAILURE; + + data[0] = RTCM_PREAMBLE; + data[1] = buf[0]; + data[2] = buf[1]; + unsigned int crcCalc = crc24q(data.data(), data.size()); + + if ( (((char*)&crcCalc)[0] != ((char*)&crcRead)[2]) + ||(((char*)&crcCalc)[1] != ((char*)&crcRead)[1]) + ||(((char*)&crcCalc)[2] != ((char*)&crcRead)[0])) + { + checksumFailure(rtcmMountpoint); + + inputStream.seekg(pos + 1); + + continue; + } + + checksumSuccess(); + + recordFrame(data, crcRead); + + //remove the header to get to the meat of the message + auto& message = data; + message.erase(message.begin(), message.begin()+3); + + auto rtcmReturnType = decode(message); + + if (rtcmReturnType == E_ReturnType::GOT_OBS) { return; } + if (rtcmReturnType == E_ReturnType::WAIT) { inputStream.seekg(pos); return; } + } - - return pair(n, b); } - - static bool LOC(LockTimeInfo& current, - LockTimeInfo& previous, - pair cell) + + string parserType() { - // TODO should we assume continuity or loss of lock when no previous epoch info??? - - if (previous. epoch.is_not_a_date_time()) return false; - if (current. epoch.is_not_a_date_time()) return true; - // From the logic in 3.5.16.3.3 Lock Time Indicator in the RTCM 10403.3 spec - - auto current_lock_time_and_coefficient = current.get_lock_time_and_coefficient(cell); - - auto n = current_lock_time_and_coefficient.first; - auto b = current_lock_time_and_coefficient.second; - - auto previous_lock_time_and_coefficient = previous.get_lock_time_and_coefficient(cell); - - auto p = previous_lock_time_and_coefficient.first; - auto a = previous_lock_time_and_coefficient.second; - - auto dt = (current.epoch - previous.epoch).total_milliseconds(); - - if (p > n) { return true; } - else if (p == n && dt >= a) { return true; } - else if (p == n && dt < a) { return false; } - else if (p < n && b > p && dt >= (n+b-p)) { return true; } - // Do we need the possible LOC??? - else if (p < n && b > p && n < dt && dt < (n+b-p)) { return true; } - else if (p < n && b > p && dt <= n) { return false; } - else if (p < n && b <= p && dt > n) { return true; } - else if (p < n && b <= p && dt <= n) { return false; } - - // Should never get here - return true; + return "RtcmParser"; } }; - -struct RtcmStream : ObsStream, NavStream, RtcmDecoder -{ - LockTimeInfo lock_time_info_current; - LockTimeInfo lock_time_info_previous; - - ObsList SuperList; - - static GTime rtcmDeltaTime; - - string rtcm_filename; - - bool record_rtcm = false; - - void createRtcmFile(); - - void parseRTCM( - std::istream& inputStream); -}; - - -#endif diff --git a/src/cpp/common/streamSerial.cpp b/src/cpp/common/streamSerial.cpp new file mode 100644 index 000000000..8779af102 --- /dev/null +++ b/src/cpp/common/streamSerial.cpp @@ -0,0 +1,17 @@ + + +#include +#include +#include + +#include "streamSerial.hpp" + +void SerialStream::openStream() +{ + fileDescriptor = open(path.c_str(), O_RDWR | O_NONBLOCK); + + if (fileDescriptor < 0) + { + std::cout << std::endl << "Error opening " << path << " as SerialStream"; + } +} diff --git a/src/cpp/common/streamSerial.hpp b/src/cpp/common/streamSerial.hpp new file mode 100644 index 000000000..e118cd02d --- /dev/null +++ b/src/cpp/common/streamSerial.hpp @@ -0,0 +1,135 @@ + +#pragma once + +#include +#include + +#include +#include + +using std::string; +using std::vector; + + +#include +#include + +namespace B_io = boost::iostreams; + + +#include "streamParser.hpp" + + + +struct SerialStateMembers +{ + vector& inputVector; + B_io::basic_array_source input_source; + + SerialStateMembers( + vector& inputVector) + : inputVector (inputVector), + input_source (B_io::basic_array_source (inputVector.data(), inputVector.size())) + { + + } +}; + +struct SerialState : SerialStateMembers, B_io::stream> +{ + SerialState( + vector& inputSource) + : SerialStateMembers (inputSource), + B_io::stream> (input_source) + { +// std::cout << "Serial State created, has length " << inputVector.size() << std::endl; + } + + ~SerialState() + { + long int pos = streamPos(*this); + + if (pos == 0) + { + return; + } + else if (pos > 0) + { + inputVector.erase(inputVector.begin(), inputVector.begin() + pos - 1); + } + else + { + inputVector.clear(); + } + +// std::cout << "Serial State destroyed, has length " << inputVector.size() << std::endl; + } +}; + +struct SerialStream : Stream +{ + string path; + + int fileDescriptor = -1; + + vector receivedData; + + SerialStream() + { + + } + + SerialStream( + string path) + : path (path) + { + openStream(); + } + + void openStream(); + + virtual void getData() + { + if (fileDescriptor < 0) + { + return; + } + + while (1) + { + const int reserve = 0x4000; + int oldSize = receivedData.size(); + + receivedData.resize(receivedData.size() + reserve); + + int n = read(fileDescriptor, &receivedData[oldSize], reserve); + + receivedData.resize(oldSize + n); + + if (n == 0) + { + break; + } + } + } + + unique_ptr getIStream_ptr() override + { + getData(); + + return make_unique(receivedData); + } + + virtual ~SerialStream() + { + if (fileDescriptor < 0) + { + return; + } + + close(fileDescriptor); + }; +}; + + + diff --git a/src/cpp/common/streamSlr.hpp b/src/cpp/common/streamSlr.hpp new file mode 100644 index 000000000..164425609 --- /dev/null +++ b/src/cpp/common/streamSlr.hpp @@ -0,0 +1,42 @@ + +#pragma once + +#include "streamObs.hpp" + +/** Interface for slr streams +*/ +struct SlrParser : Parser, ObsLister +{ + SlrParser() + { + + } + + void parse( + std::istream& inputStream) + { + ObsList obsList; + //read some of the input + //save outputs to member variables. + //dont parse all, just some. + + //this structure to match real-time architecture. + int stat = 0; + while ( stat<=0 + &&inputStream) + { + stat = readSlrObs(inputStream, obsList); + } + + if (obsList.size() > 0) + { + obsListList.push_back(std::move(obsList)); + } + } + + string parserType() + { + return "SlrParser"; + } +}; + diff --git a/src/cpp/common/streamSp3.hpp b/src/cpp/common/streamSp3.hpp index a66e07cb8..7894aaf7b 100644 --- a/src/cpp/common/streamSp3.hpp +++ b/src/cpp/common/streamSp3.hpp @@ -1,60 +1,45 @@ -#ifndef __SP3_STREAM__HPP -#define __SP3_STREAM__HPP - +#pragma once #include "streamObs.hpp" #include "ephemeris.hpp" -/** Interface for rinex streams -*/ -struct SP3Stream : PseudoObsStream +struct Sp3Parser : Parser, ObsLister { - PseudoObsList tempPseudoObsList; + ObsList tempObsList; - bool isUTC = false; - double bfact[2] = {}; - - SP3Stream() - { + E_TimeSys tsys = E_TimeSys::GPST; - } + double bfact[2] = {}; - void parseSP3( + void parse( std::istream& inputStream) { -// //read some of the input,(up to next epoch header?) -// //save outputs to member variables. -// //eg. header metadata -// //eg. list of (ObsLists) with multiple sats, signals combined for each epoch. -// //dont parse all, just some. - list pephList; + vector pephList; - bool more = readsp3(inputStream, pephList, 0, isUTC, bfact); + bool more = readsp3(inputStream, pephList, 0, tsys, bfact); for (auto& peph : pephList) { - PseudoObs pseudoObs; - pseudoObs.pos = peph.Pos; - pseudoObs.vel = peph.Vel; - pseudoObs.time = peph.time; - pseudoObs.Sat = peph.Sat; + PObs pObs; + pObs.pos = peph.pos; + pObs.vel = peph.vel; + pObs.time = peph.time; + pObs.Sat = peph.Sat; - tempPseudoObsList.push_back(pseudoObs); + tempObsList.push_back((shared_ptr)pObs); } - if (tempPseudoObsList.size() > 0) + if (tempObsList.size() > 0) { - obsListList.push_back(std::move(tempPseudoObsList)); + obsListList.push_back(std::move(tempObsList)); } } - - int readSP3Header( - std::istream& inputStream) + + string parserType() { - return EXIT_SUCCESS; + return "Sp3Parser"; } }; -#endif diff --git a/src/cpp/common/streamTrace.cpp b/src/cpp/common/streamTrace.cpp deleted file mode 100644 index 8465a22d7..000000000 --- a/src/cpp/common/streamTrace.cpp +++ /dev/null @@ -1,168 +0,0 @@ - -// #pragma GCC optimize ("O0") - -#include "streamTrace.hpp" -#include -#include -#include -#ifndef WIN32 -# include -# include -# include -# include -# include -#endif - -#include - -#include "observations.hpp" -#include "navigation.hpp" -#include "constants.hpp" -#include "common.hpp" -#include "gTime.hpp" - -boost::iostreams::stream< boost::iostreams::null_sink > nullStream( ( boost::iostreams::null_sink() ) ); - - -void tracematpde( - int level, ///< [] - std::ostream& stream, ///< [] - MatrixXd& mat, ///< [] - int width, ///< [] - int precision) ///< [] -{ - if (level > trace_level) - return; - - stream << std::endl - << std::fixed - << std::setw(width) - << std::setprecision(precision) - << std::endl - << mat - << std::endl; -} - -void tracematpde( - int level, ///< [] - std::ostream& stream, ///< [] - VectorXd& vec, ///< [] - int width, ///< [] - int precision) ///< [] -{ - if (level > trace_level) - return; - - stream << std::fixed - << std::setw(width) - << std::setprecision(precision) - << vec//.transpose() - << std::endl; -} - -void tracematpde( - int level, ///< [] - std::ostream& stream, ///< [] - MatrixXd* mat, ///< [] - int width, ///< [] - int precision) ///< [] -{ - if (level > trace_level) - return; - - stream << std::fixed - << std::setw(width) - << std::setprecision(precision) - << *mat - << std::endl; -} - -void tracematpde( - int level, ///< [] - std::ostream& stream, ///< [] - VectorXd* vec, ///< [] - int width, ///< [] - int precision) ///< [] -{ - if (level > trace_level) - return; - - stream << std::fixed - << std::setw(width) - << std::setprecision(precision) - << vec->transpose() - << std::endl; -} - -/* fatal error ---------------------------------------------------------------*/ -[[deprecated]] -void fatalerr(const char *format, ...) -{ - va_list ap; - va_start(ap,format); vfprintf(stderr,format,ap); va_end(ap); - exit(-9); -} - -/* print matrix ---------------------------------------------------------------- -* print matrix to stdout -* args : double *A I matrix A (n x m) -* int n,m I number of rows and columns of A -* int p,q I total columns, columns under decimal point -* (FILE *fp I output file pointer) -* return : none -* notes : matirix stored by column-major order (fortran convention) -*-----------------------------------------------------------------------------*/ -[[deprecated]] -void matfprint(const double A[], int n, int m, int p, int q, FILE *fp) -{ - int i,j; - - for (i=0;itrace_level) - return; - - va_start(ap,format); - vfprintf(fppde,format,ap); - va_end(ap); - - fflush(fppde); -} - -[[deprecated]] -void tracematpde(int level, FILE *fppde, const double *A, int n, int m, int p, int q) -{ - if (!fppde||level>trace_level) return; - matfprint(A,n,m,p,q,fppde); fflush(fppde); -} diff --git a/src/cpp/common/streamTrace.hpp b/src/cpp/common/streamTrace.hpp deleted file mode 100644 index 2d089363a..000000000 --- a/src/cpp/common/streamTrace.hpp +++ /dev/null @@ -1,83 +0,0 @@ - - -#ifndef _STREAM_TRACE_HPP_ -#define _STREAM_TRACE_HPP_ - - -#include -#include -#include -#include -#include -#include -#include - -using std::string; - -extern boost::iostreams::stream< boost::iostreams::null_sink > nullStream; - - -using Trace = std::ostream; - -#include "eigenIncluder.hpp" - -extern int trace_level; - -void tracematpde(int lv, Trace& stream, MatrixXd& mat, int width, int precision); -void tracematpde(int lv, Trace& stream, VectorXd& vec, int width, int precision); -void tracematpde(int lv, Trace& stream, MatrixXd* mat, int width, int precision); -void tracematpde(int lv, Trace& stream, VectorXd* vec, int width, int precision); - -template -void tracepdeex(int level, Trace& stream, std::string const& fmt, Arguments&&... args) -{ - if (level > trace_level) - return; - - boost::format f(fmt); - int unroll[] {0, (f % std::forward(args), 0)...}; - static_cast(unroll); - - stream << boost::str(f); -} - - -template -std::ofstream getTraceFile( - T& thing) -{ - if (thing.traceFilename.empty()) - { - return std::ofstream(); - } - - std::ofstream trace(thing.traceFilename, std::ios::app); - if (!trace) - { - BOOST_LOG_TRIVIAL(error) - << "Error: Could not open trace file for " << thing.id << " at " << thing.traceFilename; - } - - return trace; -} - -//forward declarations -struct Obs; - -void tracepdeex(int level, FILE *fppde, const char *format, ...); -void tracematpde(int level, FILE *fppde, const double *A, int n, - int m, int p, int q); - -/* debug trace functions -----------------------------------------------------*/ -void tracelevel(int level); -void traceFormatedFloat(Trace& trace, double val, string formatStr); -void matfprint(const double *A, int n, int m, int p, int q, FILE *fp); - -void fatalerr(const char *format, ...); - - -template -std::ofstream getTraceFile(T& thing); - -#endif - diff --git a/src/cpp/common/streamUbx.cpp b/src/cpp/common/streamUbx.cpp new file mode 100644 index 000000000..17615b0b3 --- /dev/null +++ b/src/cpp/common/streamUbx.cpp @@ -0,0 +1,81 @@ + +#include + +#include "packetStatistics.hpp" +#include "streamUbx.hpp" + + +#define CLEAN_UP_AND_RETURN_ON_FAILURE \ + \ + if (inputStream.fail()) \ + { \ + inputStream.clear(); \ + inputStream.seekg(pos); \ + return; \ + } + + +void UbxParser::parse( + std::istream& inputStream) +{ +// std::cout << "Parsing ubx" << std::endl; + + while (inputStream) + { + int pos; + unsigned char c1 = 0; + unsigned char c2 = 0; + while (true) + { + pos = inputStream.tellg(); + + //move c2 back one and replace, (check one byte at a time, not in pairs) + c1 = c2; + inputStream.read((char*)&c2, 1); + + if (inputStream) + { + if ( c1 == UBX_PREAMBLE1 + &&c2 == UBX_PREAMBLE2) + { + break; + } + } + else + { + return; + } + nonFrameByteFound(c2); + } + CLEAN_UP_AND_RETURN_ON_FAILURE; + + //account for 2 byte preamble + pos--; + + preambleFound(); + + unsigned char ubxClass = 0; inputStream.read((char*)&ubxClass, 1); CLEAN_UP_AND_RETURN_ON_FAILURE; + unsigned char id = 0; inputStream.read((char*)&id, 1); CLEAN_UP_AND_RETURN_ON_FAILURE; + unsigned short int payload_length = 0; inputStream.read((char*)&payload_length, 2); CLEAN_UP_AND_RETURN_ON_FAILURE; + vector payload(payload_length); inputStream.read((char*)payload.data(), payload_length); CLEAN_UP_AND_RETURN_ON_FAILURE; // Read the frame data (include the header) + unsigned short int crcRead = 0; inputStream.read((char*)&crcRead, 2); CLEAN_UP_AND_RETURN_ON_FAILURE; + + //todo aaron calculate crcRead + if (0) + { + checksumFailure(); + + inputStream.seekg(pos + 1); + + continue; + } + + checksumSuccess(); + + recordFrame(ubxClass, id, payload, crcRead); + + decode(ubxClass, id, payload); + } + inputStream.clear(); +} + diff --git a/src/cpp/common/streamUbx.hpp b/src/cpp/common/streamUbx.hpp new file mode 100644 index 000000000..65c6c9c7e --- /dev/null +++ b/src/cpp/common/streamUbx.hpp @@ -0,0 +1,23 @@ + +#pragma once + + +#include "packetStatistics.hpp" +#include "streamParser.hpp" +#include "ubxDecoder.hpp" +#include "streamObs.hpp" + +#define UBX_PREAMBLE1 0xB5 +#define UBX_PREAMBLE2 0x62 + +struct UbxParser : Parser, UbxDecoder, PacketStatistics +{ + void parse( + std::istream& inputStream); + + string parserType() + { + return "UbxParser"; + } +}; + diff --git a/src/cpp/common/summary.cpp b/src/cpp/common/summary.cpp index 8aad8e93e..95e2da55a 100644 --- a/src/cpp/common/summary.cpp +++ b/src/cpp/common/summary.cpp @@ -3,6 +3,22 @@ #include "summary.hpp" +void outputStatistics( + Trace& trace, + map& statisticsMap, + map& statisticsMapSum) +{ + Block block(trace, "Filter Statistics"); + + for (auto& [str, count] : statisticsMap) + { + tracepdeex(0, trace, "! %-30s: %d\n", str.c_str(), count); + statisticsMapSum[str] += count; + } + + statisticsMap.clear(); +} + /** Output statistics from each station. * Including observation counts, slips, beginning and ending epochs*/ void outputSummaries( @@ -14,8 +30,8 @@ void outputSummaries( for (auto& [id, rec] : stationMap) { trace << std::endl << "------------------- " << rec.id << " --------------------"; - auto a = boost::posix_time::from_time_t(rec.firstEpoch.time); - auto b = boost::posix_time::from_time_t(rec.lastEpoch.time); + auto a = boost::posix_time::from_time_t((time_t)rec.firstEpoch.bigTime); + auto b = boost::posix_time::from_time_t((time_t)rec.lastEpoch. bigTime); auto ab = b-a; trace << std::endl << "First Epoch : " << a; @@ -49,7 +65,8 @@ void outputSummaries( trace << sat << " : " << count; } - trace << std::endl << "Obs/Slips : " << rec.obsCount / (rec.slipCount + 1); + trace << std::endl << "GObs/Slips : " << rec.obsCount / (rec.slipCount + 1); trace << std::endl; } + } diff --git a/src/cpp/common/summary.hpp b/src/cpp/common/summary.hpp index 9e736da2c..eb97008ea 100644 --- a/src/cpp/common/summary.hpp +++ b/src/cpp/common/summary.hpp @@ -1,15 +1,18 @@ -#ifndef __SUMMARY_HPP__ -#define __SUMMARY_HPP__ + +#pragma once #include using std::map; -#include "streamTrace.hpp" #include "station.hpp" +#include "trace.hpp" + +void outputStatistics( + Trace& trace, + map& statisticsMap, + map& statisticsMapSum); void outputSummaries( Trace& trace, map& stationMap); - -#endif diff --git a/src/cpp/common/testUtils.cpp b/src/cpp/common/testUtils.cpp index 570aeaa63..dfe08b1f7 100644 --- a/src/cpp/common/testUtils.cpp +++ b/src/cpp/common/testUtils.cpp @@ -297,7 +297,7 @@ bool TestStack::checkMat( int n) ///< Number of elements in matrix { #ifdef ENABLE_UNIT_TESTS - if ( (acsConfig.testOpts.enable == false) + if ( acsConfig.testOpts.enable == false // ||(DontTest) ) { diff --git a/src/cpp/common/testUtils.hpp b/src/cpp/common/testUtils.hpp index 24bbaed03..4761ae73d 100644 --- a/src/cpp/common/testUtils.hpp +++ b/src/cpp/common/testUtils.hpp @@ -1,7 +1,5 @@ -#ifndef __TEST_UTILS_H__ -#define __TEST_UTILS_H__ - +#pragma once #include #include @@ -9,9 +7,6 @@ namespace sinks = boost::log::sinks; - - -#include #include #include #include @@ -20,7 +15,6 @@ namespace sinks = boost::log::sinks; #include #include -using std::unordered_map; using std::vector; using std::string; using std::tuple; @@ -131,22 +125,6 @@ struct TestStack string str); }; -struct TestClipper -{ - bool oldVal = false; - - TestClipper() - { - oldVal = TestStack::DontTest; - TestStack::DontTest = true; - } - - ~TestClipper() - { - TestStack::DontTest = oldVal; - } -}; - struct ErrorExit : public sinks::basic_formatted_sink_backend { // The function consumes the log records that come from the frontend @@ -157,7 +135,6 @@ struct ErrorExit : public sinks::basic_formatted_sink_backend +#include + +#include +#include + +#include "observations.hpp" +#include "navigation.hpp" +#include "constants.hpp" +#include "acsConfig.hpp" +#include "common.hpp" +#include "gTime.hpp" +#include "trace.hpp" + +boost::iostreams::stream nullStream((boost::iostreams::null_sink())); + + + +void ConsoleLog::consume( + boost::log::record_view const& rec, + sinks::basic_formatted_sink_backend::string_type const& logString) +{ + static map warnedMap; + + auto attrs = rec.attribute_values(); + auto sev = attrs[boost::log::trivial::severity].get(); + + if (sev == boost::log::trivial::warning) + { + auto& warned = warnedMap[logString]; + if (warned) + { + return; + } + + warned = true; + } + + std::cout << std::endl << logString << std::flush; +} + + +int trace_level = 0; ///< level of trace + +void tracelevel(int level) +{ + trace_level = level; +} + +void traceFormatedFloat(Trace& trace, double val, string formatStr) +{ + // If someone knows how to make C++ print with just one digit as exponent... + int exponent = 0; + double base = 0; + + if (val != 0) + { + exponent = (int)floor(log10(fabs(val))); + base = val * pow(10, -1 * exponent); + } + tracepdeex(0, trace, formatStr.c_str(), base, exponent); +} + +void tracepdeex(int level, FILE *fppde, const char *format, ...) +{ + va_list ap; + + if (!fppde||level>trace_level) + return; + + va_start(ap,format); + vfprintf(fppde,format,ap); + va_end(ap); + + fflush(fppde); +} + + +void printHex( + Trace& trace, + vector chunk) +{ + trace << "\nHex Data : "; + + for (int i = 0; i < chunk.size(); i++) + { + if (i % 10 == 0) + trace << std::endl; + char hex[3]; + snprintf(hex, sizeof(hex),"%02x",(unsigned char) chunk[i]); + tracepdeex(0, trace, "%s ", hex); + } + trace << std::endl; +} + + +void mongoTrace(string); + +void traceJson( + int level, + Trace& trace, + string time, + vector id, + vector val) +{ + if (level > trace_level) + return; + + if ( acsConfig.output_json_trace == false + &&acsConfig.localMongo.output_trace) + { + return; + } + + string json = "{ \"time\":\"" + time + "\", \"id\":{"; + for (auto& thing : id) + { + json += "\"" + thing.name + "\":" + thing.value() + ","; + } + json = json.substr(0, json.length() - 1); + + json += "}, \"val\":{"; + + for (auto& thing : val) + { + json += "\"" + thing.name + "\":" + thing.value() + ","; + } + json = json.substr(0, json.length() - 1); + json += "} }"; + + if (acsConfig.output_json_trace) + { + trace << "\n - " + json; + } + if (acsConfig.localMongo.output_trace) + { + mongoTrace(json); + } +} + diff --git a/src/cpp/common/trace.hpp b/src/cpp/common/trace.hpp new file mode 100644 index 000000000..3e61f83d9 --- /dev/null +++ b/src/cpp/common/trace.hpp @@ -0,0 +1,136 @@ + + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace sinks = boost::log::sinks; + + +#include +#include +#include + + +using std::vector; +using std::string; + +extern boost::iostreams::stream< boost::iostreams::null_sink> nullStream; + + +using Trace = std::ostream; + +#include "eigenIncluder.hpp" + +struct ConsoleLog : public sinks::basic_formatted_sink_backend +{ + // The function consumes the log records that come from the frontend + void consume( + boost::log::record_view const& rec, + sinks::basic_formatted_sink_backend::string_type const& log_string); +}; + +extern int trace_level; + +template +void tracepdeex(int level, Trace& stream, string const& fmt, Arguments&&... args) +{ + if (level > trace_level) + return; + + boost::format f(fmt); + int unroll[] {0, (f % std::forward(args), 0)...}; + static_cast(unroll); + + stream << boost::str(f); +} + + +template +std::ofstream getTraceFile( + T& thing) +{ + if (thing.traceFilename.empty()) + { + return std::ofstream(); + } + + std::ofstream trace(thing.traceFilename, std::ios::app); + if (!trace) + { + BOOST_LOG_TRIVIAL(error) + << "Error: Could not open trace file for " << thing.id << " at " << thing.traceFilename; + } + + return trace; +} + +void printHex( + Trace& trace, + vector chunk); + +void tracelevel(int level); +void traceFormatedFloat(Trace& trace, double val, string formatStr); + +void fatalerr(const char *format, ...); + + +template +std::ofstream getTraceFile(T& thing); + + +struct Block +{ + Trace& trace; + string blockName; + + Block( + Trace& trace, + string blockName) + : trace {trace}, + blockName {blockName} + { + trace << std::endl << "+" << blockName << std::endl; + } + + ~Block() + { + trace << "-" << blockName << std::endl; + } +}; + +struct ArbitraryKVP +{ + string name; + string str; + double num; + int integer; + int type = 0; + + ArbitraryKVP(string name, string str) : name {name}, str {str } { type = 0; } + ArbitraryKVP(string name, double num) : name {name}, num {num } { type = 1; } + ArbitraryKVP(string name, int integer) : name {name}, integer {integer } { type = 2; } + + string value() + { + if (type == 0) return "\"" + str + "\""; + else if (type == 1) return std::to_string(num); + else if (type == 2) return std::to_string(integer); + else return ""; + } +}; + +void traceJson( + int level, + Trace& trace, + string time, + vector id, + vector val); diff --git a/src/cpp/common/tropSinex.cpp b/src/cpp/common/tropSinex.cpp index 325b97046..6f6991bcb 100644 --- a/src/cpp/common/tropSinex.cpp +++ b/src/cpp/common/tropSinex.cpp @@ -1,6 +1,7 @@ #include #include "eigenIncluder.hpp" +#include "coordinates.hpp" #include "instrument.hpp" #include "acsConfig.hpp" #include "station.hpp" @@ -15,24 +16,16 @@ using std::ofstream; /** Reset comments to their default values */ -void resetCommentsToDefault() -{ - if (!theSinex.tropDesc. isEmpty) {theSinex.tropDescCommentList. clear(); theSinex.tropDescCommentList. push_back("*_________KEYWORD_____________ __VALUE(S)_______________________________________");} // TROP/DESCRIPTION - if (!theSinex.map_siteids. empty()) {theSinex.tropSiteIdCommentList. clear(); theSinex.tropSiteIdCommentList. push_back("*STATION__ PT __DOMES__ T _STATION_DESCRIPTION__ _LONGITUDE _LATITUDE_ _HGT_ELI_ HGT_GEOID");} // SITE/ID - if (!theSinex.map_receivers. empty()) {theSinex.tropSiteRecCommentList. clear(); theSinex.tropSiteRecCommentList. push_back("*STATION__ PT SOLN T DATA_START____ DATA_END______ DESCRIPTION_________ S/N_________________ FIRMWARE___");} // SITE/RECEIVER - if (!theSinex.map_antennas. empty()) {theSinex.tropSiteAntCommentList. clear(); theSinex.tropSiteAntCommentList. push_back("*STATION__ PT SOLN T DATA_START____ DATA_END______ DESCRIPTION_________ S/N_________________ PCV_MODEL_");} // SITE/ANTENNA - if (!theSinex.map_eccentricities. empty()) {theSinex.tropSiteEccCommentList. clear(); theSinex.tropSiteEccCommentList. push_back("* _UP_____ _NORTH__ _EAST___"); - theSinex.tropSiteEccCommentList. push_back("*STATION__ PT SOLN T DATA_START____ DATA_END______ REF _MARKER->ARP(m)____________");} // SITE/ECCENTRICITY - if (!theSinex.tropSiteCoordMapMap. empty()) {theSinex.tropSiteCoordCommentList.clear(); theSinex.tropSiteCoordCommentList. push_back("*STATION__ PT SOLN T __DATA_START__ __DATA_END____ __STA_X_____ __STA_Y_____ __STA_Z_____ SYSTEM REMRK");} // SITE/COORDINATES -} - -/** Set marker name for file header - */ -void setSinexMarkerName( - string markerName) ///< 4-char rec ID for PPP, 'MIX' for network -{ - theSinex.markerName = markerName.substr(0,4); -} +// void resetCommentsToDefault() +// { +// if (!theSinex.tropDesc. isEmpty) {theSinex.tropDescCommentList. clear(); theSinex.tropDescCommentList. push_back("*_________KEYWORD_____________ __VALUE(S)_______________________________________");} // TROP/DESCRIPTION +// if (!theSinex.map_siteids. empty()) {theSinex.tropSiteIdCommentList. clear(); theSinex.tropSiteIdCommentList. push_back("*STATION__ PT __DOMES__ T _STATION_DESCRIPTION__ _LONGITUDE _LATITUDE_ _HGT_ELI_ HGT_GEOID");} // SITE/ID +// if (!theSinex.map_receivers. empty()) {theSinex.tropSiteRecCommentList. clear(); theSinex.tropSiteRecCommentList. push_back("*STATION__ PT SOLN T DATA_START____ DATA_END______ DESCRIPTION_________ S/N_________________ FIRMWARE___");} // SITE/RECEIVER +// if (!theSinex.map_antennas. empty()) {theSinex.tropSiteAntCommentList. clear(); theSinex.tropSiteAntCommentList. push_back("*STATION__ PT SOLN T DATA_START____ DATA_END______ DESCRIPTION_________ S/N_________________ PCV_MODEL_");} // SITE/ANTENNA +// if (!theSinex.map_eccentricities. empty()) {theSinex.tropSiteEccCommentList. clear(); theSinex.tropSiteEccCommentList. push_back("* _UP_____ _NORTH__ _EAST___"); +// theSinex.tropSiteEccCommentList. push_back("*STATION__ PT SOLN T DATA_START____ DATA_END______ REF _MARKER->ARP(m)____________");} // SITE/ECCENTRICITY +// if (!theSinex.tropSiteCoordMapMap. empty()) {theSinex.tropSiteCoordCommentList.clear(); theSinex.tropSiteCoordCommentList. push_back("*STATION__ PT SOLN T __DATA_START__ __DATA_END____ __STA_X_____ __STA_Y_____ __STA_Z_____ SYSTEM REMRK");} // SITE/COORDINATES +// } /** Write out trop sinex file header */ @@ -58,7 +51,7 @@ void writeTropHeader( /** Set data for trop description block */ -void setTropDesc( +void setDescription( bool isSmoothed) ///< if solution is smoothed (RTS or fixed-lag) { string tropEstMethod; @@ -75,7 +68,6 @@ void setTropDesc( theSinex.tropDesc.strings ["TROPO MAPPING FUNCTION"] = acsConfig.model.trop.model._to_string(); theSinex.tropDesc.strings ["GRADS MAPPING FUNCTION"] = acsConfig.gradient_mapping_function; theSinex.tropDesc.ints ["ELEVATION CUTOFF ANGLE"] = acsConfig.elevation_mask*R2D; - theSinex.tropDesc.vecStrings["TROPO PARAMETER NAMES"].clear(); theSinex.tropDesc.vecStrings["TROPO PARAMETER UNITS"].clear(); theSinex.tropDesc.vecStrings["TROPO PARAMETER WIDTH"].clear(); @@ -94,11 +86,12 @@ void setTropDesc( /** Write TROP/DESCRIPTION block */ -int writeTropDesc( +void writeTropDesc( ofstream& out) ///< stream to write out { - out << "+TROP/DESCRIPTION" << endl; - write_as_comments(out, theSinex.tropDescCommentList); + Block block(out, "TROP/DESCRIPTION"); + + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [key, entry] : theSinex.tropDesc.strings) tracepdeex(0, out, " %-29s %22s\n", key, entry); for (auto& [key, entry] : theSinex.tropDesc.ints) tracepdeex(0, out, " %-29s %22d\n", key, entry); @@ -109,20 +102,17 @@ int writeTropDesc( for (auto& str : entry) tracepdeex(0, out, " %6s", str); tracepdeex(0, out, "\n"); } - - out << "-TROP/DESCRIPTION" << endl; - return 0; } /** Write SITE/ID block */ -int writeTropSiteId( +void writeTropSiteId( ofstream& out, ///< stream to write out string markerName) ///< recID if individual rec used for soln, else blank { - out << "+SITE/ID" << endl; - - write_as_comments(out, theSinex.tropSiteIdCommentList); + Block block(out, "SITE/ID"); + + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [id, ssi] : theSinex.map_siteids) { @@ -131,40 +121,49 @@ int writeTropSiteId( { continue; } - if (ssi.used == false) continue; - // Calc rec pos (ECEF) - double lat = ssi.lat_deg + ssi.lat_min /60.0 + ssi.lat_sec /60.0/60.0; - double lon = ssi.long_deg + ssi.long_min/60.0 + ssi.long_sec/60.0/60.0; - double ht = ssi.height; - double pos[3] = { lat*D2R, - lon*D2R, - ht }; + // Retrieve rec pos + VectorPos pos; + pos.lat() = ssi.lat_deg + ssi.lat_min / 60.0 + ssi.lat_sec / 60.0 / 60.0; + pos.lon() = ssi.lon_deg + ssi.lon_min / 60.0 + ssi.lon_sec / 60.0 / 60.0; + pos.hgt() = ssi.height; + Vector3d rRec; - pos2ecef(pos, rRec); + auto it = theSinex.tropSiteCoordMapMap.find(id); + if (it != theSinex.tropSiteCoordMapMap.end()) + { + auto& [key, coords] = *it; + rRec(0) = coords[0]; + rRec(1) = coords[1]; + rRec(2) = coords[2]; + } + else + { + rRec = pos2ecef(pos); + } // Calc ant offset (ECEF) - // retrieve eccentricitiy - from sinexPerEpochPerStation() - Sinex_stn_snx_t stationSinex; - int result = getstnsnx(id, theSinex.solution_start_date, stationSinex); - if (result == E_SnxDataMissing::SITE_ID) continue; // Station not found in sinex file - if (result == E_SnxDataMissing::ESTIMATE) continue; // Position not found in sinex file + SinexRecData stationSinex; + + auto result = getStnSnx(id, theSinex.solution_start_date, stationSinex); + + if (result.failureSiteId) continue; // Station not found in sinex file + if (result.failureEstimate) continue; // Position not found in sinex file //todo aaron, remove this, use other function - Vector3d& antdel = stationSinex.ecc; - Vector3d dr1; - enu2ecef(pos, antdel, dr1); + VectorEnu& antdel = stationSinex.ecc_ptr->ecc; + Vector3d dr1 = enu2ecef(pos, antdel); // Calc ant pos (ECEF), convert to lat/lon/ht rRec += dr1; - ecef2pos(rRec, pos); - lat = pos[0]*R2D; - lon = pos[1]*R2D; - ht = pos[2]; + pos = ecef2pos(rRec); + double lat = pos.latDeg(); + double lon = pos.lonDeg(); + double hgt = pos.hgt(); while (lon < 0) - lon += 360.0; + lon += 360; double offset = egm96_compute_altitude_offset(lat, lon); @@ -176,24 +175,20 @@ int writeTropSiteId( ssi.desc, lon, lat, - ht, - ht + offset); + hgt, + hgt - offset); } - - out << "-SITE/ID" << endl; - - return 0; } /** Write SITE/RECEIVER block */ -int writeTropSiteRec( +void writeTropSiteRec( ofstream& out, ///< stream to write out string markerName) ///< recID if individual rec used for soln, else blank { - out << "+SITE/RECEIVER" << endl; - - write_as_comments(out, theSinex.tropSiteRecCommentList); + Block block(out, "SITE/RECEIVER"); + + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [id, timemap] : theSinex.map_receivers) for (auto it = timemap.rbegin(); it != timemap.rend(); it++) @@ -209,44 +204,41 @@ int writeTropSiteRec( if (receiver.used == false) continue; - if (receiver.recsn. empty()) receiver.recsn = "-----"; - if (receiver.recfirm. empty()) receiver.recfirm = "-----"; + if (receiver.sn. empty()) receiver.sn = "-----"; + if (receiver.firm. empty()) receiver.firm = "-----"; tracepdeex(0, out, " %-9s %2s %4s %c %04d:%03d:%05d %04d:%03d:%05d %20s %-20s %s\n", receiver.sitecode .c_str(), receiver.ptcode .c_str(), receiver.solnid .c_str(), receiver.typecode, - receiver.recstart[0], - receiver.recstart[1], - receiver.recstart[2], - receiver.recend[0], - receiver.recend[1], - receiver.recend[2], - receiver.rectype .c_str(), - receiver.recsn .c_str(), - receiver.recfirm .c_str()); + receiver.start[0], + receiver.start[1], + receiver.start[2], + receiver.end[0], + receiver.end[1], + receiver.end[2], + receiver.type .c_str(), + receiver.sn .c_str(), + receiver.firm .c_str()); } - - out << "-SITE/RECEIVER" << endl; - return 0; } /** Set antenna calibration model data for SITE/ANTENNA block */ -void setTropSiteAntCalibModelsFromNav() +void setSiteAntCalib() { string defaultStr = "-----"; for (auto& [site, antmap] : theSinex.map_antennas) for (auto it = antmap.rbegin(); it != antmap.rend(); it++) { auto& [time, ant] = *it; - if ( ant.calibModel == "" + if ( ant.calibModel.empty() ||ant.calibModel == defaultStr) { ant.calibModel = defaultStr; PhaseCenterData* pcd_ptr; - bool pass = findAntenna(ant.anttype, E_Sys::GPS, time, nav, F1, &pcd_ptr); + bool pass = findAntenna(ant.type, E_Sys::GPS, time, nav, F1, &pcd_ptr); if (pass) ant.calibModel = pcd_ptr->calibModel; } @@ -255,13 +247,13 @@ void setTropSiteAntCalibModelsFromNav() /** Write SITE/ANTENNA block */ -int writeTropSiteAnt( +void writeTropSiteAnt( ofstream& out, ///< stream to write out string markerName) ///< recID if individual rec used for soln, else blank { - out << "+SITE/ANTENNA" << endl; - - write_as_comments(out, theSinex.tropSiteAntCommentList); + Block block(out, "SITE/ANTENNA"); + + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [id, antmap] : theSinex.map_antennas) for (auto it = antmap.rbegin(); it != antmap.rend(); it++) @@ -273,40 +265,35 @@ int writeTropSiteAnt( { continue; } - if (ant.used == false) continue; - tracepdeex(0, out, " %-9s %2s %4s %c %04d:%03d:%05d %04d:%03d:%05d %20s %-20s %-10s\n", ant.sitecode, ant.ptcode, ant.solnnum, ant.typecode, - ant.antstart[0], - ant.antstart[1], - ant.antstart[2], - ant.antend[0], - ant.antend[1], - ant.antend[2], - ant.anttype, - ant.antsn, + ant.start[0], + ant.start[1], + ant.start[2], + ant.end[0], + ant.end[1], + ant.end[2], + ant.type, + ant.sn, ant.calibModel); } - - out << "-SITE/ANTENNA" << endl; - return 0; } /** Write SITE/ECCENTRICITY block */ -int writeTropSiteEcc( +void writeTropSiteEcc( ofstream& out, ///< stream to write out string markerName) ///< recID if individual rec used for soln, else blank { - out << "+SITE/ECCENTRICITY" << endl; - - write_as_comments(out, theSinex.tropSiteEccCommentList); + Block block(out, "SITE/ECCENTRICITY"); + + write_as_comments(out, theSinex.blockComments[block.blockName]); for (auto& [id, setMap] : theSinex.map_eccentricities) for (auto it = setMap.rbegin(); it != setMap.rend(); it++) @@ -318,7 +305,6 @@ int writeTropSiteEcc( { continue; } - if (set.used == false) continue; @@ -327,65 +313,54 @@ int writeTropSiteEcc( set.ptcode, set.solnnum, set.typecode, - set.eccstart[0], - set.eccstart[1], - set.eccstart[2], - set.eccend[0], - set.eccend[1], - set.eccend[2], - set.eccrs, + set.start[0], + set.start[1], + set.start[2], + set.end[0], + set.end[1], + set.end[2], + set.rs, set.ecc[2], set.ecc[1], set.ecc[0]); } - - out << "-SITE/ECCENTRICITY" << endl; - return 0; } /** Set site coordinates from filter */ void setTropSiteCoordsFromFilter( - map& stationMap) ///< map of stations used in network + KFState& kfState) ///< KF state { -// Instrument instrument(__FUNCTION__); - - // Merge rec & network filters - list kfStatePointers; - - if (acsConfig.process_user) - for (auto& [key, rec] : stationMap) - { - kfStatePointers.push_back(&rec.pppState); - } - - theSinex.tropKFState = mergeFilters(kfStatePointers, true); - - for (auto& [key, index] : theSinex.tropKFState.kfIndexMap) + for (auto& [key, index] : kfState.kfIndexMap) { if (key.type != KF::REC_POS) { continue; } - theSinex.tropKFState.getKFValue(key, theSinex.tropSiteCoordMapMap[key.str][key.num]); + kfState.getKFValue(key, theSinex.tropSiteCoordMapMap[key.str][key.num]); } } /** Write SITE/COORDINATES block */ -int writeTropSiteCoord( +void writeTropSiteCoord( ofstream& out, ///< stream to write out string markerName, ///< recID if individual rec used for soln, else blank - bool firstWrite) ///< first time file is being written to (writes header if true) + string filename) ///< filename of file to write out { - if (firstWrite) + long int pos = theSinex.tropSiteCoordBodyFPosMap[filename]; + if (pos == 0) { out << "+SITE/COORDINATES" << endl; - write_as_comments(out, theSinex.tropSiteCoordCommentList); - theSinex.tropSiteCoordBodyFPosMap[markerName] = out.tellp(); + + write_as_comments(out, theSinex.blockComments["SITE/COORDINATES"]); + + pos = out.tellp(); + + theSinex.tropSiteCoordBodyFPosMap[filename] = pos; } - out.seekp(theSinex.tropSiteCoordBodyFPosMap[markerName]); // Overwrite previous body entries + out.seekp(pos); // Overwrite previous body entries for (auto& [id, entry] : theSinex.tropSiteCoordMapMap) { @@ -413,15 +388,13 @@ int writeTropSiteCoord( acsConfig.analysis_agency); } - out << "-SITE/COORDINATES" << endl; - return 0; + out << "-SITE/COORDINATES" << endl << endl; } /** Set troposphere solution data from filter */ -void setTropSolsFromFilter( -// bool isUserMode, ///< True: user mode; false: network mode - bool isSmoothed) ///< if solution is smoothed (RTS or fixed-lag) +void setTropSolFromFilter( + KFState& kfState) ///< KF state { // Retrieve & accumulate KF & preprocessor values struct State @@ -432,67 +405,42 @@ void setTropSolsFromFilter( map> tropSumMap; //for summing similar components - eg trop and trop_gm - for (auto& [key, index] : theSinex.tropKFState.kfIndexMap) + for (auto& [key, index] : kfState.kfIndexMap) { if ( key.type != KF::TROP - &&key.type != KF::TROP_GM) + &&key.type != KF::TROP_GRAD) { continue; } string type; - if (key.num == 0) type = "TRO"; //zenith - else if (key.num == 1) type = "TGN"; //N gradient - else if (key.num == 2) type = "TGE"; //E gradient + if (key.type == KF::TROP) type = "TRO"; //zenith + else if (key.type == KF::TROP_GRAD && key.num == 0) type = "TGN"; //N gradient + else if (key.type == KF::TROP_GRAD && key.num == 1) type = "TGE"; //E gradient - string typeWet = type + "WET"; - string typeTotal = type + "TOT"; + string typeWet = type + "WET"; + string typeTot = type + "TOT"; string id = theSinex.map_siteids[key.str].sitecode; double x = 0; double var = 0; - theSinex.tropKFState.getKFValue(key, x, &var); + kfState.getKFValue(key, x, &var); double oldVar = tropSumMap[id][typeWet].var; double newVar = var + oldVar; //Ref: https://en.wikipedia.org/wiki/Propagation_of_uncertainty#Example_formulae - switch (key.num) - { - case 0: //zenith - { - // Add on filter estimates - tropSumMap[id][typeWet] .x += x; - tropSumMap[id][typeTotal] .x += x; - tropSumMap[id][typeWet] .var = newVar; - tropSumMap[id][typeTotal] .var = newVar; - break; - } - - case 1: //N grad - case 2: //E grad - { - tropSumMap[id][typeWet] .x += x; - tropSumMap[id][typeWet] .var = newVar; - break; - } - - default: - { - BOOST_LOG_TRIVIAL(error) - << "Error: Unknown trop key.num " << key.num; - } - } + // Add on filter estimates + if (key.type == KF::TROP) { tropSumMap[id][typeTot].x += x; tropSumMap[id][typeTot].var = newVar; } + { tropSumMap[id][typeWet].x += x; tropSumMap[id][typeWet].var = newVar; } } // Store accumulated trop values for writing out later for (auto& [id, entries] : tropSumMap) { - SinexTropSol StationEntry; - StationEntry.site = id; - StationEntry.epoch[0] = theSinex.solution_end_date[0]; - StationEntry.epoch[1] = theSinex.solution_end_date[1]; - StationEntry.epoch[2] = theSinex.solution_end_date[2]; + SinexTropSol stationEntry; + stationEntry.site = id; + stationEntry.yds = theSinex.solution_end_date; for (auto& [type, entry] : entries) { @@ -516,22 +464,21 @@ void setTropSolsFromFilter( auto& [key, coords] = *it; - double ecef[3] = { coords[0], - coords[1], - coords[2]}; - double pos[3]; - ecef2pos(ecef, pos); + VectorEcef ecef = Vector3d( coords[0], + coords[1], + coords[2]); //todo aaron, why are these all arrays? + VectorPos pos = ecef2pos(ecef); - double azel[3] = {0,1,0}; // not used in zhd calc, but tropacs has el>0 requirement + double azel[2] = {0,1}; // not used in zhd calc, but tropacs has el>0 requirement double modelledZhd = tropacs(pos, azel); entry.x -= modelledZhd; } - StationEntry.solutions.push_back({type, entry.x, units, 8}); //type, value, units (multiplier), printing width - StationEntry.solutions.push_back({"STDDEV", sqrt(entry.var), 1e3, 8}); + stationEntry.solutions.push_back({type, entry.x, units, 8}); //type, value, units (multiplier), printing width + stationEntry.solutions.push_back({"STDDEV", sqrt(entry.var), 1e3, 8}); } - theSinex.tropSolList.push_back(StationEntry); + theSinex.tropSolList.push_back(stationEntry); } } @@ -548,26 +495,27 @@ void setTropSolCommentList() headerFields << " " << std::setw(entry.width) << entry.type; } - theSinex.tropSolCommentList.clear(); - theSinex.tropSolCommentList.push_back("*STATION__ ____EPOCH_____" + headerFields.str()); +// theSinex.tropSolCommentList.clear(); +// theSinex.tropSolCommentList.push_back("*STATION__ ____EPOCH_____" + headerFields.str()); } /** Set troposphere solution data */ -void setTropSols( - bool isSmoothed) ///< if solution is smoothed (RTS or fixed-lag) +void setTropSol( + KFState& kfState) ///< KF state { - switch (acsConfig.trop_data_source) + auto source = acsConfig.trop_sinex_data_sources.front(); + switch (source) { - case E_Ephemeris::KALMAN: + case E_Source::KALMAN: { - setTropSolsFromFilter(isSmoothed); + setTropSolFromFilter(kfState); break; } default: { BOOST_LOG_TRIVIAL(error) - << "Error: Unrecognised troposphere delay source " << acsConfig.trop_data_source; + << "Error: Unrecognised troposphere delay source " << source; } } setTropSolCommentList(); @@ -575,19 +523,22 @@ void setTropSols( /** Write TROP/SOLUTION block */ -int writeTropSol( +void writeTropSol( ofstream& out, ///< stream to write out string markerName, ///< recID if individual rec used for soln, else blank - bool firstWrite) ///< first time file is being written to (writes header if true) + string filename) ///< filename of file to write out { - if (firstWrite) + long int pos = theSinex.tropSolFootFPosMap[filename]; + if (pos == 0) { out << "+TROP/SOLUTION" << endl; - write_as_comments(out, theSinex.tropSolCommentList); - theSinex.tropSolFootFPosMap[markerName] = out.tellp(); + write_as_comments(out, theSinex.blockComments["TROP/SOLUTION"]); + + pos = out.tellp(); + theSinex.tropSolFootFPosMap[filename] = pos; } - out.seekp(theSinex.tropSolFootFPosMap[markerName]); // Append body entries each epoch, overwriting previous footer + out.seekp(pos); // Append body entries each epoch, overwriting previous footer for (auto& entry : theSinex.tropSolList) { @@ -599,9 +550,9 @@ int writeTropSol( tracepdeex(0, out, " %-9s %04d:%03d:%05d", entry.site, - entry.epoch[0], - entry.epoch[1], - entry.epoch[2]); + entry.yds[0], + entry.yds[1], + entry.yds[2]); for (auto& solution : entry.solutions) { @@ -611,16 +562,17 @@ int writeTropSol( out << endl; } + pos = out.tellp(); + theSinex.tropSolList.clear(); - theSinex.tropSolFootFPosMap[markerName] = out.tellp(); + theSinex.tropSolFootFPosMap[filename] = pos; - out << "-TROP/SOLUTION" << endl; - return 0; + out << "-TROP/SOLUTION" << endl << endl; } /** Write troposphere Sinex data to file */ -int writeTropSinexToFile( +void writeTropSinexToFile( string filename, ///< filename of file to write out string markerName) ///< recID if individual rec used for soln, else blank { @@ -630,91 +582,72 @@ int writeTropSinexToFile( BOOST_LOG_TRIVIAL(warning) << "Warning: Could not open " << filename << " for writing trop sinex"; - return 1; + return; } // Write header if required - fout.seekp(0, fout.end); // seek to end of file - int failure = 0; - bool firstWrite = (fout.tellp() == 0); // file is empty if current position is 0 - if (firstWrite) + fout.seekp(0, fout.end); // seek to end of file + + long int pos = fout.tellp(); + + if (pos == 0) { - resetCommentsToDefault(); - - writeTropHeader (fout); write_pretty_line(fout); - if (!theSinex.refstrings. empty()) {failure += write_snx_reference (fout); write_pretty_line(fout);} - if (!theSinex.tropDesc. isEmpty) {failure += writeTropDesc (fout); write_pretty_line(fout);} - if (!theSinex.map_siteids. empty()) {failure += writeTropSiteId (fout, markerName); write_pretty_line(fout);} - if (!theSinex.map_receivers. empty()) {failure += writeTropSiteRec (fout, markerName); write_pretty_line(fout);} - if (!theSinex.map_antennas. empty()) {failure += writeTropSiteAnt (fout, markerName); write_pretty_line(fout);} - if (!theSinex.map_eccentricities. empty()) {failure += writeTropSiteEcc (fout, markerName); write_pretty_line(fout);} + writeTropHeader(fout); + + if (!theSinex.refstrings. empty()) { write_snx_reference (fout); } + if (!theSinex.tropDesc. isEmpty) { writeTropDesc (fout); } + if (!theSinex.map_siteids. empty()) { writeTropSiteId (fout, markerName); } + if (!theSinex.map_receivers. empty()) { writeTropSiteRec (fout, markerName); } + if (!theSinex.map_antennas. empty()) { writeTropSiteAnt (fout, markerName); } + if (!theSinex.map_eccentricities. empty()) { writeTropSiteEcc (fout, markerName); } } - if ( !theSinex.tropSiteCoordMapMap. empty()) {failure += writeTropSiteCoord (fout, markerName, firstWrite); write_pretty_line(fout);} - if ( !theSinex.tropSolList. empty()) {failure += writeTropSol (fout, markerName, firstWrite); write_pretty_line(fout);} + if ( !theSinex.tropSiteCoordMapMap. empty()) { writeTropSiteCoord (fout, markerName, filename); } + if ( !theSinex.tropSolList. empty()) { writeTropSol (fout, markerName, filename); } fout << "%=ENDTRO" << endl; - - return failure; } -void setFileRefData() -{ - theSinex.inputFiles. clear(); - theSinex.acknowledgements. clear(); - theSinex.inputHistory. clear(); - sinex_check_add_ga_reference("Solution parameters", "1.1", true); -} - -void setTropHeaderData( - GTime& time) ///< epoch of solution -{ - // Set creation time (default this to config. If not set, get it from the first station read) - boost::posix_time::ptime start_epoch = acsConfig.start_epoch; - GTime start_time; - start_time.time = static_cast(boost::posix_time::to_time_t(start_epoch)); - start_time.sec = 0; - double ep[6]; - int start[3]; - int end[3]; - time2epoch(start_time, ep); - epoch2yds(ep, start); - time2epoch(time, ep); - epoch2yds(ep, end); - struct timeval tv; - struct tm* tmbuf; - gettimeofday(&tv, NULL); - tmbuf = gmtime(&tv.tv_sec); - int create_yds[3]; // create time for Sinex header - create_yds[0] = tmbuf->tm_year + 1900; - create_yds[1] = tmbuf->tm_yday; - create_yds[2] = tmbuf->tm_sec - + tmbuf->tm_min * 60 - + tmbuf->tm_hour * 60 * 60; - string data_agc; - string contents; - sinex_update_header(acsConfig.analysis_agency, create_yds, data_agc, start, end, 'P', ' ', contents, 2.00); //Change this if the trop sinex format gets updated -} - -/** Export troposphere Sinex data +/** Output troposphere SINEX data */ void outputTropSinex( string filename, ///< filename of file to write out GTime time, ///< epoch of solution - map& stationMap, ///< map of stations used in network + KFState& kfState, ///< KF state string markerName, ///< name of station to use ("MIX" for all) bool isSmoothed) ///< if solution is smoothed (RTS or fixed-lag) { -// Instrument instrument(__FUNCTION__); - - setFileRefData(); - setTropHeaderData(time); + theSinex.markerName = markerName.substr(0,4); + sinex_check_add_ga_reference( acsConfig.trop_sinex_sol_type, + acsConfig.analysis_program_version, + true); + + PTime startTime; + startTime.bigTime = boost::posix_time::to_time_t(acsConfig.start_epoch); + string dataAgc; + string contents; + updateSinexHeader( acsConfig.analysis_agency, + dataAgc, + (GTime) startTime, + time, + acsConfig.trop_sinex_obs_code, + acsConfig.trop_sinex_const_code, + contents, + acsConfig.trop_sinex_version); replaceTimes(filename, acsConfig.start_epoch); - setTropSiteCoordsFromFilter(stationMap); - setTropSiteAntCalibModelsFromNav(); + for (auto& [key, index] : kfState.kfIndexMap) + { + if (key.type != KF::REC_POS) + continue; + + kfState.getKFValue(key, theSinex.tropSiteCoordMapMap[key.str][key.num]); + } + + setSiteAntCalib(); + + setTropSol(kfState); + + setDescription(isSmoothed); - setTropSols(isSmoothed); // requires setTropKFState() & setTropSiteCoordsFromFilter to have been called - setTropDesc(isSmoothed); // requires setTropSols() to have been called - setSinexMarkerName(markerName); writeTropSinexToFile(filename, markerName); } diff --git a/src/cpp/common/ubxDecoder.cpp b/src/cpp/common/ubxDecoder.cpp new file mode 100644 index 000000000..ecdc009e1 --- /dev/null +++ b/src/cpp/common/ubxDecoder.cpp @@ -0,0 +1,230 @@ + + +// #pragma GCC optimize ("O0") + +#include + +using std::make_shared; + +#include "ubxDecoder.hpp" +#include "icdDecoder.hpp" +#include "streamUbx.hpp" +#include "constants.hpp" +#include "gTime.hpp" +#include "enums.h" + + +map ubxSysMap = +{ + {0, E_Sys::GPS}, + {1, E_Sys::SBS}, + {2, E_Sys::GAL}, + {3, E_Sys::BDS}, + {4, E_Sys::IMS}, + {5, E_Sys::QZS}, + {6, E_Sys::GLO} +}; + +map> ubxSysObsCodeMap = +{ + { E_Sys::GPS, + { + {0, E_ObsCode::L1C}, + {3, E_ObsCode::L2C}, + {4, E_ObsCode::L2C}, + {6, E_ObsCode::L5I}, + {7, E_ObsCode::L5Q} + } + } +}; + +void UbxDecoder::decodeRAWX( + vector& payload) +{ + std::cout << "Recieved RAWX message" << std::endl; + + double rcvTow = *((double*) &payload[0]); + short unsigned int week = *((short unsigned int*) &payload[8]); + short int leapS = *((short int*) &payload[10]); + int numMeas = payload[11]; + + std::cout << "has " << numMeas << " measurements" << std::endl; + + map obsMap; + + for (int i = 0; i < numMeas; i++) + { + unsigned char* measPayload = &payload[i*32]; //below offsets dont start at zero, this matches spec + + double pr = *((double*) &measPayload[16]); + double cp = *((double*) &measPayload[24]); + float dop = *((float*) &measPayload[32]); + int gnssId = measPayload[36]; + int satId = measPayload[37]; + int sigId = measPayload[38]; + + E_Sys sys = ubxSysMap[gnssId]; + + if (sys == +E_Sys::NONE) + continue; + + E_ObsCode obsCode = ubxSysObsCodeMap[sys][sigId]; + + if (obsCode == +E_ObsCode::NONE) + continue; + + Sig sig; + sig.code = obsCode; + sig.L = cp; + sig.P = pr; + sig.D = dop; + + SatSys Sat(sys, satId); + auto& obs = obsMap[Sat]; + obs.Sat = Sat; + obs.time = gpst2time(week, rcvTow); + +// printf("meas %s %s %s %14.3lf %14.3lf\n", obs.time.to_string(4).c_str(), Sat.id().c_str(), obsCode._to_string(), pr, cp); + auto ft = code2Freq[sys][obsCode]; + obs.SigsLists[ft].push_back(sig); + } + + ObsList obsList; + + for (auto& [Sat, obs] : obsMap) + { + obsList.push_back((shared_ptr)obs); + } + + obsListList.push_back(obsList); +} + +int gpsBitSFromWord( + int word, + int offset, + int len) +{ + word <<= (offset - 1); + word >>= (32 - len); + + return word; +} + +unsigned int gpsBitUFromWord( + unsigned int word, + int offset, + int len) +{ + word <<= (offset - 1); + word >>= (32 - len); + + return word; +} + +void UbxDecoder::decodeEphFrames( + SatSys Sat) +{ + auto& frame1 = subframeMap[Sat][1]; + auto& frame2 = subframeMap[Sat][2]; + auto& frame3 = subframeMap[Sat][3]; + + + Eph eph; + bool pass = true; + + pass &= decodeGpsSubframe(frame1, eph); + pass &= decodeGpsSubframe(frame2, eph); + pass &= decodeGpsSubframe(frame3, eph); + +} +// int save_subfrm(int sat, raw_t* raw) +// { +// unsigned char* p = raw->buff + 6, *q; +// int i, j, n, id = (U4(p + 6) >> 2) & 0x7; +// +// trace(4, "save_subfrm: sat=%2d id=%d\n", sat, id); +// +// if (id < 1 || 5 < id) return 0; +// +// q = raw->subfrm[sat - 1] + (id - 1) * 30; +// +// for (i = n = 0, p += 2; i < 10; i++, p += 4) +// { +// for (j = 23; j >= 0; j--) +// { +// *q = (*q << 1) + ((U4(p) >> j) & 1); if (++n % 8 == 0) q++; +// } +// } +// return id; +// } +void UbxDecoder::decodeSFRBX( + vector& payload) +{ +// std::cout << "Recieved SFRBX message" << std::endl; + int gnssId = payload[0]; + int satId = payload[1]; + int frameLen = payload[4]; + + if (frameLen != (payload.size() - 8) / 4.0) + return; + + E_Sys sys = ubxSysMap[gnssId]; + + if (sys == +E_Sys::NONE) + return; + + if (sys != +E_Sys::GPS) + return; + + if (satId != 6) + return; + + SatSys Sat(sys, satId); + + printf("\n %s ", Sat.id().c_str()); + + for (int b = 0; b < 8; b++) + { + auto byte = payload[b]; + if (b % 4 == 0) + printf("--- "); + printf("%02x ", byte); + } + + vector frameWords; + + int* words = (int*) &payload.data()[8]; + for (int f = 0; f < frameLen; f++) + { + int word = words[f] << 2; + + frameWords.push_back(word); + + printf("%08x ", word); + } + + + int preamble = gpsBitUFromWord(frameWords[0], 1, 8); + int subFrameId = gpsBitUFromWord(frameWords[1], 20, 3); + + if (preamble != 0x8b) + return; + + printf("\n preamble : %02x - subFrameId : %02x - ", preamble, subFrameId); + + if ( subFrameId <= 0 + &&subFrameId >= 4) + { + return; + } + +// subframeMap[Sat][subFrameId] = frameWords; + + switch (subFrameId) + { + default: break; + case 2: + case 3: decodeEphFrames(Sat); break; + } +} + diff --git a/src/cpp/common/ubxDecoder.hpp b/src/cpp/common/ubxDecoder.hpp new file mode 100644 index 000000000..559b92d14 --- /dev/null +++ b/src/cpp/common/ubxDecoder.hpp @@ -0,0 +1,99 @@ + +#pragma once + +// #pragma GCC optimize ("O0") + +#include +#include + +using std::vector; +using std::map; + +#include "icdDecoder.hpp" +#include "streamObs.hpp" +#include "enums.h" + +extern map ubxSysMap; +extern map> ubxSysObsCodeMap; + +struct UbxDecoder : ObsLister, icdDecoder +{ + string raw_ubx_filename; + + void decodeEphFrames( + SatSys Sat); + + void decodeRAWX( + vector& payload); + + void decodeSFRBX( + vector& payload); + + void decodeRXM( + vector& payload, + unsigned char id) + { +// printf("\nReceived RXM-0x%02x message", id); + switch (id) + { + default: + { + break; + } + case E_RXMId::RAWX: { decodeRAWX (payload); break; } + case E_RXMId::SFRBX: { decodeSFRBX (payload); break; } + } + } + + void decode( + unsigned char ubxClass, + unsigned char id, + vector& payload) + { + switch (ubxClass) + { + default: { break; } + case E_UBXClass::RXM: { decodeRXM(payload, id); break; } + } + } + + void recordFrame( + unsigned char ubxClass, + unsigned char id, + vector& data, + unsigned short int crcRead) + { + if (raw_ubx_filename.empty()) + { + return; + } + + std::ofstream ofs(raw_ubx_filename, std::ofstream::app); + + if (!ofs) + { + return; + } + +// //Write the custom time stamp message. +// RtcmEncoder encoder; +// encoder.rtcmTraceFilename = rtcmTraceFilename; +// +// auto buffer = encoder.encodeTimeStampRTCM(); +// bool write = encoder.encodeWriteMessageToBuffer(buffer); +// +// if (write) +// { +// encoder.encodeWriteMessages(ofs); +// } + + //copy the message to the output file too + unsigned short int payloadLength = data.size(); + + ofs.write((char *)&ubxClass, 1); + ofs.write((char *)&id, 1); + ofs.write((char *)&payloadLength, 2); + ofs.write((char *)data.data(), data.size()); + ofs.write((char *)&crcRead, 3); + } +}; diff --git a/src/cpp/common/walkthrough.cpp b/src/cpp/common/walkthrough.cpp new file mode 100644 index 000000000..345de3583 --- /dev/null +++ b/src/cpp/common/walkthrough.cpp @@ -0,0 +1,435 @@ + +// #pragma GCC optimize ("O0") + +#include "algebra.hpp" +#include "common.hpp" +#include "trace.hpp" +#include "ppp.hpp" + +#include +#include + + +string noteONE = R"raw( +This is the basic form of the outputStates function's output, describing the times, keys, values, variances, and adjustments of everything in the filter. +Note that the filter is not empty upon initialisation, it contains a ONE element that is always present with state value 1, and used for internal calculations. +Get used to ignoring this element. + )raw"; + +string noteInit = R"raw( +When the stateTransition function is called, any kfKeys that were defined and used in measurements are automatically added as states. +They contain the values as defined in the InitialState that may have been used. + )raw"; + +string noteAddMeas = R"raw( +Here the code creates several KFMeasEntrys and adds them to a list + )raw"; + +string noteMeas = R"raw( +When the combineKFMeasList function is called, finalised matrices of the measurements are generated, ready for filtering +They can be viewed with the outputMeasurements function, which displays the measurements keys down the left, states across the top, OMCs on the right, and non zero entries of the design matrix between. +(Its a lot more obvious whats going on when there are more observations and states, and this output is generally unnecessary) + )raw"; + +string noteResiduals = R"raw( +When the filterKalman function is called, standard ekf processes are used to update the states and covariances of the filter. +During the process, the residuals and statistics may be output, showing the fit achieved to the measurements. +Here we see a significant reduction in pre->post fit residuals, indicating the adjustments have improved the fit to these measurements. + )raw"; + + +string noteIntro1 = R"raw( +This walkthrough demonstrates the basics of Ginan's kalman filter. +Its target is an object having its position measured in 1D, by measurements over several epochs. +It's expected that the comments in the code, and the descriptions in the outputs below will give a good basis for starting to work with Ginan's kalman filter. + )raw"; + +string notePostFilter1 = R"raw( +Here we see that the "Walk" REC_POS state value after the filter has moved substantially toward the true value (10), and its variance has decreased from its previous value. + )raw"; + +string noteProcNoise = R"raw( +In the second epoch, after some time has elapsed, the stateTransition function has added process noise according to the value specified by InitialState. +We see a large increase in the variance. + )raw"; + +string noteReject = R"raw( +During this epoch, one of the measurements encounters an outlier, with some large glitch in the observed term. +During processing of the filter the consistency of measurements' and states' variances with each other is confirmed, and outliers detected. +In the case that this consistency check fails, rejection callbacks may be defined, which may trigger appropriate actions. +Here we see that the measurement with the glitch has its measurement variance deweighted by a factor of 10000 such that it doesnt corrupt the filter states. +In the first filter residuals block, both states have poor postfit residuals, but upon iteration when the second measurement is deweighted, the remaining first measurement achieves a good fit. + )raw"; + +string noteIntro2 = R"raw( +Beginning of walkthrough section 2 + +This walkthrough demonstrates the basics of using rate terms in Ginan's kalman filter (velocities, accelerations) + +Its target is an object having its position measured in 1D, by measurements over several epochs. +It's expected that the comments in the code, and the descriptions in the outputs below will give a good basis for starting to work with Ginan's kalman filter. + )raw"; + +string noteRemove = R"raw( +The states from section 1 remain in the filter. +At this point the code removes all states, but this wont be seen until the next stateTransition call + )raw"; + +string noteMeas2 = R"raw( +Here we see the design matrix created by the code - there are 6 states that have been automatically added to the filter by 3 measurements. +1 - This measurement measures the state with num = 1 directly. There is no rate associated with this state +2 - This measurement measures the position state with num = 2 directly. There is a velocity term associated with this rate, but it cant be measured directly with a position observation. +3 - This measurement measures the position state with num = 3 directly. There are velocity and acceleration terms associated with this rate, but they also cant be measured directly. + +Thus the only entries in the design matrix are those corresponding to the position states. + )raw"; + +string noteFirstMeas = R"raw( +Here we see that after one measurement the variance of the position state has reduced substantially, and the position state value quite close to the actual x value. +The estimate for the velocity and acceleration remain unchanged and with large variances, since there is not enough data for them to update.. yet. + )raw"; + +string noteCorrelations = R"raw( +We also see that the velocity terms have began to become corellated with their corresponding position terms. + )raw"; + + +string noteSecondMeas = R"raw( +After a second measurement the velocity terms begin to adjust to the measurements. +This takes place purely due to corellations with the position terms, caused by the propagation of the state transition matrix. + )raw"; + +string noteThirdMeas = R"raw( +After a third measurement the acceleration term also begins to adjust to the measurements. + )raw"; + +string note1Second = R"raw( +Over the next 1 second's worth of measurements, the velocities and acceleration terms have converged toward the correct values, +initially overshooting before oscillating around the correct value (a = -9.8) +The postfit residuals for most measurements have reduced significantly, despite the very poor initilisation conditions. +(The relatively good prefit residual for the num=1 measurement (the one with no velocity or acceleration integration) +is only due to the lack of motion at this point in time. The correct value is relatively close to the previous value, see below) + )raw"; + +string note2Seconds = R"raw( +Over the next second's worth of measurements, the velocities and acceleration terms have further converged toward the correct values +Now however the position state with no velocity term has relatively poor residuals, due to the fast unmodelled kinematics, as compared with the state that is estimating and modelling a linear acceleration + )raw"; + + +void printWait( + string str) +{ + std::cout << "\n\n\n\n\n" << str; + std::cout << "(continue)\n"; + + getline(std::cin, str); + std::cout << "\n\n\n\n\n"; +} + +/** Ginan kalman filter basics + * The basic structure for kalman filtering in ginan is the KFState struct, it is required for all filtering. + * The KFKey struct is used to define a state element within the filter. These are used rather than row/column indexing to eliminate manual bookkeeping + * State elements are generally initialised using an InitialState object, which defines the initial value, sigma, and process noise to be applied between epochs. + * Measurements are defined individually as KFMeasEntry objects and added to a list, before being combined to create a KFMeas object that contains the aggregated measurement list in matrix form. + * The measurement's design matrix is set by defining the sensitivity of the measurement to state elements, and its innovation (OMC) and noise are set with helper functions. + * State elements are automatically added to the filter when a stateTransition occurs after referencing a KFKey with one of the helper functions. + */ +KFState walkthrough1() +{ + //unrequired preparation + double actualPosition = 10; + double measVar = 0.21; + std::random_device randoDev; + std::mt19937 randoGen(randoDev()); + std::normal_distribution rando(0, SQRT(measVar)); + + //prepare the filter + KFState kfState; + kfState.output_residuals = true; //turn on nice outputs for pre/postfit residuals when filtering + kfState.measRejectCallbacks.push_back(deweightMeas); //turn on a rejection callback + kfState.max_filter_iter = 4; + kfState.max_prefit_remv = 4; + + //Prepare the initial state for whenever this element is eventaully initialised + InitialState posInit; + posInit.x = 0.0123; //initial estimate of the state + posInit.P = 900; //initial variance of the state + posInit.Q = 6; //process noise per second + + GTime time; + + printWait(noteIntro1); + + + kfState.outputStates(std::cout, " - BEFORE ANYTHING HAPPENS"); + printWait(noteONE); + + for (int epoch = 1; epoch <= 2; epoch++) + { + std::cout << std::endl << "Begin Epoch " << epoch << std::endl; + time += 60; + + KFMeasEntryList kfMeasEntryList; + + KFKey posKey; + posKey.type = KF::REC_POS; + posKey.str = "Walk"; + + if (epoch == 1) printWait(noteAddMeas); + { + //get the computed (usually just current) state + double stateVal = posInit.x; //inital computed state is whatever we are going to initialise it as + kfState.getKFValue(posKey, stateVal); //override that with whatever is in the kalman filter, if there is something there, that is. + + double computed = stateVal; + double observed = actualPosition + rando(randoDev); //the measurement is the actual position +- some error noise + + double omc = observed - computed; + + KFMeasEntry measEntry(&kfState); + measEntry.addDsgnEntry(posKey, 1, posInit); //this measEntry is a direct measurement of the state with key posKey -> sensitivity is 1, create and initialise the state with posInit if required. + measEntry.setInnov(omc); + measEntry.setNoise(measVar); + + //this is optional, but makes the output easier to read. Usually this would be passed in through KFMeasEntry's constructor + if (1) + { + KFKey obsKey; + obsKey.str = "Meas"; + obsKey.num = 1337; + measEntry.obsKey = obsKey; + } + + kfMeasEntryList.push_back(measEntry); + } + + { + //get the computed (usually just current) state + double stateVal = posInit.x; //inital computed state is whatever we are going to initialise it as + kfState.getKFValue(posKey, stateVal); //override that with whatever is in the kalman filter, if there is something there, that is. + + double computed = stateVal / 2.54; //this measurement is in inches, this time the 'computation' is needed before use. + double observed = actualPosition / 2.54; //the measurement is the actual position if it were measured in inches. + + if (epoch == 2) observed += 14; + + double omc = observed - computed; + + KFMeasEntry measEntry(&kfState); + measEntry.addDsgnEntry(posKey, 1 / 2.54, posInit); //this measEntry is a scaled measurement of the state with key posKey -> sensitivity of measuremet to change in state is 1/2.54, create and initialise the state with posInit if required. + measEntry.setInnov(omc); //error between the current state value, and what we think it should be (observed minus computed) + measEntry.setNoise(measVar); //how much variance we expect in the measurement - our rulers are not perfect + + //this is optional, but makes the output easier to read. Usually this would be passed in through KFMeasEntry's constructor + if (1) + { + KFKey obsKey; + obsKey.str = "Inch"; + measEntry.obsKey = obsKey; + } + + kfMeasEntryList.push_back(measEntry); + } + + + kfState.stateTransition(std::cout, time); //the state transition to t = time initialises newly created states, and adds process noise to existing ones as per their initialisation + + kfState.outputStates(std::cout, " - POST STATE TRANSITION"); + if (epoch == 1) printWait(noteInit); + if (epoch == 2) printWait(noteProcNoise); + + KFMeas combinedMeas = kfState.combineKFMeasList(kfMeasEntryList, time); //filterKalman requires a consolidated KFMeas input, rather than a list of individial KFMeasEntrys, create it here + + if (1) + { + if (epoch == 1) + kfState.outputMeasurements(std::cout, combinedMeas); + if (epoch == 1) printWait(noteMeas); + } + + + kfState.filterKalman(std::cout, combinedMeas, true); //perform the kalman filter operation (the true indicates this is an extended kalman filter using precalculated OMCs, this should generally be true in ginan) + if (epoch == 1) printWait(noteResiduals); + if (epoch == 2) printWait(noteReject); + + + kfState.outputStates(std::cout, " - POST FILTER"); + if (epoch == 1) printWait(notePostFilter1); + } + + printWait("End of walkthrough section 1\n\t"); + + return kfState; +} + + +void walkthrough2( + KFState& kfState) +{ + //unrequired preparation + double measVar = 1; + std::random_device randoDev; + std::mt19937 randoGen(randoDev()); + std::normal_distribution rando(0, SQRT(measVar)); + double v0 = 10; + double x0 = 30; + double a = -9.8; + double dt = 0.02; + GTime time = kfState.time + 1000; + + + + InitialState posInit; //initial values for pos, vel, and acc. + posInit.P = 10000; //large P values indicate large uncertainty in initial position + //initial x value defaults to 0 if undefined, substantially different from actual initial values defined above + + InitialState velInit; + velInit.P = 10000; + + InitialState accInit; + accInit.P = 10000; + + printWait(noteIntro2); + + KFKey posKey; //keys for identifying the states added to the filter + posKey.type = KF::POS; + posKey.str = "Obj"; + + KFKey velKey; + velKey.type = KF::VEL; + velKey.str = "Obj"; + + KFKey accKey; + accKey.type = KF::ACC; + accKey.str = "Obj"; + + + kfState.outputStates(std::cout, " - BEFORE ANYTHING HAPPENS"); + + printWait(noteRemove); + + //idiomatic procedure for iterating over things in the filter + for (auto& [key, index] : kfState.kfIndexMap) + { + //dont remove ONE, we need that! + if (key.type == KF::ONE) + { + continue; + } + + //remove all other states + kfState.removeState(key); + } + + + for (double t = 0; t <= 2; t += dt) + { + double actualPosition = x0 //compute positions and velocities of a simulated ball in gravity + + v0 * t + + a * t * t / 2; + + double actualVelocity = v0 + + a * t; + + std::cout << std::endl << "\n\n\n\nEpoch " + << "\n t = " << t + << "\n x = " << actualPosition + << "\n v = " << actualVelocity << std::endl; + time += dt; //generally we wouldnt be iterating over t, dt like this, we would be given a time from some external observation source and we'd just use it + + KFMeasEntryList kfMeasEntryList; + + kfState.stateTransition(std::cout, time); //since we're using rates we need to compute the current value of the states since they have changed over the period since the stateTransition at the end of this loop was last called, (at t-dt) + //call stateTransition to do this computation + + + + + if (t == 0) + kfState.outputStates(std::cout, " - POST FIRST STATE TRANSITION"); + if (t == 0) printWait(noteAddMeas + "\nAlso note that the current true value of the x,v,t at each epoch will be shown as above\n\t"); + + double observed = actualPosition; //the measurement is the actual position + + //create three types of measurements for the same object, with more or less kinematics involved + for (int i = 1; i <= 3; i++) + { + posKey.num = i; + velKey.num = i; + accKey.num = i; + + if (i == 1) { posInit.Q = SQR(10); } + else if (i == 2) { posInit.Q = 0; velInit.Q = SQR(10); } //The Q value (process noise) should be 0 for elements that have rates applied - eg, for num==2 a vel term is the derivative of pos, so posInit.Q = 0 + else if (i == 3) { posInit.Q = 0; velInit.Q = 0; } //only the highest derivative should get process noise. + + //get the computed (usually just current) state + double stateVal = posInit.x; //inital computed state is whatever we are going to initialise it as + kfState.getKFValue(posKey, stateVal); //override that with whatever is in the kalman filter, if there is something there, that is. + + double computed = stateVal; + + double omc = observed - computed; + + KFKey obsKey; //give the measEntry a KFKey just so the residuals/measurements outputs are easier to read (optional) + obsKey.str = "MEAS"; + obsKey.num = i; + + KFMeasEntry measEntry(&kfState, obsKey); + measEntry.addDsgnEntry(posKey, 1, posInit); //this measEntry is a direct measurement of the state with key posKey -> sensitivity is 1, create and initialise the state with posInit if required. + measEntry.setInnov(omc); + measEntry.setNoise(measVar); + + if (i >= 2) + kfState.setKFTransRate(posKey, velKey, 1, velInit); //here we define that velKey is the rate derivative of posKey, with scaling 1, and some initial velocity state + + if (i == 3) + kfState.setAccelerator(posKey, velKey, accKey, 1, accInit); //here we define that accKey is an accelerator of posKey, with velKey being an intermediate derivative between that and this. + + + kfMeasEntryList.push_back(measEntry); + } + + + kfState.stateTransition(std::cout, time); //since we called stateTransition with t = time above, this will only initialise new states - no time has passed to change state values or process noises + + if (t < dt*3) + kfState.outputStates(std::cout, " - POST SECOND STATE TRANSITION"); + + + KFMeas combinedMeas = kfState.combineKFMeasList(kfMeasEntryList, time); + + + if (1) + { + if (t == 0) + kfState.outputMeasurements(std::cout, combinedMeas); + if (t == 0) printWait(noteMeas2); + + + if (t == dt) + kfState.outputCorrelations(std::cout); + if (t == dt) printWait(noteCorrelations); + } + + + kfState.filterKalman(std::cout, combinedMeas, true); + + + kfState.outputStates(std::cout, " - POST FILTER"); + if (t == 0) printWait(noteFirstMeas); + if (t == dt) printWait(noteSecondMeas); + if (t == dt*2) printWait(noteThirdMeas); + if (t > 1) printWait(note1Second); + } + + printWait(note2Seconds); + printWait("End of walkthrough section 2"); +} + +void walkthrough() +{ + KFState kfState = walkthrough1(); + walkthrough2(kfState); + exit(1); +} diff --git a/src/cpp/gui/anode.cpp b/src/cpp/gui/anode.cpp new file mode 100644 index 000000000..d239d2949 --- /dev/null +++ b/src/cpp/gui/anode.cpp @@ -0,0 +1,1314 @@ + +// #pragma GCC optimize ("O0") + + +#include + +#include + +#include +#include "binaryStore.hpp" +#include "constants.hpp" +#include "anode.hpp" + +#include +#include +#include +#include + +using std::shared_ptr; +using std::ofstream; + +extern map*> anyPtrMap; +map subscribedMap; +// map requestedMap; +list> stringList; + + + +int ANode::nextGuid = 0; +map> ANode::anodeIdMap; + +map stringMap; + + ostream& operator<<( + ostream& out, + ANode& anode) + { + return anode.shift(out); + } + + ANode& ANode::operator << (string content) + { + if (childless) + { + this->content += content; + } + else + { + addChild() << content; + } + return *this; + } + +list outQueue; +list msgQueue; +mutex outMutex; + +mutex subscribedMapMutex; + +bool sendFlag = true; + +extern double click; +namespace sinks = boost::log::sinks; + + + +struct GooeySinkBackend : public sinks::basic_formatted_sink_backend +{ + // The function consumes the log records that come from the frontend + void consume( + boost::log::record_view const& rec, + sinks::basic_formatted_sink_backend::string_type const& log_string) + { + int sev; + if (auto severity = rec[boost::log::trivial::severity]) + { + // Convert the enum to unsigned int + sev = static_cast< unsigned int >(*severity); + } + else + { + // Either "Severity" attribute not found, or it has value type + // other than boost::log::trivial::severity_level. Use a default level. + sev = 0; + } + + bsoncxx::builder::basic::document doc = {}; + doc.append(kvp("send", "CONS" )); + doc.append(kvp("level", sev )); + doc.append(kvp("content", log_string.c_str() )); + { + lock_guard guard(outMutex); + + msgQueue.push_back(bsoncxx::to_json(doc)); + } + } +}; + +void callback0() +{ + static bool once = true; + + if (once == false) + { + return; + } + + // Construct the sink + using GooeyLogSink = sinks::synchronous_sink; + + boost::shared_ptr gooeyLogSink = boost::make_shared(); + + // Register the sink in the logging core + boost::log::core::get()->add_sink(gooeyLogSink); + + once = false; +} + +string nonNumericStack( + string stack, + bool colon = true); + +#include "acsConfig.hpp" + +void callback2() +{ + auto config = make_shared
("configTab_"); + ANode::anodeIdMap[config->id] = config; +// config->parent = "body"; +// config->Class("pageTab"); + config->addChild

("configHeader") << "Configuration"; + + auto it = acsConfig.yamlDefaults.begin(); + while (it != acsConfig.yamlDefaults.end()) + { + auto& [stack, defaultVals] = *it; + it++; + + auto& gotValue = defaultVals.foundValue; + auto& comment = defaultVals.comment; + + //split the name into tokens so that ordering numerals can be removed + size_t pos_start = 0; + size_t pos_end; + + string token; + string flatStack = ""; + //find each part of the stack for this entry and make a list of them + while ((pos_end = stack.find(":", pos_start)) != string::npos) + { + token = stack.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + 1; + token = nonNumericStack(token); + flatStack += token; + } + +// if (token == "outputs:") +// { +// break; +// } + string root = flatStack.substr(0, flatStack.size() - token.size()); + + string parentString = "configTab_"; + if (root.empty() == false) + { + parentString = root + "_"; + } + + auto& parent = ANode::anodeIdMap[parentString]; + auto& element = parent->addChild
() + .Class("element"); + + + auto& modified = element.addChild(flatStack) + .attr("type", "checkbox"); + + if (defaultVals.found) + { + modified.attr("checked", "true"); + } + + auto& ident = element.addChild
() + .Class("ident"); + + bool nextIsChild = false; + if (it != acsConfig.yamlDefaults.end()) + { + auto& [nextStack, dummy] = *it; + if (nextStack.substr(0, stack.size()) == stack) + { + nextIsChild = true; + } + } + if (nextIsChild) ident.Class("bold"); + + ident << token; + + if (nextIsChild) ident << " ⯆"; + + + if (comment.empty() == false) + { + ident.addChild() + .Class("tooltiptext") << "# " + comment; + } + + if (nextIsChild) + element.addChild
(flatStack + "_") + .Class("contents"); + +// if (firstChild) +// { +// //finalise the child section +// html << std::endl << -- htmlIndentor << "
"; +// } +// else + { + //this has no children, output the default value of this parameter instead - according to its commented parameter type + + for (auto once : {1}) + { + //booleans + if (comment.find("(bool)") != string::npos) + { + auto& boolSelect = element.addChild() + .attr("class", "value"); + + + //find each part of the stack for this entry and make a list of them + while ((pos_end = enums.find(',', pos_start)) != string::npos) + { + string token = enums.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + 1; + + auto& a = boolSelect.addChild