File indexing completed on 2024-09-08 03:28:59
0001 /* 0002 SPDX-FileCopyrightText: 2011 Akarsh Simha <akarshsimha@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 /* 0008 * NOTE: I modified nomadbinfiletester.c 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 "nomadbinfile2mysql.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 0025 using namespace std; 0026 0027 NOMADStarDataWriter::NOMADStarDataWriter(FILE *f, int HTMLevel, MYSQL *link, char *_db_tbl) 0028 { 0029 m_MySQLLink = link; 0030 DataFile = f; 0031 // Create a new shiny HTMesh 0032 m_Mesh = new HTMesh(HTMLevel, HTMLevel); 0033 strcpy(db_tbl, _db_tbl); 0034 m_HeaderRead = false; 0035 } 0036 0037 NOMADStarDataWriter::~NOMADStarDataWriter() 0038 { 0039 delete m_Mesh; 0040 } 0041 0042 void NOMADStarDataWriter::bswap_stardata(DeepStarData *stardata) 0043 { 0044 stardata->RA = bswap_32(stardata->RA); 0045 stardata->Dec = bswap_32(stardata->Dec); 0046 stardata->dRA = bswap_16(stardata->dRA); 0047 stardata->dDec = bswap_16(stardata->dDec); 0048 stardata->B = bswap_16(stardata->B); 0049 stardata->V = bswap_16(stardata->V); 0050 } 0051 0052 /** 0053 *@short Create the table 0054 */ 0055 bool NOMADStarDataWriter::createTable() 0056 { 0057 // TODO: This is not working. Investigate. 0058 char create_query[2048]; 0059 sprintf(create_query, 0060 "CREATE TABLE IF NOT EXISTS `%s` (`Trixel` int(32) NOT NULL COMMENT 'Trixel Number', `RA` double NOT NULL " 0061 "COMMENT 'RA Hours', `Dec` double NOT NULL COMMENT 'Declination Degrees', `dRA` double NOT NULL COMMENT " 0062 "'Proper Motion along RA', `dDec` double NOT NULL COMMENT 'Proper Motion along Dec', `PM` double NOT NULL " 0063 "COMMENT 'Proper Motion (magnitude)', `V` float NOT NULL COMMENT 'Visual Magnitude', `B` float NOT NULL " 0064 "COMMENT 'Blue Magnitude', `Mag` float NOT NULL COMMENT 'Magnitude for sorting', `UID` int(64) NOT NULL " 0065 "auto_increment COMMENT 'Unique ID', `Copies` tinyint(8) NOT NULL COMMENT 'Number of Copies of the star', " 0066 "PRIMARY KEY (`UID`), UNIQUE KEY `UID` (`UID`), KEY `Trixel` (`Trixel`,`PM`,`Mag`)) ENGINE=MyISAM DEFAULT " 0067 "CHARSET=latin1 AUTO_INCREMENT=1", 0068 db_tbl); 0069 0070 if (mysql_query(m_MySQLLink, create_query)) 0071 { 0072 cerr << "ERROR: Table creation failed!" << endl; 0073 return false; 0074 } 0075 return true; 0076 } 0077 0078 /** 0079 *@short Calculate the final destination RA and Dec of a star with the 0080 *given initial RA, Dec and proper motion rates after 'years' number 0081 *of years 0082 */ 0083 void NOMADStarDataWriter::calculatePMCoords(double startRA, double startDec, double dRA, double dDec, double *endRA, 0084 double *endDec, float years) 0085 { 0086 // (Translated from Perl) 0087 double theta0 = hour2rad(startRA); 0088 double lat0 = deg2rad(startDec); 0089 0090 double PMperyear = sqrt(dRA * dRA + dDec * dDec); 0091 0092 double dir0 = (years > 0.0) ? atan2(dRA, dDec) : atan2(-dRA, -dDec); // If years < 0, we're precessing backwards 0093 double PM = PMperyear * fabs(years); 0094 0095 double dst = deg2rad(arcsec2deg(PM / 1000.0)); // Milliarcsecond -> radian 0096 0097 double phi0 = M_PI / 2.0 - lat0; 0098 0099 double lat1 = asin(sin(lat0) * cos(dst) + cos(lat0) * sin(dst) * cos(dir0)); // Cosine rule on a sphere 0100 double dtheta = atan2(sin(dir0) * sin(dst) * cos(lat0), cos(dst) - sin(lat0) * sin(lat1)); 0101 0102 *endRA = rad2hour(theta0 + dtheta); 0103 *endDec = rad2deg(lat1); 0104 } 0105 0106 /** 0107 *@short Do some calculations and insert the star data into the database 0108 */ 0109 bool NOMADStarDataWriter::insertStarData(unsigned int trixel, const DeepStarData *const data) 0110 { 0111 char query[2048]; 0112 float mag; 0113 float B, V, RA, Dec, dRA, dDec; 0114 0115 // Rescale the data from the structure 0116 B = ((double)data->B) / 1000.0; 0117 V = ((double)data->V) / 1000.0; 0118 RA = ((double)data->RA) / 1000000.0; 0119 Dec = ((double)data->Dec) / 100000.0; 0120 dRA = ((double)data->dRA) / 1000.0; 0121 dDec = ((double)data->dDec) / 1000.0; 0122 0123 // Check if the supplied trixel is really the trixel in which the 0124 // star is in according to its RA and Dec. If that's not the case, 0125 // this star is a duplicate and must be ignored 0126 unsigned int originalTrixelID = m_Mesh->index(RA, Dec); 0127 if (trixel != originalTrixelID) 0128 return true; // Ignore this star. 0129 0130 // Magnitude for sorting. 0131 if (V == 30.0 && B != 30.0) 0132 { 0133 mag = B - 1.6; 0134 } 0135 else 0136 { 0137 mag = V; 0138 } 0139 0140 // Compute the proper motion 0141 double RA1, Dec1, RA2, Dec2; 0142 double PM; // Magnitude of the proper motion in milliarcseconds per year 0143 0144 PM = sqrt(dRA * dRA + dDec * dDec); 0145 0146 calculatePMCoords(RA, Dec, dRA, dDec, &RA1, &Dec1, PM_MILLENIA * -1000.); 0147 calculatePMCoords(RA, Dec, dRA, dDec, &RA2, &Dec2, PM_MILLENIA * 1000.); 0148 0149 unsigned int TrixelList[900]; 0150 int ntrixels = 0; 0151 0152 double separation = sqrt(hour2deg(RA1 - RA2) * hour2deg(RA1 - RA2) + 0153 (Dec1 - Dec2) * (Dec1 - Dec2)); // Separation in degrees // ugly. 0154 if (separation > 50.0 / 60.0) // 50 arcminutes 0155 { 0156 m_Mesh->intersect(RA1, Dec1, RA2, Dec2); 0157 MeshIterator trixels(m_Mesh); 0158 while (trixels.hasNext()) 0159 { 0160 TrixelList[ntrixels] = trixels.next(); 0161 ntrixels++; 0162 } 0163 } 0164 else 0165 { 0166 TrixelList[0] = originalTrixelID; 0167 ntrixels = 1; 0168 } 0169 0170 if (ntrixels == 0) 0171 { 0172 cerr << "Ntrixels is zero in trixel " << originalTrixelID; 0173 return false; 0174 } 0175 0176 for (int i = 0; i < ntrixels; ++i) 0177 { 0178 sprintf(query, 0179 "INSERT INTO `%s` (`Trixel`, `RA`, `Dec`, `dRA`, `dDec`, `B`, `V`, `mag`, `PM`, `Copies`) VALUES " 0180 "(\'%d\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%u\')", 0181 db_tbl, TrixelList[i], RA, Dec, dRA, dDec, B, V, mag, PM, 0182 ((TrixelList[i] == originalTrixelID) ? 0183 ntrixels : 0184 0) // Duplicates get a 'Copies' value of 0. The real star gets the actual value. 0185 ); 0186 if (mysql_query(m_MySQLLink, query)) 0187 { 0188 cerr << "MySQL INSERT INTO failed! Query was: " << endl << query << endl; 0189 return false; 0190 } 0191 } 0192 return true; 0193 } 0194 0195 bool NOMADStarDataWriter::truncateTable() 0196 { 0197 // Truncate table. TODO: Issue warning etc 0198 char query[60]; 0199 sprintf(query, "TRUNCATE TABLE `%s`", db_tbl); 0200 if (mysql_query(m_MySQLLink, query)) 0201 { 0202 cerr << "Truncate table query \"" << query << "\" failed!" << endl; 0203 return false; 0204 } 0205 return true; 0206 } 0207 0208 /** 0209 *@short Write star data to the database 0210 */ 0211 bool NOMADStarDataWriter::writeStarDataToDB() 0212 { 0213 int8_t HTM_Level; 0214 u_int16_t MSpT; 0215 u_int32_t nstars; 0216 u_int32_t offset; 0217 unsigned int trixel; 0218 DeepStarData data; 0219 int16_t mag; 0220 0221 /* 0222 // TODO: FIX THIS // FIXME 0223 // We must at least check if the HTM level matches 0224 fseek( DataFile, m_IndexOffset - 3, SEEK_SET ); 0225 fread( &HTM_Level, 1, 1, DataFile ); 0226 fprintf( stdout, "HTMesh Level: %d\n", HTM_Level ); 0227 if( HTM_Level != m_Mesh->level() ) { 0228 cerr << "ERROR: HTMesh Level in file (" << HTM_Level << ") and HTM_LEVEL in program (" << m_Mesh->level() << ") differ." << endl 0229 << "Please set the define directive for HTM_LEVEL in the header file correctly and rebuild." 0230 << endl; 0231 return false; 0232 } 0233 */ 0234 0235 for (trixel = 0; trixel < ntrixels; ++trixel) 0236 { 0237 fseek(DataFile, m_IndexOffset + trixel * INDEX_ENTRY_SIZE + 4, SEEK_SET); 0238 fread(&offset, 4, 1, DataFile); 0239 fread(&nstars, 4, 1, DataFile); 0240 0241 /* If offset > 2^31 - 1, do the fseek in two steps */ 0242 if (offset > (unsigned)(pow2(31) - 1)) 0243 { 0244 fseek(DataFile, pow2(31) - 1, SEEK_SET); 0245 fseek(DataFile, offset - pow2(31) + 1, SEEK_CUR); 0246 } 0247 else 0248 fseek(DataFile, offset, SEEK_SET); 0249 0250 for (int i = 0; i < nstars; ++i) 0251 { 0252 fread(&data, sizeof(DeepStarData), 1, DataFile); 0253 if (byteswap) 0254 bswap_stardata(&data); 0255 0256 /** CODE FROM INSERTSTARDATA PASTED HERE FOR SPEED */ 0257 { 0258 char query[2048]; 0259 float mag; 0260 float B, V, RA, Dec, dRA, dDec; 0261 0262 // Rescale the data from the structure 0263 B = ((double)data.B) / 1000.0; 0264 V = ((double)data.V) / 1000.0; 0265 RA = ((double)data.RA) / 1000000.0; 0266 Dec = ((double)data.Dec) / 100000.0; 0267 dRA = ((double)data.dRA) / 1000.0; 0268 dDec = ((double)data.dDec) / 1000.0; 0269 0270 // Check if the supplied trixel is really the trixel in which the 0271 // star is in according to its RA and Dec. If that's not the case, 0272 // this star is a duplicate and must be ignored 0273 unsigned int originalTrixelID = m_Mesh->index(hour2deg(RA), Dec); 0274 if (trixel != originalTrixelID) 0275 { 0276 cout << "Trixel = " << trixel << ", but this is the original Trixel ID: " << originalTrixelID 0277 << ". Skipping" << endl; 0278 cout << "Skipped star has (RA, Dec) = " << RA << Dec << "; (dRA, dDec) = " << dRA << dDec 0279 << "; and (B, V) = " << B << V << "." << endl; 0280 cout << "This suspected duplicate is star " << i << "in trixel " << trixel; 0281 continue; 0282 } 0283 0284 // Magnitude for sorting. 0285 if (V == 30.0 && B != 30.0) 0286 { 0287 mag = B - 1.6; 0288 } 0289 else 0290 { 0291 mag = V; 0292 } 0293 0294 // Compute the proper motion 0295 double RA1, Dec1, RA2, Dec2, RA1deg, RA2deg; 0296 double PM; // Magnitude of the proper motion in milliarcseconds per year 0297 0298 PM = sqrt(dRA * dRA + dDec * dDec); 0299 0300 calculatePMCoords(RA, Dec, dRA, dDec, &RA1, &Dec1, PM_MILLENIA * -1000.); 0301 calculatePMCoords(RA, Dec, dRA, dDec, &RA2, &Dec2, PM_MILLENIA * 1000.); 0302 RA1deg = hour2deg(RA1); 0303 RA2deg = hour2deg(RA2); 0304 0305 unsigned int TrixelList[60]; 0306 int nt = 0; 0307 0308 double separationsqr = (RA1deg - RA2deg) * (RA1deg - RA2deg) + 0309 (Dec1 - Dec2) * (Dec1 - Dec2); // Separation in degrees // ugly. 0310 if (separationsqr > 0311 0.69) // 50 arcminutes converted to degrees, squared and rounded below = 0.69. (This has nothing to do with sex positions.) 0312 { 0313 m_Mesh->intersect(RA1deg, Dec1, RA2deg, Dec2); 0314 MeshIterator trixels(m_Mesh); 0315 while (trixels.hasNext()) 0316 { 0317 TrixelList[nt] = trixels.next(); 0318 nt++; 0319 } 0320 } 0321 else 0322 { 0323 TrixelList[0] = originalTrixelID; 0324 nt = 1; 0325 } 0326 0327 if (nt == 0) 0328 { 0329 cerr << "# of trixels is zero in trixel " << originalTrixelID; 0330 return false; 0331 } 0332 0333 for (int i = 0; i < nt; ++i) 0334 { 0335 sprintf(query, 0336 "INSERT INTO `%s` (`Trixel`, `RA`, `Dec`, `dRA`, `dDec`, `B`, `V`, `mag`, `PM`, `Copies`) " 0337 "VALUES (\'%d\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', \'%lf\', " 0338 "\'%u\')", 0339 db_tbl, TrixelList[i], RA, Dec, dRA, dDec, B, V, mag, PM, 0340 ((TrixelList[i] == originalTrixelID) ? 0341 nt : 0342 0) // Duplicates get a 'Copies' value of 0. The real star gets the actual value. 0343 ); 0344 if (mysql_query(m_MySQLLink, query)) 0345 { 0346 cerr << "MySQL INSERT INTO failed! Query was: " << endl << query << endl; 0347 return false; 0348 } 0349 } 0350 } 0351 } 0352 if (trixel % 100 == 0) 0353 cout << "Finished trixel " << trixel << endl; 0354 } 0355 0356 return true; 0357 } 0358 0359 bool NOMADStarDataWriter::readFileHeader() 0360 { 0361 int i; 0362 int16_t endian_id; 0363 char ASCII_text[125]; 0364 u_int8_t version_no; 0365 u_int16_t nfields; 0366 0367 if (!DataFile) 0368 return false; 0369 0370 fread(ASCII_text, 124, 1, DataFile); 0371 ASCII_text[124] = '\0'; 0372 printf("%s", ASCII_text); 0373 0374 fread(&endian_id, 2, 1, DataFile); 0375 if (endian_id != 0x4B53) 0376 { 0377 fprintf(stdout, "Byteswapping required\n"); 0378 byteswap = 1; 0379 } 0380 else 0381 { 0382 fprintf(stdout, "Byteswapping not required\n"); 0383 byteswap = 0; 0384 } 0385 0386 fread(&version_no, 1, 1, DataFile); 0387 fprintf(stdout, "Version number: %d\n", version_no); 0388 0389 fread(&nfields, 2, 1, DataFile); 0390 0391 // Just to read those many bytes 0392 // TODO: Don't waste time and memory. fseek. 0393 dataElement de; 0394 for (i = 0; i < nfields; ++i) 0395 fread(&de, sizeof(struct dataElement), 1, DataFile); 0396 0397 fread(&ntrixels, 4, 1, DataFile); 0398 if (byteswap) 0399 ntrixels = bswap_32(ntrixels); 0400 fprintf(stdout, "Number of trixels reported = %d\n", ntrixels); 0401 0402 m_IndexOffset = ftell(DataFile); 0403 0404 m_HeaderRead = true; 0405 0406 return true; 0407 } 0408 0409 bool NOMADStarDataWriter::write() 0410 { 0411 if (!readFileHeader()) 0412 return false; 0413 if (!createTable()) 0414 return false; 0415 truncateTable(); 0416 if (!writeStarDataToDB()) 0417 return false; 0418 } 0419 0420 int main(int argc, char *argv[]) 0421 { 0422 MYSQL link; 0423 FILE *f; 0424 char db_tbl[20]; 0425 char db_name[20]; 0426 0427 if (argc <= 5) 0428 { 0429 fprintf(stderr, "USAGE: %s <NOMAD bin file> <MySQL DB User> <Password> <DB Name> <Table Name>\n", argv[0]); 0430 return 1; 0431 } 0432 0433 strcpy(db_tbl, argv[5]); 0434 strcpy(db_name, argv[4]); 0435 0436 f = fopen(argv[1], "r"); 0437 0438 if (f == nullptr) 0439 { 0440 fprintf(stderr, "ERROR: Could not open file %s for binary read.\n", argv[1]); 0441 return 1; 0442 } 0443 0444 /* Open the Database */ 0445 if (mysql_init(&link) == nullptr) 0446 { 0447 fprintf(stderr, "ERROR: Failed to initialize MySQL connection!\n"); 0448 return 1; 0449 } 0450 MYSQL *ret; 0451 ret = mysql_real_connect(&link, "localhost", argv[2], argv[3], db_name, 0, nullptr, 0); 0452 0453 if (!ret) 0454 { 0455 fprintf(stderr, "ERROR: MySQL connect failed for the following reason: %s\n", mysql_error(&link)); 0456 fcloseall(); 0457 return 1; 0458 } 0459 0460 if (mysql_select_db(&link, db_name)) 0461 { 0462 fprintf(stderr, "ERROR: Could not select MySQL database %s. MySQL said: %s", db_name, mysql_error(&link)); 0463 fcloseall(); 0464 mysql_close(&link); 0465 return 1; 0466 } 0467 0468 NOMADStarDataWriter writer(f, HTM_LEVEL, &link, db_tbl); 0469 0470 writer.write(); 0471 0472 fclose(f); 0473 mysql_close(&link); 0474 return 0; 0475 }