File indexing completed on 2024-09-08 03:28:59
0001 /* 0002 SPDX-FileCopyrightText: 2011-2016 Akarsh Simha <akarsh@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 /* 0008 * NOTE: I modified nomadbinfile2mysql to do this -- Akarsh 0009 */ 0010 0011 /* 0012 * TODO: VERY UGLY CODE. Please fix it some day. Preferably now. This 0013 * file was created from a modified C file, and needs to be recast 0014 * into the C++ way of writing stuff, i.e. with classes etc. 0015 */ 0016 0017 #include "nomadbinfile2sqlite.h" 0018 #include "binfile.h" 0019 #include "angconversion.h" 0020 #include "MeshIterator.h" 0021 #include <iostream> 0022 #include <string.h> 0023 #include <stdio.h> 0024 #define DEBUG false 0025 0026 using namespace std; 0027 0028 NOMADStarDataWriter::NOMADStarDataWriter(FILE *f, int HTMLevel, sqlite3 *_db, char *_db_tbl) 0029 { 0030 db = _db; 0031 DataFile = f; 0032 // Create a new shiny HTMesh 0033 m_Mesh = new HTMesh(HTMLevel, HTMLevel); 0034 strcpy(db_tbl, _db_tbl); 0035 m_HeaderRead = false; 0036 } 0037 0038 NOMADStarDataWriter::~NOMADStarDataWriter() 0039 { 0040 delete m_Mesh; 0041 } 0042 0043 void NOMADStarDataWriter::bswap_stardata(DeepStarData *stardata) 0044 { 0045 stardata->RA = bswap_32(stardata->RA); 0046 stardata->Dec = bswap_32(stardata->Dec); 0047 stardata->dRA = bswap_16(stardata->dRA); 0048 stardata->dDec = bswap_16(stardata->dDec); 0049 stardata->B = bswap_16(stardata->B); 0050 stardata->V = bswap_16(stardata->V); 0051 } 0052 0053 /** 0054 *@short Create the table 0055 */ 0056 bool NOMADStarDataWriter::createTable() 0057 { 0058 // TODO: This is not working. Investigate. 0059 char create_query[2048]; 0060 char index_query[2048]; 0061 char *errorMessage = 0; 0062 sprintf(create_query, 0063 "CREATE TABLE IF NOT EXISTS `%s` (`Trixel` int(32) NOT NULL , `RA` double NOT NULL , `Dec` double NOT NULL " 0064 ", `dRA` double NOT NULL , `dDec` double NOT NULL , `PM` double NOT NULL , `V` float NOT NULL , `B` float " 0065 "NOT NULL , `Mag` float NOT NULL , `UID` INTEGER UNIQUE PRIMARY KEY AUTOINCREMENT , `Copies` int(8) NOT " 0066 "NULL )", 0067 db_tbl); 0068 0069 if (sqlite3_exec(db, create_query, 0, 0, &errorMessage) != SQLITE_OK) 0070 { 0071 cerr << "ERROR: Table creation failed: " << errorMessage << endl; 0072 sqlite3_free(errorMessage); 0073 return false; 0074 } 0075 0076 sprintf(index_query, "CREATE INDEX IF NOT EXISTS `TrixelIndex` ON `%s`(`Trixel`)", db_tbl); 0077 0078 if (sqlite3_exec(db, index_query, 0, 0, &errorMessage) != SQLITE_OK) 0079 { 0080 cerr << "ERROR: Trixel index creation failed: " << errorMessage << endl; 0081 sqlite3_free(errorMessage); 0082 return false; 0083 } 0084 0085 return true; 0086 } 0087 0088 /** 0089 *@short Calculate the final destination RA and Dec of a star with the 0090 *given initial RA, Dec and proper motion rates after 'years' number 0091 *of years 0092 */ 0093 void NOMADStarDataWriter::calculatePMCoords(double startRA, double startDec, double dRA, double dDec, double *endRA, 0094 double *endDec, float years) 0095 { 0096 // (Translated from Perl) 0097 double theta0 = hour2rad(startRA); 0098 double lat0 = deg2rad(startDec); 0099 0100 double PMperyear = sqrt(dRA * dRA + dDec * dDec); 0101 0102 double dir0 = (years > 0.0) ? atan2(dRA, dDec) : atan2(-dRA, -dDec); // If years < 0, we're precessing backwards 0103 double PM = PMperyear * fabs(years); 0104 0105 double dst = deg2rad(arcsec2deg(PM / 1000.0)); // Milliarcsecond -> radian 0106 0107 double phi0 = M_PI / 2.0 - lat0; 0108 0109 double lat1 = asin(sin(lat0) * cos(dst) + cos(lat0) * sin(dst) * cos(dir0)); // Cosine rule on a sphere 0110 double dtheta = atan2(sin(dir0) * sin(dst) * cos(lat0), cos(dst) - sin(lat0) * sin(lat1)); 0111 0112 *endRA = rad2hour(theta0 + dtheta); 0113 *endDec = rad2deg(lat1); 0114 } 0115 0116 /** 0117 *@short Do some calculations and insert the star data into the database 0118 */ 0119 bool NOMADStarDataWriter::insertStarData(unsigned int trixel, const DeepStarData *const data) 0120 { 0121 char query[2048]; 0122 char *errorMessage = 0; 0123 float mag; 0124 float B, V, RA, Dec, dRA, dDec; 0125 0126 // Rescale the data from the structure 0127 B = ((double)data->B) / 1000.0; 0128 V = ((double)data->V) / 1000.0; 0129 RA = ((double)data->RA) / 1000000.0; 0130 Dec = ((double)data->Dec) / 100000.0; 0131 dRA = ((double)data->dRA) / 1000.0; 0132 dDec = ((double)data->dDec) / 1000.0; 0133 0134 // Check if the supplied trixel is really the trixel in which the 0135 // star is in according to its RA and Dec. If that's not the case, 0136 // this star is a duplicate and must be ignored 0137 unsigned int originalTrixelID = m_Mesh->index(RA, Dec); 0138 if (trixel != originalTrixelID) 0139 return true; // Ignore this star. 0140 0141 // Magnitude for sorting. 0142 if (V == 30.0 && B != 30.0) 0143 { 0144 mag = B - 1.6; 0145 } 0146 else 0147 { 0148 mag = V; 0149 } 0150 0151 // Compute the proper motion 0152 double RA1, Dec1, RA2, Dec2; 0153 double PM; // Magnitude of the proper motion in milliarcseconds per year 0154 0155 PM = sqrt(dRA * dRA + dDec * dDec); 0156 0157 calculatePMCoords(RA, Dec, dRA, dDec, &RA1, &Dec1, PM_MILLENIA * -1000.); 0158 calculatePMCoords(RA, Dec, dRA, dDec, &RA2, &Dec2, PM_MILLENIA * 1000.); 0159 0160 unsigned int TrixelList[900]; 0161 int ntrixels = 0; 0162 0163 double separation = sqrt(hour2deg(RA1 - RA2) * hour2deg(RA1 - RA2) + 0164 (Dec1 - Dec2) * (Dec1 - Dec2)); // Separation in degrees // ugly. 0165 if (separation > 50.0 / 60.0) // 50 arcminutes 0166 { 0167 m_Mesh->intersect(RA1, Dec1, RA2, Dec2); 0168 MeshIterator trixels(m_Mesh); 0169 while (trixels.hasNext()) 0170 { 0171 TrixelList[ntrixels] = trixels.next(); 0172 ntrixels++; 0173 } 0174 } 0175 else 0176 { 0177 TrixelList[0] = originalTrixelID; 0178 ntrixels = 1; 0179 } 0180 0181 if (ntrixels == 0) 0182 { 0183 cerr << "Ntrixels is zero in trixel " << originalTrixelID; 0184 return false; 0185 } 0186 0187 sprintf(query, 0188 "INSERT INTO `%s` (`Trixel`, `RA`, `Dec`, `dRA`, `dDec`, `B`, `V`, `mag`, `PM`, `Copies`) VALUES (:Trixel, " 0189 ":RA, :Dec, :dRA, :dDec, :B, :V, :mag, :PM, :Copies)", 0190 db_tbl); 0191 sqlite3_stmt *stmt; 0192 sqlite3_prepare_v2(db, query, -1, &stmt, 0); 0193 0194 if (sqlite3_exec(db, "BEGIN TRANSACTION", 0, 0, &errorMessage) != SQLITE_OK) 0195 { 0196 cerr << "SQLite INSERT INTO failed! Query was: " << endl << query << endl; 0197 cerr << "Error was: " << errorMessage << endl; 0198 sqlite3_free(errorMessage); 0199 return false; 0200 } 0201 0202 for (int i = 0; i < ntrixels; ++i) 0203 { 0204 sqlite3_bind_int(stmt, 1, TrixelList[i]); 0205 sqlite3_bind_double(stmt, 2, RA); 0206 sqlite3_bind_double(stmt, 3, Dec); 0207 sqlite3_bind_double(stmt, 4, dRA); 0208 sqlite3_bind_double(stmt, 5, dDec); 0209 sqlite3_bind_double(stmt, 6, B); 0210 sqlite3_bind_double(stmt, 7, V); 0211 sqlite3_bind_double(stmt, 8, mag); 0212 sqlite3_bind_double(stmt, 9, PM); 0213 sqlite3_bind_int(stmt, 10, ((TrixelList[i] == originalTrixelID) ? ntrixels : 0)); 0214 0215 sqlite3_step(stmt); 0216 sqlite3_clear_bindings(stmt); 0217 sqlite3_reset(stmt); 0218 } 0219 0220 if (sqlite3_exec(db, "END TRANSACTION", 0, 0, &errorMessage) != SQLITE_OK) 0221 { 0222 cerr << "SQLite INSERT INTO failed! Query was: " << endl << query << endl; 0223 cerr << "Error was: " << errorMessage << endl; 0224 sqlite3_free(errorMessage); 0225 return false; 0226 } 0227 0228 sqlite3_finalize(stmt); 0229 0230 return true; 0231 } 0232 0233 bool NOMADStarDataWriter::truncateTable() 0234 { 0235 // Truncate table. TODO: Issue warning etc 0236 char query[60]; 0237 char *errorMessage = 0; 0238 sprintf(query, "DELETE FROM `%s`; VACUUM;", db_tbl); 0239 if (sqlite3_exec(db, query, 0, 0, &errorMessage) != SQLITE_OK) 0240 { 0241 cerr << "Truncate table query \"" << query << "\" failed!" << endl; 0242 cerr << "Error was: " << errorMessage << endl; 0243 sqlite3_free(errorMessage); 0244 return false; 0245 } 0246 return true; 0247 } 0248 0249 /** 0250 *@short Write star data to the database 0251 */ 0252 bool NOMADStarDataWriter::writeStarDataToDB() 0253 { 0254 int8_t HTM_Level; 0255 u_int16_t MSpT; 0256 u_int32_t nstars; 0257 u_int32_t offset; 0258 unsigned int trixel; 0259 DeepStarData data; 0260 int16_t mag; 0261 0262 /* 0263 // TODO: FIX THIS // FIXME 0264 // We must at least check if the HTM level matches 0265 fseek( DataFile, m_IndexOffset - 3, SEEK_SET ); 0266 fread( &HTM_Level, 1, 1, DataFile ); 0267 fprintf( stdout, "HTMesh Level: %d\n", HTM_Level ); 0268 if( HTM_Level != m_Mesh->level() ) { 0269 cerr << "ERROR: HTMesh Level in file (" << HTM_Level << ") and HTM_LEVEL in program (" << m_Mesh->level() << ") differ." << endl 0270 << "Please set the define directive for HTM_LEVEL in the header file correctly and rebuild." 0271 << endl; 0272 return false; 0273 } 0274 */ 0275 char *errorMessage = 0; 0276 char query[2048]; 0277 0278 sprintf(query, 0279 "INSERT INTO `%s` (`Trixel`, `RA`, `Dec`, `dRA`, `dDec`, `B`, `V`, `mag`, `PM`, `Copies`) VALUES (:Trixel, " 0280 ":RA, :Dec, :dRA, :dDec, :B, :V, :mag, :PM, :Copies)", 0281 db_tbl); 0282 sqlite3_stmt *stmt; 0283 sqlite3_prepare_v2(db, query, -1, &stmt, 0); 0284 0285 if (sqlite3_exec(db, "BEGIN TRANSACTION", 0, 0, &errorMessage) != SQLITE_OK) 0286 { 0287 cerr << "SQLite BEGIN TRANSACTION failed! Query was: " << endl << query << endl; 0288 cerr << "Error was: " << errorMessage << endl; 0289 sqlite3_free(errorMessage); 0290 return false; 0291 } 0292 0293 for (trixel = 0; trixel < ntrixels; ++trixel) 0294 { 0295 fseek(DataFile, m_IndexOffset + trixel * INDEX_ENTRY_SIZE + 4, SEEK_SET); 0296 fread(&offset, 4, 1, DataFile); 0297 fread(&nstars, 4, 1, DataFile); 0298 0299 if (DEBUG) 0300 cerr << "Processing trixel " << trixel << " of " << ntrixels << endl; 0301 0302 /* If offset > 2^31 - 1, do the fseek in two steps */ 0303 if (offset > unsigned(pow2(31) - 1)) 0304 { 0305 fseek(DataFile, unsigned(pow2(31) - 1), SEEK_SET); 0306 fseek(DataFile, offset - pow2(31) + 1, SEEK_CUR); 0307 } 0308 else 0309 fseek(DataFile, offset, SEEK_SET); 0310 0311 for (int i = 0; i < nstars; ++i) 0312 { 0313 if (DEBUG) 0314 cerr << "Processing star " << i << " of " << nstars << " in trixel " << trixel << endl; 0315 fread(&data, sizeof(DeepStarData), 1, DataFile); 0316 if (byteswap) 0317 bswap_stardata(&data); 0318 0319 /** CODE FROM INSERTSTARDATA PASTED HERE FOR SPEED */ 0320 { 0321 float mag; 0322 float B, V, RA, Dec, dRA, dDec; 0323 0324 // Rescale the data from the structure 0325 B = ((double)data.B) / 1000.0; 0326 V = ((double)data.V) / 1000.0; 0327 RA = ((double)data.RA) / 1000000.0; 0328 Dec = ((double)data.Dec) / 100000.0; 0329 dRA = ((double)data.dRA) / 1000.0; 0330 dDec = ((double)data.dDec) / 1000.0; 0331 0332 // Check if the supplied trixel is really the trixel in which the 0333 // star is in according to its RA and Dec. If that's not the case, 0334 // this star is a duplicate and must be ignored 0335 unsigned int originalTrixelID = m_Mesh->index(hour2deg(RA), Dec); 0336 if (trixel != originalTrixelID) 0337 { 0338 cout << "Trixel = " << trixel << ", but this is the original Trixel ID: " << originalTrixelID 0339 << ". Skipping" << endl; 0340 cout << "Skipped star has (RA, Dec) = " << RA << Dec << "; (dRA, dDec) = " << dRA << dDec 0341 << "; and (B, V) = " << B << V << "." << endl; 0342 cout << "This suspected duplicate is star " << i << "in trixel " << trixel; 0343 continue; 0344 } 0345 0346 // Magnitude for sorting. 0347 if (V == 30.0 && B != 30.0) 0348 { 0349 mag = B - 1.6; 0350 } 0351 else 0352 { 0353 mag = V; 0354 } 0355 0356 // Compute the proper motion 0357 double RA1, Dec1, RA2, Dec2, RA1deg, RA2deg; 0358 double PM; // Magnitude of the proper motion in milliarcseconds per year 0359 0360 PM = sqrt(dRA * dRA + dDec * dDec); 0361 0362 calculatePMCoords(RA, Dec, dRA, dDec, &RA1, &Dec1, PM_MILLENIA * -1000.); 0363 calculatePMCoords(RA, Dec, dRA, dDec, &RA2, &Dec2, PM_MILLENIA * 1000.); 0364 RA1deg = hour2deg(RA1); 0365 RA2deg = hour2deg(RA2); 0366 0367 unsigned int TrixelList[60]; 0368 int nt = 0; 0369 0370 double separationsqr = (RA1deg - RA2deg) * (RA1deg - RA2deg) + 0371 (Dec1 - Dec2) * (Dec1 - Dec2); // Separation in degrees // ugly. 0372 if (separationsqr > 0373 0.69) // 50 arcminutes converted to degrees, squared and rounded below = 0.69. (This has nothing to do with sex positions.) 0374 { 0375 m_Mesh->intersect(RA1deg, Dec1, RA2deg, Dec2); 0376 MeshIterator trixels(m_Mesh); 0377 while (trixels.hasNext()) 0378 { 0379 TrixelList[nt] = trixels.next(); 0380 nt++; 0381 } 0382 } 0383 else 0384 { 0385 TrixelList[0] = originalTrixelID; 0386 nt = 1; 0387 } 0388 0389 if (nt == 0) 0390 { 0391 cerr << "# of trixels is zero in trixel " << originalTrixelID; 0392 return false; 0393 } 0394 0395 for (int i = 0; i < nt; ++i) 0396 { 0397 sqlite3_bind_int(stmt, 1, TrixelList[i]); 0398 sqlite3_bind_double(stmt, 2, RA); 0399 sqlite3_bind_double(stmt, 3, Dec); 0400 sqlite3_bind_double(stmt, 4, dRA); 0401 sqlite3_bind_double(stmt, 5, dDec); 0402 sqlite3_bind_double(stmt, 6, B); 0403 sqlite3_bind_double(stmt, 7, V); 0404 sqlite3_bind_double(stmt, 8, mag); 0405 sqlite3_bind_double(stmt, 9, PM); 0406 sqlite3_bind_int(stmt, 10, ((TrixelList[i] == originalTrixelID) ? ntrixels : 0)); 0407 0408 sqlite3_step(stmt); 0409 sqlite3_clear_bindings(stmt); 0410 sqlite3_reset(stmt); 0411 } 0412 } 0413 } 0414 if (trixel % 100 == 0 && trixel != 0) 0415 { 0416 if (sqlite3_exec(db, "END TRANSACTION", 0, 0, &errorMessage) != SQLITE_OK) 0417 { 0418 cerr << "SQLite END TRANSACTION failed! Query was: " << endl << query << endl; 0419 cerr << "Error was: " << errorMessage << endl; 0420 sqlite3_free(errorMessage); 0421 return false; 0422 } 0423 sqlite3_finalize(stmt); 0424 sqlite3_prepare_v2(db, query, -1, &stmt, 0); 0425 0426 if (sqlite3_exec(db, "BEGIN TRANSACTION", 0, 0, &errorMessage) != SQLITE_OK) 0427 { 0428 cerr << "SQLite BEGIN TRANSACTION failed! Query was: " << endl << query << endl; 0429 cerr << "Error was: " << errorMessage << endl; 0430 sqlite3_free(errorMessage); 0431 return false; 0432 } 0433 0434 cout << "Finished trixel " << trixel << endl; 0435 } 0436 } 0437 0438 if (sqlite3_exec(db, "END TRANSACTION", 0, 0, &errorMessage) != SQLITE_OK) 0439 { 0440 cerr << "SQLite INSERT INTO failed! Query was: " << endl << query << endl; 0441 cerr << "Error was: " << errorMessage << endl; 0442 sqlite3_free(errorMessage); 0443 return false; 0444 } 0445 0446 sqlite3_finalize(stmt); 0447 0448 return true; 0449 } 0450 0451 bool NOMADStarDataWriter::readFileHeader() 0452 { 0453 int i; 0454 int16_t endian_id; 0455 char ASCII_text[125]; 0456 u_int8_t version_no; 0457 u_int16_t nfields; 0458 0459 if (!DataFile) 0460 return false; 0461 0462 fread(ASCII_text, 124, 1, DataFile); 0463 ASCII_text[124] = '\0'; 0464 printf("%s", ASCII_text); 0465 0466 fread(&endian_id, 2, 1, DataFile); 0467 if (endian_id != 0x4B53) 0468 { 0469 fprintf(stdout, "Byteswapping required\n"); 0470 byteswap = 1; 0471 } 0472 else 0473 { 0474 fprintf(stdout, "Byteswapping not required\n"); 0475 byteswap = 0; 0476 } 0477 0478 fread(&version_no, 1, 1, DataFile); 0479 fprintf(stdout, "Version number: %d\n", version_no); 0480 0481 fread(&nfields, 2, 1, DataFile); 0482 0483 // Just to read those many bytes 0484 // TODO: Don't waste time and memory. fseek. 0485 dataElement de; 0486 for (i = 0; i < nfields; ++i) 0487 fread(&de, sizeof(struct dataElement), 1, DataFile); 0488 0489 fread(&ntrixels, 4, 1, DataFile); 0490 if (byteswap) 0491 ntrixels = bswap_32(ntrixels); 0492 fprintf(stdout, "Number of trixels reported = %d\n", ntrixels); 0493 0494 m_IndexOffset = ftell(DataFile); 0495 0496 m_HeaderRead = true; 0497 0498 return true; 0499 } 0500 0501 bool NOMADStarDataWriter::write() 0502 { 0503 if (!readFileHeader()) 0504 return false; 0505 if (!createTable()) 0506 return false; 0507 truncateTable(); 0508 if (!writeStarDataToDB()) 0509 return false; 0510 } 0511 0512 int main(int argc, char *argv[]) 0513 { 0514 sqlite3 *db; 0515 FILE *f; 0516 char db_tbl[20]; 0517 char db_name[20]; 0518 int rc; 0519 0520 if (argc <= 3) 0521 { 0522 fprintf(stderr, "USAGE: %s <NOMAD bin file> <SQLite DB File Name> <Table Name>\n", argv[0]); 0523 return 1; 0524 } 0525 0526 strcpy(db_name, argv[2]); 0527 strcpy(db_tbl, argv[3]); 0528 0529 f = fopen(argv[1], "r"); 0530 0531 if (f == NULL) 0532 { 0533 fprintf(stderr, "ERROR: Could not open file %s for binary read.\n", argv[1]); 0534 return 1; 0535 } 0536 0537 /* Open the Database */ 0538 if (sqlite3_open(db_name, &db)) 0539 { 0540 fprintf(stderr, "ERROR: Failed to open database: %s\n", sqlite3_errmsg(db)); 0541 sqlite3_close(db); 0542 return 1; 0543 } 0544 0545 NOMADStarDataWriter writer(f, HTM_LEVEL, db, db_tbl); 0546 0547 writer.write(); 0548 0549 fclose(f); 0550 sqlite3_close(db); 0551 return 0; 0552 }