File indexing completed on 2025-01-12 03:30:51
0001 /* KStars tests 0002 SPDX-FileCopyrightText: 2020 Eric Dejouhanet <eric.dejouhanet@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <QTest> 0008 #include <memory> 0009 #include "testfitsdata.h" 0010 #include "Options.h" 0011 #include "ekos/auxiliary/solverutils.h" 0012 #include "ekos/auxiliary/stellarsolverprofile.h" 0013 #include <QtGlobal> 0014 0015 Q_DECLARE_METATYPE(FITSMode); 0016 0017 TestFitsData::TestFitsData(QObject *parent) : QObject(parent) 0018 { 0019 } 0020 0021 void TestFitsData::initTestCase() 0022 { 0023 Options::setStellarSolverPartition(true); 0024 } 0025 0026 void TestFitsData::cleanupTestCase() 0027 { 0028 } 0029 0030 void TestFitsData::init() 0031 { 0032 0033 } 0034 0035 void TestFitsData::cleanup() 0036 { 0037 0038 } 0039 0040 void TestFitsData::testComputeHFR_data() 0041 { 0042 #if QT_VERSION < 0x050900 0043 QSKIP("Skipping fixture-based test on old QT version."); 0044 #else 0045 QTest::addColumn<QString>("NAME"); 0046 QTest::addColumn<FITSMode>("MODE"); 0047 QTest::addColumn<int>("NSTARS"); 0048 QTest::addColumn<double>("HFR"); 0049 0050 // Normal HFR differs from focusHFR, in that the 'quickHFR' setting 0051 // defaults to true, so only the 25% in the center of the image 0052 // will have stars detected and HFRs computed. 'quickHFR' does not apply 0053 // to FITS_FOCUS images, only to FITS_NORMAL images. 0054 0055 // Normal HFR tests 0056 QTest::newRow("NGC4535-1-FOCUS") << "ngc4535-autofocus1.fits" << FITS_FOCUS << 11 << 3.92; 0057 QTest::newRow("NGC4535-2-FOCUS") << "ngc4535-autofocus2.fits" << FITS_FOCUS << 17 << 2.13; 0058 QTest::newRow("NGC4535-3-FOCUS") << "ngc4535-autofocus3.fits" << FITS_FOCUS << 126 << 1.254911; 0059 0060 // Focus HFR tests 0061 QTest::newRow("NGC4535-1-NORMAL") << "ngc4535-autofocus1.fits" << FITS_NORMAL << 3 << 3.17; 0062 QTest::newRow("NGC4535-2-NORMAL") << "ngc4535-autofocus2.fits" << FITS_NORMAL << 4 << 1.99; 0063 QTest::newRow("NGC4535-3-NORMAL") << "ngc4535-autofocus3.fits" << FITS_NORMAL << 30 << 1.22; 0064 #endif 0065 } 0066 0067 void TestFitsData::testComputeHFR() 0068 { 0069 #if QT_VERSION < 0x050900 0070 QSKIP("Skipping fixture-based test on old QT version."); 0071 #else 0072 QFETCH(QString, NAME); 0073 QFETCH(FITSMode, MODE); 0074 QFETCH(int, NSTARS); 0075 QFETCH(double, HFR); 0076 0077 if(!QFile::exists(NAME)) 0078 QSKIP("Skipping load test because of missing fixture"); 0079 0080 std::unique_ptr<FITSData> d(new FITSData(MODE)); 0081 QVERIFY(d != nullptr); 0082 0083 QFuture<bool> worker = d->loadFromFile(NAME); 0084 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 60000); 0085 QVERIFY(worker.result()); 0086 0087 worker = d->findStars(ALGORITHM_SEP); 0088 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 10000); 0089 QVERIFY(worker.result()); 0090 0091 QCOMPARE(d->getDetectedStars(), NSTARS); 0092 QCOMPARE(d->getStarCenters().count(), NSTARS); 0093 QVERIFY2(abs(d->getHFR() - HFR) <= 0.1, qPrintable(QString("HFR expected(measured): %1(%2)").arg(HFR).arg(d->getHFR()))); 0094 #endif 0095 } 0096 0097 void TestFitsData::testBahtinovFocusHFR_data() 0098 { 0099 #if QT_VERSION < 0x050900 0100 QSKIP("Skipping fixture-based test on old QT version."); 0101 #else 0102 QTest::addColumn<QString>("NAME"); 0103 QTest::addColumn<FITSMode>("MODE"); 0104 QTest::addColumn<int>("NSTARS"); 0105 QTest::addColumn<double>("HFR"); 0106 0107 QTest::newRow("BAHTINOV-1-NORMAL") << "bahtinov-focus.fits" << FITS_NORMAL << 1 << 1.544; 0108 #endif 0109 } 0110 0111 void TestFitsData::testBahtinovFocusHFR() 0112 { 0113 #if QT_VERSION < 0x050900 0114 QSKIP("Skipping fixture-based test on old QT version."); 0115 #else 0116 QFETCH(QString, NAME); 0117 QFETCH(FITSMode, MODE); 0118 QFETCH(int, NSTARS); 0119 QFETCH(double, HFR); 0120 0121 if(!QFile::exists(NAME)) 0122 QSKIP("Skipping load test because of missing fixture"); 0123 0124 std::unique_ptr<FITSData> d(new FITSData(MODE)); 0125 QVERIFY(d != nullptr); 0126 0127 QFuture<bool> worker = d->loadFromFile(NAME); 0128 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 10000); 0129 QVERIFY(worker.result()); 0130 0131 // The bahtinov algorithm depends on which star is selected and number of average rows - not sure how to fiddle with that yet 0132 const QRect trackingBox(204, 240, 128, 128); 0133 0134 d->findStars(ALGORITHM_BAHTINOV, trackingBox).waitForFinished(); 0135 QCOMPARE(d->getDetectedStars(), NSTARS); 0136 QCOMPARE(d->getStarCenters().count(), 1); 0137 QVERIFY(abs(d->getHFR() - HFR) < 0.01); 0138 #endif 0139 } 0140 0141 void TestFitsData::initGenericDataFixture() 0142 { 0143 #if QT_VERSION < 0x050900 0144 QSKIP("Skipping fixture-based test on old QT version."); 0145 #else 0146 QTest::addColumn<QString>("NAME"); 0147 QTest::addColumn<FITSMode>("MODE"); 0148 0149 // Star count 0150 QTest::addColumn<int>("NSTARS_CENTROID"); 0151 QTest::addColumn<int>("NSTARS_STELLARSOLVER"); 0152 0153 // HFRs using variouls methods 0154 QTest::addColumn<double>("HFR_CENTROID"); 0155 QTest::addColumn<double>("HFR_GRADIENT"); 0156 QTest::addColumn<double>("HFR_THRESHOLD"); 0157 QTest::addColumn<double>("HFR_STELLARSOLVER"); 0158 0159 // Statistics 0160 QTest::addColumn<double>("ADU"); 0161 QTest::addColumn<double>("MEAN"); 0162 QTest::addColumn<double>("STDDEV"); 0163 QTest::addColumn<double>("SNR"); 0164 QTest::addColumn<long>("MAXIMUM"); 0165 QTest::addColumn<long>("MINIMUM"); 0166 QTest::addColumn<double>("MEDIAN"); 0167 0168 // This tracking box should detect a single centered star using SEP 0169 QTest::addColumn<QRect>("TRACKING_BOX"); 0170 0171 QTest::newRow("M47-1-NORMAL") 0172 << "m47_sim_stars.fits" 0173 << FITS_NORMAL 0174 << 80 // Stars found with the Centroid detection 0175 << 104 // Stars found with the StellarSolver detection - default profile limits count 0176 << 1.49 // HFR found with the Centroid detection 0177 << 1.482291 // HFR found with the Gradient detection 0178 << 0.0 // HFR found with the Threshold detection - not used 0179 << 1.482291 // HFR found with the StellarSolver detection 0180 << 41.08 // ADU 0181 << 41.08 // Mean 0182 << 360.2932 // StdDev 0183 << 0.114 // SNR 0184 << 57832L // Max 0185 << 21L // Min 0186 << 31.0 // Median 0187 << QRect(591 - 16 / 2, 482 - 16 / 2, 16, 16); 0188 #endif 0189 } 0190 0191 void TestFitsData::testLoadFits_data() 0192 { 0193 #if QT_VERSION < 0x050900 0194 QSKIP("Skipping fixture-based test on old QT version."); 0195 #else 0196 initGenericDataFixture(); 0197 #endif 0198 } 0199 0200 void TestFitsData::testLoadFits() 0201 { 0202 #if QT_VERSION < 0x050900 0203 QSKIP("Skipping fixture-based test on old QT version."); 0204 #else 0205 QFETCH(QString, NAME); 0206 QFETCH(FITSMode, MODE); 0207 QFETCH(int, NSTARS_CENTROID); 0208 QFETCH(int, NSTARS_STELLARSOLVER); 0209 QFETCH(double, HFR_CENTROID); 0210 QFETCH(double, HFR_GRADIENT); 0211 QFETCH(double, HFR_THRESHOLD); 0212 Q_UNUSED(HFR_THRESHOLD); 0213 QFETCH(double, HFR_STELLARSOLVER); 0214 QFETCH(double, ADU); 0215 QFETCH(double, MEAN); 0216 QFETCH(double, STDDEV); 0217 QFETCH(double, SNR); 0218 QFETCH(long, MAXIMUM); 0219 QFETCH(long, MINIMUM); 0220 QFETCH(double, MEDIAN); 0221 QFETCH(QRect, TRACKING_BOX); 0222 0223 if(!QFile::exists(NAME)) 0224 QSKIP("Skipping load test because of missing fixture"); 0225 0226 std::unique_ptr<FITSData> fd(new FITSData(MODE)); 0227 QVERIFY(fd != nullptr); 0228 0229 QFuture<bool> worker = fd->loadFromFile(NAME); 0230 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 10000); 0231 QVERIFY(worker.result()); 0232 0233 // Statistics computation 0234 QVERIFY(abs(fd->getADU() - ADU) < 0.01); 0235 QVERIFY(abs(fd->getMean() - MEAN) < 0.01); 0236 fprintf(stderr, "%f vs %f (%f\n", fd->getStdDev(), STDDEV, abs(fd->getStdDev() - STDDEV)); 0237 QVERIFY(abs(fd->getStdDev() - STDDEV) < 0.01); 0238 QVERIFY(abs(fd->getSNR() - SNR) < 0.001); 0239 0240 // Minmax 0241 QCOMPARE((long)fd->getMax(), MAXIMUM); 0242 QCOMPARE((long)fd->getMin(), MINIMUM); 0243 0244 QVERIFY(abs(fd->getMedian() - MEDIAN) < 0.01); 0245 0246 // Without searching for stars, there are no stars found 0247 QCOMPARE(fd->getStarCenters().count(), 0); 0248 QCOMPARE(fd->getHFR(), -1.0); 0249 0250 // Default algorithm is centroid, 80 stars with 1.495 as HFR 0251 fd->findStars().waitForFinished(); 0252 QCOMPARE(fd->getDetectedStars(), NSTARS_CENTROID); 0253 QCOMPARE(fd->getStarCenters().count(), NSTARS_CENTROID); 0254 QVERIFY(abs(fd->getHFR() - HFR_CENTROID) < 0.01); 0255 0256 // With the centroid algorithm, 80 stars with MEAN HFR 1.495 0257 fd->findStars(ALGORITHM_CENTROID).waitForFinished(); 0258 QCOMPARE(fd->getDetectedStars(), NSTARS_CENTROID); 0259 QCOMPARE(fd->getStarCenters().count(), NSTARS_CENTROID); 0260 QVERIFY(abs(fd->getHFR() - HFR_CENTROID) < 0.01); 0261 0262 // With the gradient algorithm, one single star found with HFR 1.801 0263 fd->findStars(ALGORITHM_GRADIENT).waitForFinished(); 0264 QCOMPARE(fd->getDetectedStars(), 1); 0265 QCOMPARE(fd->getStarCenters().count(), 1); 0266 QVERIFY(abs(fd->getHFR() - HFR_GRADIENT) < 0.01); 0267 0268 // The threshold algorithm depends on a global option - skip until we know how to fiddle with that 0269 //QCOMPARE(fd->findStars(ALGORITHM_THRESHOLD), -1); 0270 //QCOMPARE(fd->getDetectedStars(), 0); 0271 //QCOMPARE(fd->getStarCenters().count(), 0); 0272 //QCOMPARE(fd->getHFR(), -1.0); 0273 0274 // With the SEP algorithm, 100 stars with MEAN HFR 2.08 0275 fd->findStars(ALGORITHM_SEP).waitForFinished(); 0276 QCOMPARE(fd->getDetectedStars(), NSTARS_STELLARSOLVER); 0277 QCOMPARE(fd->getStarCenters().count(), NSTARS_STELLARSOLVER); 0278 QVERIFY(abs(fd->getHFR() - HFR_STELLARSOLVER) < 0.1); 0279 0280 // Test the SEP algorithm with a tracking box, as used by the internal guider and subframe focus. 0281 fd->findStars(ALGORITHM_SEP, TRACKING_BOX).waitForFinished(); 0282 auto centers = fd->getStarCenters(); 0283 QCOMPARE(centers.count(), 1); 0284 // QWARN(QString("Center %1,%2").arg(centers[0]->x).arg(centers[0]->y).toStdString().c_str()); 0285 // QWARN(QString("TB Center %1,%2").arg(TRACKING_BOX.center().x()).arg(TRACKING_BOX.center().y()).toStdString().c_str()); 0286 QVERIFY(abs(centers[0]->x - TRACKING_BOX.center().x()) <= 5); 0287 QVERIFY(abs(centers[0]->y - TRACKING_BOX.center().y()) <= 5); 0288 #endif 0289 } 0290 0291 void TestFitsData::testCentroidAlgorithmBenchmark_data() 0292 { 0293 #if QT_VERSION < 0x050900 0294 QSKIP("Skipping fixture-based test on old QT version."); 0295 #else 0296 initGenericDataFixture(); 0297 #endif 0298 } 0299 0300 void TestFitsData::testCentroidAlgorithmBenchmark() 0301 { 0302 #if QT_VERSION < 0x050900 0303 QSKIP("Skipping fixture-based test on old QT version."); 0304 #else 0305 QFETCH(QString, NAME); 0306 0307 if(!QFile::exists(NAME)) 0308 QSKIP("Skipping load test because of missing fixture"); 0309 0310 std::unique_ptr<FITSData> d(new FITSData()); 0311 QVERIFY(d != nullptr); 0312 0313 QFuture<bool> worker = d->loadFromFile(NAME); 0314 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 10000); 0315 QVERIFY(worker.result()); 0316 0317 QBENCHMARK { d->findStars(ALGORITHM_CENTROID).waitForFinished(); } 0318 #endif 0319 } 0320 0321 void TestFitsData::testGradientAlgorithmBenchmark_data() 0322 { 0323 #if QT_VERSION < 0x050900 0324 QSKIP("Skipping fixture-based test on old QT version."); 0325 #else 0326 initGenericDataFixture(); 0327 #endif 0328 } 0329 0330 void TestFitsData::testGradientAlgorithmBenchmark() 0331 { 0332 #if QT_VERSION < 0x050900 0333 QSKIP("Skipping fixture-based test on old QT version."); 0334 #else 0335 QFETCH(QString, NAME); 0336 0337 if(!QFile::exists(NAME)) 0338 QSKIP("Skipping load test because of missing fixture"); 0339 0340 std::unique_ptr<FITSData> d(new FITSData()); 0341 QVERIFY(d != nullptr); 0342 0343 QFuture<bool> worker = d->loadFromFile(NAME); 0344 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 10000); 0345 QVERIFY(worker.result()); 0346 0347 QBENCHMARK { d->findStars(ALGORITHM_GRADIENT).waitForFinished(); } 0348 #endif 0349 } 0350 0351 void TestFitsData::testThresholdAlgorithmBenchmark_data() 0352 { 0353 #if QT_VERSION < 0x050900 0354 QSKIP("Skipping fixture-based test on old QT version."); 0355 #else 0356 initGenericDataFixture(); 0357 #endif 0358 } 0359 0360 void TestFitsData::testThresholdAlgorithmBenchmark() 0361 { 0362 #if QT_VERSION < 0x050900 0363 QSKIP("Skipping fixture-based test on old QT version."); 0364 #else 0365 QSKIP("Skipping benchmark of Threshold Algorithm, which requires fiddling with a global option"); 0366 0367 QFETCH(QString, NAME); 0368 0369 if(!QFile::exists(NAME)) 0370 QSKIP("Skipping load test because of missing fixture"); 0371 0372 std::unique_ptr<FITSData> d(new FITSData()); 0373 QVERIFY(d != nullptr); 0374 0375 QFuture<bool> worker = d->loadFromFile(NAME); 0376 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 10000); 0377 QVERIFY(worker.result()); 0378 0379 QBENCHMARK { d->findStars(ALGORITHM_THRESHOLD).waitForFinished(); } 0380 #endif 0381 } 0382 0383 void TestFitsData::testSEPAlgorithmBenchmark_data() 0384 { 0385 #if QT_VERSION < 0x050900 0386 QSKIP("Skipping fixture-based test on old QT version."); 0387 #else 0388 initGenericDataFixture(); 0389 #endif 0390 } 0391 0392 void TestFitsData::testSEPAlgorithmBenchmark() 0393 { 0394 #if QT_VERSION < 0x050900 0395 QSKIP("Skipping fixture-based test on old QT version."); 0396 #else 0397 QFETCH(QString, NAME); 0398 0399 if(!QFile::exists(NAME)) 0400 QSKIP("Skipping load test because of missing fixture"); 0401 0402 std::unique_ptr<FITSData> d(new FITSData()); 0403 QVERIFY(d != nullptr); 0404 0405 QFuture<bool> worker = d->loadFromFile(NAME); 0406 QTRY_VERIFY_WITH_TIMEOUT(worker.isFinished(), 10000); 0407 QVERIFY(worker.result()); 0408 0409 QBENCHMARK { d->findStars(ALGORITHM_SEP).waitForFinished(); } 0410 #endif 0411 } 0412 0413 QString SolverLoop::status() const 0414 { 0415 return QString("%1/%2 %3% %4 %5") 0416 .arg(upto()).arg(repetitions).arg(upto() * 100.0 / repetitions, 2, 'f', 0) 0417 .arg(solver.get() && solver->isRunning() ? " running" : "") 0418 .arg(done() ? " Done" : ""); 0419 } 0420 0421 SolverLoop::SolverLoop(const QVector<QString> &files, const QString &dir, bool isDetecting, int numReps) 0422 { 0423 filenames = files; 0424 repetitions = numReps; 0425 directory = dir; 0426 detecting = isDetecting; 0427 0428 // Preload the images. 0429 for (const QString &fname : files) 0430 { 0431 images.push_back(QSharedPointer<FITSData>(new FITSData)); 0432 images.back().get()->loadFromFile(QString("%1/%2").arg(dir, fname)).waitForFinished(); 0433 } 0434 } 0435 0436 void SolverLoop::start() 0437 { 0438 startDetect(numDetects % filenames.size()); 0439 } 0440 0441 bool SolverLoop::done() const 0442 { 0443 return numDetects >= repetitions; 0444 } 0445 0446 int SolverLoop::upto() const 0447 { 0448 return numDetects; 0449 } 0450 0451 void SolverLoop::timeout() 0452 { 0453 qInfo() << QString("timed out on %1 %2 !!!!!!!!!!!!!!!!!!!!!").arg(currentIndex).arg(filenames[currentIndex]); 0454 if (detecting) 0455 watcher.cancel(); 0456 else 0457 solver->abort(); 0458 0459 startDetect(currentIndex); 0460 } 0461 0462 void SolverLoop::solverDone(bool timedOut, bool success, const FITSImage::Solution &solution, 0463 double elapsedSeconds) 0464 { 0465 disconnect(&timer, &QTimer::timeout, this, &SolverLoop::timeout); 0466 timer.stop(); 0467 disconnect(solver.get(), &SolverUtils::done, this, &SolverLoop::solverDone); 0468 0469 const auto &filename = filenames[currentIndex]; 0470 if (timedOut) 0471 qInfo() << QString("#%1: %2 Solver timed out: %3s").arg(numDetects).arg(filename).arg(elapsedSeconds, 0, 'f', 1); 0472 else if (!success) 0473 qInfo() << QString("#%1: %2 Solver failed: %3s").arg(numDetects).arg(filename).arg(elapsedSeconds, 0, 'f', 1); 0474 else 0475 { 0476 const double ra = solution.ra; 0477 const double dec = solution.dec; 0478 const double scale = solution.pixscale; 0479 qInfo() << QString("#%1: %2 Solver returned RA %3 DEC %4 Scale %5: %6s").arg(numDetects).arg(filename) 0480 .arg(ra, 6, 'f', 3).arg(dec, 6, 'f', 3).arg(scale).arg(elapsedSeconds, 4, 'f', 1); 0481 0482 if (numDetects++ < repetitions) 0483 startDetect(numDetects % filenames.size()); 0484 } 0485 } 0486 0487 void SolverLoop::randomTimeout() 0488 { 0489 disconnect(&watcher, &QFutureWatcher<bool>::finished, this, &SolverLoop::detectFinished); 0490 disconnect(&watcher, &QFutureWatcher<bool>::canceled, this, &SolverLoop::detectFinished); 0491 disconnect(&randomAbortTimer, &QTimer::timeout, this, &SolverLoop::randomTimeout); 0492 disconnect(&timer, &QTimer::timeout, this, &SolverLoop::timeout); 0493 timer.stop(); 0494 randomAbortTimer.stop(); 0495 qInfo() << QString("#%1: %2 random timeout was %3s (%4s)").arg(numDetects).arg(filenames[currentIndex]) 0496 .arg(thisRandomTimeout, 3, 'f', 3).arg(dTimer.elapsed() / 1000.0, 3, 'f', 3); 0497 thisImage.reset(); 0498 if (++numDetects < repetitions) 0499 { 0500 startDetect(numDetects % filenames.size()); 0501 } 0502 } 0503 0504 void SolverLoop::detectFinished() 0505 { 0506 disconnect(&timer, &QTimer::timeout, this, &SolverLoop::timeout); 0507 timer.stop(); 0508 randomAbortTimer.stop(); 0509 disconnect(&watcher, &QFutureWatcher<bool>::finished, this, &SolverLoop::detectFinished); 0510 disconnect(&watcher, &QFutureWatcher<bool>::canceled, this, &SolverLoop::detectFinished); 0511 bool result = watcher.result(); 0512 if (result) 0513 { 0514 qInfo() << QString("#%1: %2 HFR %3 (%4s)").arg(numDetects).arg(filenames[currentIndex]) 0515 .arg(thisImage->getHFR(), 4, 'f', 2).arg(dTimer.elapsed() / 1000.0, 3, 'f', 3); 0516 if (++numDetects < repetitions) 0517 { 0518 startDetect(numDetects % filenames.size()); 0519 } 0520 } 0521 else 0522 { 0523 QFAIL("Detect failed"); 0524 } 0525 } 0526 0527 void SolverLoop::startDetect(int index) 0528 { 0529 connect(&timer, &QTimer::timeout, this, &SolverLoop::timeout, Qt::UniqueConnection); 0530 timer.setSingleShot(true); 0531 timer.start(timeoutSecs * 1000); 0532 0533 currentIndex = index; 0534 if (detecting) 0535 { 0536 thisImage.reset(new FITSData(images[currentIndex])); 0537 // detecting stars 0538 connect(&watcher, &QFutureWatcher<bool>::finished, this, &SolverLoop::detectFinished); 0539 connect(&watcher, &QFutureWatcher<bool>::canceled, this, &SolverLoop::detectFinished); 0540 0541 if (randomAbortSecs > 0) 0542 { 0543 randomAbortTimer.setSingleShot(true); 0544 connect(&randomAbortTimer, &QTimer::timeout, this, &SolverLoop::randomTimeout, Qt::UniqueConnection); 0545 thisRandomTimeout = rand.generateDouble() * randomAbortSecs; 0546 randomAbortTimer.start(thisRandomTimeout * 1000); 0547 0548 } 0549 dTimer.start(); 0550 future = thisImage->findStars(ALGORITHM_SEP); 0551 watcher.setFuture(future); 0552 } 0553 else 0554 { 0555 // plate solving 0556 auto profiles = Ekos::getDefaultAlignOptionsProfiles(); 0557 auto parameters = profiles.at(Options::solveOptionsProfile()); 0558 0559 // Double search radius 0560 Options::setSolverType(0); // Internal solver 0561 parameters.search_radius = parameters.search_radius * 2; 0562 solver.reset(new SolverUtils(parameters, 20), &QObject::deleteLater); 0563 connect(solver.get(), &SolverUtils::done, this, &SolverLoop::solverDone, Qt::UniqueConnection); 0564 solver->useScale(false, 0, 0); 0565 solver->usePosition(false, 0, 0); 0566 solver->runSolver(images[currentIndex]); 0567 } 0568 } 0569 0570 // This tests how well we can detect stars and/or plate-solve a number of images 0571 // at the same time. Mostly a memory test--a failure would be a segv. 0572 // I have not provided the fits files as part of the source code, so you need to 0573 // provide them, add them the QVector<QString> variables, and make sure the directory 0574 // below points to the one holding your files. 0575 // 0576 // You may wish to reconfigure the section with SolverLoop at the bottom to have more 0577 // or less parallelism and switch between star detection and plate solves. 0578 // 0579 // You can want to run this as follows: 0580 // export QTEST_FUNCTION_TIMEOUT=1000000000; testfitsdata testParallelSolvers -maxwarnings 1000000 0581 void TestFitsData::testParallelSolvers() 0582 { 0583 #define SKIP_PARALLEL_SOLVERS_TEST 0584 #ifdef SKIP_PARALLEL_SOLVERS_TEST 0585 QSKIP("Skipping testParallelSolvers"); 0586 return; 0587 #else 0588 Options::setAutoDebayer(false); 0589 0590 const QString dir = "/home/hy/Desktop/SharedFolder/DEBUG-solver"; 0591 const QString dir1 = dir; 0592 const QVector<QString> files1 = 0593 { 0594 "guide_frame_00-20-08.fits", 0595 "guide_frame_00-20-12.fits", 0596 "guide_frame_00-20-15.fits", 0597 "guide_frame_00-20-18.fits", 0598 "guide_frame_00-20-21.fits", 0599 "guide_frame_00-20-24.fits", 0600 "guide_frame_00-20-27.fits", 0601 }; 0602 0603 const QString dir2 = dir; 0604 const QVector<QString> files2 = 0605 { 0606 "guide_frame_00-20-30.fits", 0607 "guide_frame_00-20-34.fits", 0608 "guide_frame_00-20-37.fits", 0609 "guide_frame_00-20-40.fits", 0610 "guide_frame_00-20-43.fits", 0611 "guide_frame_00-20-46.fits" 0612 }; 0613 0614 const QString dir3 = dir; 0615 const QVector<QString> files3 = 0616 { 0617 "m5_Light_LPR_120_secs_2022-03-12T04-44-56_201.fits", 0618 "m5_Light_LPR_120_secs_2022-03-12T04-47-02_202.fits", 0619 "m5_Light_LPR_120_secs_2022-03-12T04-49-04_203.fits", 0620 "m5_Light_LPR_120_secs_2022-03-12T04-51-06_204.fits", 0621 "m5_Light_LPR_120_secs_2022-03-12T04-53-07_205.fits" 0622 }; 0623 0624 const QString dir5 = dir; 0625 const QVector<QString> files5 = 0626 { 0627 "m74_Light_LPR_60_secs_2021-10-11T04-48-41_301.fits", 0628 "m74_Light_LPR_60_secs_2021-10-11T04-49-43_302.fits", 0629 "m74_Light_LPR_60_secs_2021-10-11T04-50-55_303.fits", 0630 "m74_Light_LPR_60_secs_2021-10-11T04-51-57_304.fits" 0631 }; 0632 0633 // Set the number of iterations here. THe more the better, e.g. 10000. 0634 constexpr int numIterations = 10000; 0635 0636 // In the below declarations of SolverLoop, 0637 // for the 3rd arg: true means detect stars, false means plate solve them. 0638 0639 // Detect stars in guide files 0640 SolverLoop loop1(files1, dir1, true, numIterations); 0641 loop1.setRandomAbort(1); 0642 0643 // Detect stars in other guide files 0644 SolverLoop loop2(files2, dir2, true, numIterations); 0645 loop2.setRandomAbort(1); 0646 0647 // Detect stars in subs 0648 SolverLoop loop3(files3, dir3, true, numIterations / 15); 0649 loop3.setRandomAbort(3); 0650 0651 // This one solves the fits files 0652 SolverLoop loop4(files1, dir1, false, numIterations / 50); 0653 0654 // This one solves the fits files 0655 SolverLoop loop5(files5, dir5, false, numIterations / 50); 0656 0657 loop1.start(); 0658 loop2.start(); 0659 loop3.start(); 0660 loop4.start(); 0661 loop5.start(); 0662 0663 int iteration = 0; 0664 while(!loop1.done() 0665 || !loop2.done() 0666 || !loop3.done() 0667 || !loop4.done() 0668 || !loop5.done()) 0669 { 0670 // The qWait is needed to allow message passing. 0671 QTest::qWait(10); 0672 if (iteration++ % 400 == 0) 0673 qInfo() << QString("%1 -- %2 -- %3 -- %4 -- %5") 0674 .arg(loop1.status()) 0675 .arg(loop2.status()) 0676 .arg(loop3.status()) 0677 .arg(loop4.status()) 0678 .arg(loop5.status()); 0679 } 0680 0681 qInfo() << QString("%1 -- %2 -- %3 -- %4 -- %5") 0682 .arg(loop1.status()) 0683 .arg(loop2.status()) 0684 .arg(loop3.status()) 0685 .arg(loop4.status()) 0686 .arg(loop5.status()); 0687 0688 qInfo() << QString("Done!"); 0689 #endif 0690 } 0691 0692 QTEST_GUILESS_MAIN(TestFitsData)