#include "Database.h" #include "pal.h" #include "nova.h" #include "Time.h" #include "Configuration.h" #include #include #include using namespace std; // ------------------------------------------------------------------------ void SetupConfiguration(Configuration &conf) { po::options_description control("Calcsource options"); control.add_options() ("uri,u", var() #if BOOST_VERSION >= 104200 ->required() #endif , "Database link as in\n\tuser:password@server[:port]/database.") //("source-key", var(5), "") //("source-name", var(""), "") ("file", var(uint32_t(0)),"FileId (YYMMDDXXX), defined the events to be processed (if omitted (=0), a list of possible numbers is printed)") ("table.events", var("Events"), "Name of the table where the events are stored") ("table.runinfo", var("RunInfo"), "Name of the table where the run-info data is stored") ("table.source", var("Source"), "Name of the table where the sources are stored") ("table.position", var("Position"), "Name of the table where the calculated posiiton will be stored") ("force", po_switch(), "Force processing even if there is no database connection") ("drop", po_switch(), "Drop the table (implies create)") ("create", po_switch(), "Create the table if it does not yet exist") ("update", po_switch(), "Update the table.position instead of inserting it (disables drop, create and delete)") ("ra", var(), "Right ascension of the source (use together with --dec)") ("dec", var(), "Declination of the source (use together with --ra)") ("focal-dist", var(4889.), "Focal distance of the camera in millimeter") ; po::options_description debug("Debug options"); debug.add_options() ("no-insert", po_switch(), "Does not insert or update any data to any table") ("dry-run", po_switch(), "Skip any query which changes the databse (might result in consecutive failures)") ("print-meta", po_switch(), "Print meta-queries (DROP, CREATE, DELETE, SELECT)") ("print-insert", po_switch(), "Print the INSERT/UPDATE queries") ("verbose,v", var(1), "Verbosity (0: quiet, 1: default, 2: more, 3, ...)") ; po::positional_options_description p; p.add("file", 1); // The 1st positional options (n=1) conf.AddOptions(control); conf.AddOptions(debug); conf.SetArgumentPositions(p); } void PrintUsage() { cout << "calcsource - Fill a table with source positions\n" "\n" "This tool is to calculate the source position in the camera and fill " "it into a database table for all events which come from a single run. " "The run is idetified by its FileId (YYMMDDXXX), where YYMMDD is " "its date and XXX is the run-number. For this run the corresponding " "source key `fSourceKey` is obtained from the RunInfo table " "(--table.runinfo) and the corresponding fRightAscension and fDeclination " "from the Source table (--table.source). If --ra and --dec was specified " "by the user, this step is skipped and these two values are used instead." "\n\n" "Then for each event with the given FileId, its pointing position " "(`Ra`, `Dec`), its time (`MJD`, `MilliSec`) and its event number " "(`EvtNumber`) are requested from the table given by --table.events. " "Based on this information and the focal distance (--focal-distance) the " "`X` and `Y` coordinate of the source in the camera plane is calculated. " "The result can then be filled into a database." "\n\n" "The table to be filled or updated should contain the following columns:\n" " - FileId INT UNSIGNED NOT NULL\n" " - EvtNumber INT UNSIGNED NOT NULL\n" " - X FLOAT NOT NULL\n" " - Y FLOAT NOT NULL\n" "\n" "If the table does not exist, it can be created automatically specifying " "the --crate option. If a table already exists and it should be dropped " "before creation, the --drop option can be used:\n" "\n" " calcsource 170909009 --create\n" "\n" "Process the data from the run 009 from 09/09/2017. If no table exists " "a table with the name given by --table.position is created.\n" "\n" " calcsource 170909009 --create --drop\n" "\n" "Same as before, but if a table with the name given by --table.position " "exists, it is dropped before.\n" "\n" "For each event, a new row is inserted. If existing rows should be updated, " "use:\n" "\n" " calcsource 170909009 --updated\n" "\n" "The --create option is compatible with that. The --drop option is ignored.\n" "\n" "" "\n" "For debugging purposes several print options and options to avoid irreversible " "changes to the database exist." "\n\n" "Usage: calcsource YYMMDDXXX [-u URI] [options]\n" "\n" ; cout << endl; } class MRotation : public TRotation { public: MRotation() : TRotation(1, 0, 0, 0, -1, 0, 0, 0, 1) { } }; int main(int argc, const char* argv[]) { Time start; gROOT->SetBatch(); Configuration conf(argv[0]); conf.SetPrintUsage(PrintUsage); SetupConfiguration(conf); if (!conf.DoParse(argc, argv)) return 127; // ----------------------------- Evaluate options -------------------------- if (conf.Has("ra")^conf.Has("dec")) throw runtime_error("--ra and --dec can only be used together"); const bool has_radec = conf.Has("ra") && conf.Has("dec"); double source_ra = conf.Has("ra") ? conf.Get("ra") : 0; double source_dec = conf.Has("dec") ? conf.Get("dec") : 0; //string source_name = conf.Get("source-name"); //uint32_t source_key = conf.Has("source-key") ? conf.Get("source-key") : 0; const string uri = conf.Get("uri"); const string tab_events = conf.Get("table.events"); const string tab_runinfo = conf.Get("table.runinfo"); const string tab_source = conf.Get("table.source"); const string tab_position = conf.Get("table.position"); const uint32_t file = conf.Get("file"); const double focal_dist = conf.Get("focal-dist"); const bool print_meta = conf.Get("print-meta"); const bool print_insert = conf.Get("print-insert"); const bool force = conf.Get("force"); const bool drop = conf.Get("drop"); const bool create = conf.Get("create") || drop; const bool update = conf.Get("update"); const bool noinsert = conf.Get("no-insert"); const bool dry_run = conf.Get("dry-run"); const uint16_t verbose = conf.Get("verbose"); // ------------------------------------------------------------------------- // Checking for database connection Database connection(uri); // Keep alive while fetching rows try { if (!force) connection.connected(); } catch (const exception &e) { cerr << "SQL connection failed: " << e.what() << endl; return 1; } // ------------------------------------------------------------------------- // list file-ids in the events table if (file==0) { const string query = "SELECT FileId FROM `"+tab_events+"` GROUP BY FileId"; if (print_meta) cout << query << endl; const mysqlpp::StoreQueryResult res = connection.query(query).store(); for (size_t i=0; i0) { cout << "\n------------------------- Evaluating source ------------------------" << endl; cout << "Requesting coordinates from " << tab_runinfo << "/" << tab_source << " table for 20" << file/1000 << "/" << file%1000 << endl; } if (!has_radec) { const string query = "SELECT "+tab_source+".fRightAscension, "+tab_source+".fDeclination, "+tab_source+".fSourceName" " FROM `"+tab_runinfo+"`"+ " LEFT JOIN `"+tab_source+"`"+ " USING (fSourceKey)" " WHERE fNight=20"+to_string(file/1000)+ " AND fRunID="+to_string(file%1000); if (print_meta) cout << query << endl; try { const mysqlpp::StoreQueryResult res = connection.query(query).store(); if (res.num_rows()!=1) { cerr << "No coordinates from " << tab_runinfo << " for " << file << endl; return 2; } source_ra = res[0][0]; source_dec = res[0][1]; if (verbose>0) cout << "Using coordinates " << source_ra << "h / " << source_dec << " deg for '" << res[0][2] << "'" << endl; } catch (const exception &e) { cerr << query << "\n"; cerr << "SQL query failed:\n" << e.what() << endl; return 3; } } else if (verbose>0) cout << "Using coordinates " << source_ra << "h / " << source_dec << " deg from resources." << endl; /* if (!source_name.empty()) { cout << "Requesting coordinates for '" << source_name << "'" << endl; const mysqlpp::StoreQueryResult res = connection.query("SELECT `Ra`, `Dec` WHERE fSourceName='"+source_name+"'").store(); if (res.num_rows()!=1) { cerr << "No " << (res.num_rows()>1?"unique ":"") << "coordinates found for '" << source_name << "'" << endl; return 1; } source_ra = res[0][0]; source_dec = res[0][1]; } */ // ------------------------------------------------------------------------- // create INSERT/UPDATE query (calculate positions) if (verbose>0) { cout << "\n-------------------------- Evaluating file ------------------------"; cout << "\nRequesting data from table `" << tab_events << "`" << endl; } const string query = "SELECT `Ra`, `Dec`, MJD, MilliSec, NanoSec, Zd, Az, EvtNumber" " FROM `"+tab_events+"`" " WHERE FileId="+to_string(file); if (print_meta) cout << query << endl; const mysqlpp::UseQueryResult res1 = connection.query(query).use(); Nova::RaDecPosn source(source_ra, source_dec); source_ra *= M_PI/12; source_dec *= M_PI/180; auto obs = Nova::kORM; obs.lng *= M_PI/180; obs.lat *= M_PI/180; //const double mm2deg = 1.17193246260285378e-02; ostringstream ins; ins << setprecision(16); vector upd; size_t count = 0; while (auto row=res1.fetch_row()) { count++; double point_ra = row[0]; double point_dec = row[1]; uint32_t mjd = row[2]; int64_t millisec = row[3]; //uint32_t nanosec = row[4]; //double zd = row[5]; //double az = row[6]; uint32_t event = row[7]; Nova::RaDecPosn point(point_ra, point_dec); point_ra *= M_PI/12; point_dec *= M_PI/180; /* // ============================ Mars ================================ TVector3 pos; // pos: source position TVector3 pos0; // pos: source position pos.SetMagThetaPhi(1, M_PI/2-source_dec, source_ra); pos0.SetMagThetaPhi(1, M_PI/2-point_dec, point_ra); const double ut = (nanosec/1e6+millisec)/(24*3600000); // Julian centuries since J2000. const double t = (ut -(51544.5-mjd)) / 36525.0; // GMST at this UT1 const double r1 = 24110.54841+(8640184.812866+(0.093104-6.2e-6*t)*t)*t; const double r2 = 86400.0*ut; const double sum = (r1+r2)/(3600*24); double gmst = fmod(sum, 1) * 2*M_PI; MRotation conv; conv.RotateZ(gmst + obs.lng); conv.RotateY(obs.lat-M_PI/2); conv.RotateZ(M_PI); pos *= conv; pos0 *= conv; pos.RotateZ(-pos0.Phi()); pos.RotateY(-pos0.Theta()); pos.RotateZ(-M_PI/2); // exchange x and y pos *= -focal_dist/pos.Z(); TVector2 v = pos.XYvector(); //if (fDeviation) // v -= fDeviation->GetDevXY()/fGeom->GetConvMm2Deg(); //cout << v.X() << " " << v.Y() << " " << v.Mod()*mm2deg << '\n'; */ // ================================= Nova =============================== Nova::ZdAzPosn ppos = Nova::GetHrzFromEqu(source, 2400000.5+mjd+millisec/1000./3600/24); Nova::ZdAzPosn ppos0 = Nova::GetHrzFromEqu(point, 2400000.5+mjd+millisec/1000./3600/24); TVector3 pos; TVector3 pos0; pos.SetMagThetaPhi( 1, ppos.zd *M_PI/180, ppos.az *M_PI/180); pos0.SetMagThetaPhi(1, ppos0.zd*M_PI/180, ppos0.az*M_PI/180); pos.RotateZ(-pos0.Phi()); pos.RotateY(-pos0.Theta()); pos.RotateZ(-M_PI/2); // exchange x and y pos *= -focal_dist/pos.Z(); TVector2 v = pos.XYvector(); //cout << v.X() << " " << v.Y() << " " << v.Mod()*mm2deg << '\n'; /* // =============================== Slalib ========================== const double height = 2200; const double temp = 10; const double hum = 0.25; const double press = 780; const double _mjd = mjd+millisec/1000./3600/24; const double dtt = palDtt(_mjd); // 32.184 + 35 const double tdb = _mjd + dtt/3600/24; const double dut = 0; // prepare calculation: Mean Place to geocentric apperent // (UTC would also do, except for the moon?) double fAmprms[21]; palMappa(2000.0, tdb, fAmprms); // Epoche, TDB // prepare: Apperent to observed place double fAoprms[14]; palAoppa(_mjd, dut, // mjd, Delta UT=UT1-UTC obs.lng, obs.lat, height, // long, lat, height 0, 0, // polar motion x, y-coordinate (radians) 273.155+temp, press, hum, // temp, pressure, humidity 0.40, 0.0065, // wavelength, tropo lapse rate fAoprms); // ---- Mean to apparent ---- double r=0, d=0; palMapqkz(point_ra, point_dec, fAmprms, &r, &d); double _zd, _az, ha, ra, dec; // -- apparent to observed -- palAopqk(r, d, fAoprms, &_az, // observed azimuth (radians: N=0,E=90) [-pi, pi] &_zd, // observed zenith distance (radians) [-pi/2, pi/2] &ha, // observed hour angle (radians) &dec, // observed declination (radians) &ra); // observed right ascension (radians) //cout << _zd*180/M_PI << " " << _az*180/M_PI << endl; pos0.SetMagThetaPhi(1, _zd, _az); r=0, d=0; palMapqkz(source_ra, source_dec, fAmprms, &r, &d); // -- apparent to observed -- palAopqk(r, d, fAoprms, &_az, // observed azimuth (radians: N=0,E=90) [-pi, pi] &_zd, // observed zenith distance (radians) [-pi/2, pi/2] &ha, // observed hour angle (radians) &dec, // observed declination (radians) &ra); // observed right ascension (radians) pos.SetMagThetaPhi(1, _zd, _az); //cout << _zd*180/M_PI << " " << _az*180/M_PI << endl; pos.RotateZ(-pos0.Phi()); pos.RotateY(-pos0.Theta()); pos.RotateZ(-M_PI/2); // exchange x and y pos *= -focal_dist/pos.Z(); v = pos.XYvector(); //cout << v.X() << " " << v.Y() << " " << v.Mod()*mm2deg << '\n'; */ if (!update) ins << "( " << file << ", " << event << ", " << v.X() << ", " << v.Y() << " ),\n"; else { ostringstream out; out << setprecision(16); out << "UPDATE `" << tab_position << "` SET X=" << v.X() << ", Y=" << v.Y() << " WHERE FileId=" << file << " AND EvtNumber=" << event; upd.emplace_back(out.str()); } } if (connection.errnum()) { cerr << "SQL error fetching row: " << connection.error() << endl; return 4; } if (verbose>0) cout << "Processed " << count << " events.\n" << endl; if (count==0) { if (verbose>0) cout << "Total execution time: " << Time().UnixTime()-start.UnixTime() << "s\n" << endl; return 0; } // ------------------------------------------------------------------------- // drop table if requested if (drop && !update) { try { if (verbose>0) cout << "Dropping table `" << tab_position << "`" << endl; if (!dry_run) connection.query("DROP TABLE `"+tab_position+"`").execute(); if (verbose>0) cout << "Table `" << tab_position << "` dropped.\n" << endl; } catch (const exception &e) { cerr << "DROP TABLE `" << tab_position << "`\n\n"; cerr << "SQL query failed:\n" << e.what() << endl; return 5; } } // ------------------------------------------------------------------------- // crate table if requested if (create && !update) { if (verbose>0) cout << "Creating table `" << tab_position << "`" << endl; const string query2 = "CREATE TABLE IF NOT EXISTS `"+tab_position+"`\n" "(\n" " FileId INT UNSIGNED NOT NULL,\n" " EvtNumber INT UNSIGNED NOT NULL,\n" " X FLOAT NOT NULL,\n" " Y FLOAT NOT NULL,\n" " PRIMARY KEY (FileId, EvtNumber)\n" ")\n" "DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci\n" "ENGINE=MyISAM\n" "COMMENT='created by "+conf.GetName()+"'\n"; try { if (!dry_run) connection.query(query2).execute(); } catch (const exception &e) { cerr << query2 << "\n\n"; cerr << "SQL query failed:\n" << e.what() << endl; return 6; } if (print_meta) cout << query2 << endl; if (verbose>0) cout << "Table `" << tab_position << "` created.\n" << endl; } // ------------------------------------------------------------------------- // delete old entries from table if (!drop && !update) { if (verbose>0) cout << "Deleting old entries from table `" << tab_position << "`" << endl; const string query2 = "DELETE FROM `"+tab_position+"` WHERE FileId="+to_string(file); try { if (!dry_run) { const mysqlpp::SimpleResult res = connection.query(query2).execute(); if (verbose>0) cout << res.rows() << " row(s) affected.\n" << endl; } } catch (const exception &e) { cerr << query2 << "\n\n"; cerr << "SQL query failed:\n" << e.what() << endl; return 7; } if (print_meta) cout << query2 << endl; } // ------------------------------------------------------------------------- // insert data into table if (!update) { if (verbose>0) cout << "Inserting data into table " << tab_position << "." << endl; const string query2 = "INSERT `"+tab_position+"` (FileId, EvtNumber, X, Y) VALUES\n"+ ins.str().substr(0, ins.str().size()-2)+ "\n"; try { if (!noinsert) { const mysqlpp::SimpleResult res = connection.query(query2).execute(); if (verbose>0) cout << res.rows() << " row(s) affected.\n" << endl; } } catch (const exception &e) { cerr << query2 << "\n\n"; cerr << "SQL query (" << query2.length() << " bytes) failed:\n" << e.what() << endl; return 8; } if (print_insert) cout << query2 << endl; } // ------------------------------------------------------------------------- // update data in table if (update) { if (verbose>0) cout << "Updating data in table " << tab_position << "." << endl; size_t cnt = 0; for (const auto &str : upd) { try { if (!noinsert && !dry_run) { const mysqlpp::SimpleResult res = connection.query(str).execute(); cnt += res.rows(); } } catch (const exception &e) { cerr << str << "\n\n"; cerr << "SQL query failed:\n" << e.what() << endl; return 9; } } if (verbose>0) cout << cnt << " row(s) out of " << upd.size() << " affected.\n" << endl; if (print_insert) { for (const auto &str : upd) cout << str << '\n'; cout << endl; } } if (verbose>0) cout << "Total execution time: " << Time().UnixTime()-start.UnixTime() << "s\n" << endl; return 0; } /* TRotation & TRotation::RotateX(Double_t a) { //rotate around x Double_t c = TMath::Cos(a); Double_t s = TMath::Sin(a); Double_t x = fyx, y = fyy, z = fyz; fyx = c*x - s*fzx; fyy = c*y - s*fzy; fyz = c*z - s*fzz; fzx = s*x + c*fzx; fzy = s*y + c*fzy; fzz = s*z + c*fzz; return *this; } TRotation & TRotation::RotateY(Double_t a){ //rotate around y Double_t c = TMath::Cos(a); Double_t s = TMath::Sin(a); Double_t x = fzx, y = fzy, z = fzz; fzx = c*x - s*fxx; fzy = c*y - s*fxy; fzz = c*z - s*fxz; fxx = s*x + c*fxx; fxy = s*y + c*fxy; fxz = s*z + c*fxz; return *this; } TRotation & TRotation::RotateZ(Double_t a) { //rotate around z Double_t c = TMath::Cos(a); Double_t s = TMath::Sin(a); Double_t x = fxx, y = fxy, z = fxz; fxx = c*x - s*fyx; fxy = c*y - s*fyy; fxz = c*z - s*fyz; fyx = s*x + c*fyx; fyy = s*y + c*fyy; fyz = s*z + c*fyz; return *this; } */ // Reuired: // pointing_ra[8] // pointing_dec[8] // fNanoSec[4], fTime[fMiliSec,8], fMjd[4] // source_ra -> rc // source_dec -> rc // fLong, fLat -> rc // fCameraDist -> rc // 32 byte per row, 1 Monat = 4mio rows => 120 MB /* void TVector3::SetThetaPhi(Double_t theta, Double_t phi) { //setter with mag, theta, phi fX = TMath::Sin(theta) * TMath::Cos(phi); fY = TMath::Sin(theta) * TMath::Sin(phi); fZ = TMath::Cos(theta); } // Set Sky coordinates of source, taken from container "MSourcePos" // of type MPointingPos. The sky coordinates must be J2000, as the // sky coordinates of the camera center that we get from the container // "MPointingPos" filled by the Drive. //MVector3 pos; // pos: source position //pos.SetRaDec(fSourcePos->GetRaRad(), fSourcePos->GetDecRad()); TVector3 pos; // pos: source position pos.SetMagThetaPhi(1, TMath::Pi()/2-source_dec, source_ra); // Set sky coordinates of camera center in pos0 (for details see below) //MVector3 pos0; // pos0: camera center //pos0.SetRaDec(fPointPos->GetRaRad(), fPointPos->GetDecRad()); TVector3 pos0; // pos: source position pos0.SetMagThetaPhi(1, TMath::Pi()/2-pointing_dec, pointing_ra); // Convert sky coordinates of source to local coordinates. Warning! These are not the "true" local // coordinates, since this transformation ignores precession and nutation effects. //const MAstroSky2Local conv(*fTime, *fObservatory); //pos *= conv; const Double_t ut = (Double_t)(fNanoSec/1e6+(Long_t)fTime)/kDay; // Julian centuries since J2000. const Double_t t = (ut -(51544.5-fMjd)) / 36525.0; // GMST at this UT1 const Double_t r1 = 24110.54841+(8640184.812866+(0.093104-6.2e-6*t)*t)*t; const Double_t r2 = 86400.0*ut; const Double_t sum = (r1+r2)/kDaySec; double gmst = fmod(sum, 1)*TMath::TwoPi(); // TRotation::TRotation(Double_t mxx, Double_t mxy, Double_t mxz, // Double_t myx, Double_t myy, Double_t myz, // Double_t mzx, Double_t mzy, Double_t mzz) // : fxx(mxx), fxy(mxy), fxz(mxz), // fyx(myx), fyy(myy), fyz(myz), // fzx(mzx), fzy(mzy), fzz(mzz) {} TRotation conv(1, 0, 0, 0, -1, 0, 0, 0, 1); conv.RotateZ(gmst + obs.GetElong()); conv.RotateY(obs.GetPhi()-TMath::Pi()/2); conv.RotateZ(TMath::Pi()); // TVector3 & TVector3::operator *= (const TRotation & m){ // return *this = m * (*this); // } // inline TVector3 TRotation::operator * (const TVector3 & p) const { // return TVector3(fxx*p.X() + fxy*p.Y() + fxz*p.Z(), // fyx*p.X() + fyy*p.Y() + fyz*p.Z(), // fzx*p.X() + fzy*p.Y() + fzz*p.Z()); // } // Convert sky coordinates of camera center convert to local. // Same comment as above. These coordinates differ from the true // local coordinates of the camera center that one could get from // "MPointingPos", calculated by the Drive: the reason is that the Drive // takes into account precession and nutation corrections, while // MAstroSky2Local (as of Jan 27 2005 at least) does not. Since we just // want to get the source position on the camera from the local // coordinates of the center and the source, it does not matter that // the coordinates contained in pos and pos0 ignore precession and // nutation... since the shift would be the same in both cases. What // would be wrong is to set in pos0 directly the local coordinates // found in MPointingPos! pos0 *= conv; if (fDeviation) { // Position at which the starguider camera is pointing in real: // pointing position = nominal position - dev // //vx = CalcXYinCamera(pos0, pos)*fGeom->GetCameraDist()*1000; pos0.SetZdAz(pos0.Theta()-fDeviation->GetDevZdRad(), pos0.Phi() -fDeviation->GetDevAzRad()); } // Calculate source position in camera, and convert to mm: TVector2 v = MAstro::GetDistOnPlain(pos0, pos, -fGeom->GetCameraDist()*1000); pos.RotateZ(-pos0.Phi()); pos.RotateY(-pos0.Theta()); pos.RotateZ(-TMath::Pi()/2); // exchange x and y pos *= -fGeom->GetCameraDist()*1000/pos.Z(); TVector2 v = pos.XYvector(); if (fDeviation) v -= fDeviation->GetDevXY()/fGeom->GetConvMm2Deg(); SetSrcPos(v); // ================================================ if (fMode==kWobble) { // The trick here is that the anti-source position in case // of the off-source regions is always the on-source positon // thus a proper anti-source cut is possible. fSrcPosAnti->SetXY(v); if (fCallback) v = Rotate(v, fCallback->GetNumPass(), fCallback->GetNumPasses()); else v *= -1; fSrcPosCam->SetXY(v); } else { // Because we don't process this three times like in the // wobble case we have to find another way to determine which // off-source region is the right anti-source position // We do it randomly. fSrcPosCam->SetXY(v); if (fNumRandomOffPositions>1) v = Rotate(v, gRandom->Integer(fNumRandomOffPositions), fNumRandomOffPositions); else v *= -1; fSrcPosAnti->SetXY(v); } */ /* PointingData CalcPointingPos(const PointingSetup &setup, double _mjd, const Weather &weather, uint16_t timeout, bool tpoint=false) { PointingData out; out.mjd = _mjd; const double elong = Nova::kORM.lng * M_PI/180; const double lat = Nova::kORM.lat * M_PI/180; const double height = 2200; const bool valid = weather.time+boost::posix_time::seconds(timeout) > Time(); const double temp = valid ? weather.temp : 10; const double hum = valid ? weather.hum : 0.25; const double press = valid ? weather.press : 780; const double dtt = palDtt(_mjd); // 32.184 + 35 const double tdb = _mjd + dtt/3600/24; const double dut = 0; // prepare calculation: Mean Place to geocentric apperent // (UTC would also do, except for the moon?) double fAmprms[21]; palMappa(2000.0, tdb, fAmprms); // Epoche, TDB // prepare: Apperent to observed place double fAoprms[14]; palAoppa(_mjd, dut, // mjd, Delta UT=UT1-UTC elong, lat, height, // long, lat, height 0, 0, // polar motion x, y-coordinate (radians) 273.155+temp, press, hum, // temp, pressure, humidity 0.40, 0.0065, // wavelength, tropo lapse rate fAoprms); out.source.ra = setup.source.ra * M_PI/ 12; out.source.dec = setup.source.dec * M_PI/180; if (setup.planet!=kENone) { // coordinates of planet: topocentric, equatorial, J2000 // One can use TT instead of TDB for all planets (except the moon?) double ra, dec, diam; palRdplan(tdb, setup.planet, elong, lat, &ra, &dec, &diam); // ---- apparent to mean ---- palAmpqk(ra, dec, fAmprms, &out.source.ra, &out.source.dec); } if (setup.wobble_offset<=0 || tpoint) { out.pointing.dec = out.source.dec; out.pointing.ra = out.source.ra; } else { const double dphi = setup.orbit_period==0 ? 0 : 2*M_PI*(_mjd-setup.start)/setup.orbit_period; const double phi = setup.wobble_angle + dphi; const double cosdir = cos(phi); const double sindir = sin(phi); const double cosoff = cos(setup.wobble_offset); const double sinoff = sin(setup.wobble_offset); const double cosdec = cos(out.source.dec); const double sindec = sin(out.source.dec); const double sintheta = sindec*cosoff + cosdec*sinoff*cosdir; const double costheta = sintheta>1 ? 0 : sqrt(1 - sintheta*sintheta); const double cosdeltara = (cosoff - sindec*sintheta)/(cosdec*costheta); const double sindeltara = sindir*sinoff/costheta; out.pointing.dec = asin(sintheta); out.pointing.ra = atan2(sindeltara, cosdeltara) + out.source.ra; } // ---- Mean to apparent ---- double r=0, d=0; palMapqkz(out.pointing.ra, out.pointing.dec, fAmprms, &r, &d); // // Doesn't work - don't know why // // slaMapqk (radec.Ra(), radec.Dec(), rdpm.Ra(), rdpm.Dec(), // 0, 0, (double*)fAmprms, &r, &d); // // -- apparent to observed -- palAopqk(r, d, fAoprms, &out.sky.az, // observed azimuth (radians: N=0,E=90) [-pi, pi] &out.sky.zd, // observed zenith distance (radians) [-pi/2, pi/2] &out.apparent.ha, // observed hour angle (radians) &out.apparent.dec, // observed declination (radians) &out.apparent.ra); // observed right ascension (radians) // ----- fix ambiguity ----- if (out.sky.zd<0) { out.sky.zd = -out.sky.zd; out.sky.az += out.sky.az<0 ? M_PI : -M_PI; } // Star culminating behind zenith and Az between ~90 and ~180deg if (out.source.dec0) out.sky.az -= 2*M_PI; out.mount = SkyToMount(out.sky); return out; } }; */