From db36f1891720d0d2def49258ab78d97b1f14cf64 Mon Sep 17 00:00:00 2001 From: dhanavanthesh Date: Tue, 17 Mar 2026 23:05:27 +0530 Subject: [PATCH 1/2] feat(gui): remove 2 billion ion limit Replace "Ions to run" spinbox from QSpinBox to QDoubleSpinBox. - Lift limit from INT_MAX (2.1B) to 2^53 (9 quadrillion) - Fix setMaxIons(int) to setMaxIons(quint64) with clamping - JSON load routes through clamp (no silent truncation) - Define kMaxExactIons constant, use in both driver and widget Closes TODO: "set limit on ion histories or time to run" (ions half). Time limit is a follow-up --- source/gui/mcdriverobj.cpp | 2 +- source/gui/mcdriverobj.h | 14 +++++++++++--- source/gui/simcontrolwidget.cpp | 20 +++++++++++++------- source/gui/simcontrolwidget.h | 5 +++-- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/source/gui/mcdriverobj.cpp b/source/gui/mcdriverobj.cpp index ff4bda2..c389d82 100644 --- a/source/gui/mcdriverobj.cpp +++ b/source/gui/mcdriverobj.cpp @@ -45,7 +45,7 @@ void McDriverObj::setOptions(const mcconfig &opt, bool initFromFile) { options_ = opt; if (initFromFile) { - max_ions_ = opt.Run.max_no_ions; + setMaxIons(opt.Run.max_no_ions); nThreads_ = opt.Run.threads; seed_ = opt.Run.seed; updInterval_ = opt.Output.storage_interval; diff --git a/source/gui/mcdriverobj.h b/source/gui/mcdriverobj.h index 481e2fe..79f3958 100644 --- a/source/gui/mcdriverobj.h +++ b/source/gui/mcdriverobj.h @@ -1,6 +1,7 @@ #ifndef MCDRIVEROBJ_H #define MCDRIVEROBJ_H +#include #include #include @@ -25,6 +26,10 @@ class McDriverObj : public QObject Q_OBJECT public: + // Largest integer exactly representable as double (53-bit mantissa). + // QDoubleSpinBox uses double internally; larger integers lose precision. + static constexpr quint64 kMaxExactIons = 1ULL << 53; + // helper class for getting real-time info // for the running simulation class running_sim_info @@ -131,7 +136,7 @@ class McDriverObj : public QObject const mccore *getSim() const; // get run parameters - size_t maxIons() const { return max_ions_; } + quint64 maxIons() const { return max_ions_; } int nThreads() const { return nThreads_; } int seed() const { return seed_; } int updInterval() const { return updInterval_; } @@ -139,7 +144,10 @@ class McDriverObj : public QObject public slots: // set run parameters - void setMaxIons(int n) { max_ions_ = n; }; + void setMaxIons(quint64 n) + { + max_ions_ = (n >= 1) ? std::min(n, kMaxExactIons) : 1; + }; void setNThreads(int n) { nThreads_ = n; }; void setSeed(int n) { seed_ = n; } void setUpdInterval(int n) { updInterval_ = n; } @@ -187,7 +195,7 @@ private slots: int io_ret_; std::string io_err_; - size_t max_ions_; + quint64 max_ions_; int nThreads_; int seed_; int updInterval_; diff --git a/source/gui/simcontrolwidget.cpp b/source/gui/simcontrolwidget.cpp index 511802e..db777b1 100644 --- a/source/gui/simcontrolwidget.cpp +++ b/source/gui/simcontrolwidget.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -64,13 +65,17 @@ SimControlWidget::SimControlWidget(MainUI *ui, QWidget *parent) // because they can be overriden every time we run the sim OptionsModel *model = mainui_->optionsModel; QModelIndex driverOptionsIdx = model->index("Run"); - QModelIndex idx = model->index("max_no_ions", 0, driverOptionsIdx); - OptionsItem *item = model->getItem(idx); - sbIons = (QSpinBox *)item->createEditor(this); + // QSpinBox is limited to INT_MAX. Used QDoubleSpinBox with 0 decimals + // to support integer values up to 2^53 exactly + sbIons = new QDoubleSpinBox; + sbIons->setDecimals(0); + sbIons->setRange(1, static_cast(McDriverObj::kMaxExactIons)); + sbIons->setSingleStep(100'000); + sbIons->setValue(static_cast(driver_->maxIons())); simCtrls.push_back(sbIons); - idx = model->index("threads", 0, driverOptionsIdx); - item = model->getItem(idx); + QModelIndex idx = model->index("threads", 0, driverOptionsIdx); + OptionsItem *item = model->getItem(idx); sbNThreads = (QSpinBox *)item->createEditor(this); simCtrls.push_back(sbNThreads); @@ -191,7 +196,8 @@ SimControlWidget::SimControlWidget(MainUI *ui, QWidget *parent) connect(driver_, &McDriverObj::configChanged, this, &SimControlWidget::revert); - connect(sbIons, QOverload::of(&QSpinBox::valueChanged), driver_, &McDriverObj::setMaxIons); + connect(sbIons, QOverload::of(&QDoubleSpinBox::valueChanged), this, + [this](double v) { driver_->setMaxIons(static_cast(v)); }); connect(sbNThreads, QOverload::of(&QSpinBox::valueChanged), driver_, &McDriverObj::setNThreads); connect(sbSeed, QOverload::of(&QSpinBox::valueChanged), driver_, &McDriverObj::setSeed); @@ -333,7 +339,7 @@ void SimControlWidget::onSimulationCreated() void SimControlWidget::revert() { - sbIons->setValue(driver_->maxIons()); + sbIons->setValue(static_cast(driver_->maxIons())); sbNThreads->setValue(driver_->nThreads()); sbSeed->setValue(driver_->seed()); sbUpdInterval->setValue(driver_->updInterval()); diff --git a/source/gui/simcontrolwidget.h b/source/gui/simcontrolwidget.h index 99aa72a..347fb40 100644 --- a/source/gui/simcontrolwidget.h +++ b/source/gui/simcontrolwidget.h @@ -5,6 +5,7 @@ class QLineEdit; class QLabel; +class QDoubleSpinBox; class QSpinBox; class QProgressBar; class QToolButton; @@ -35,11 +36,11 @@ private slots: McDriverObj *driver_; QToolButton *btStart; QToolButton *btReset; - QSpinBox *sbIons; + QDoubleSpinBox *sbIons; QSpinBox *sbNThreads; QSpinBox *sbSeed; QSpinBox *sbUpdInterval; - std::vector simCtrls; + std::vector simCtrls; std::vector simIndicators; QProgressBar *progressBar; QLabel *runIndicator; From 6ebc5e8a53b14846145308c368c6c8371567a0bb Mon Sep 17 00:00:00 2001 From: dhanavanthesh Date: Tue, 17 Mar 2026 23:32:28 +0530 Subject: [PATCH 2/2] feat(gui): add time-based run limit to Run panel - add sbMaxTime spinbox (0 = "no limit", suffix "s", step 60s) - label as "Max CPU time (s)" engine uses CPU time, not wall time - tooltip explains N-thread effect on wall time - wire max_cpu_time_ through all 6 paths in mcdriverobj.cpp - sim stops when either ion count or time limit is reached Closes TODO: "set limit on ion histories or time to un" --- TODO.md | 2 +- source/gui/mcdriverobj.cpp | 12 +++++++++++- source/gui/mcdriverobj.h | 3 +++ source/gui/simcontrolwidget.cpp | 21 +++++++++++++++++++++ source/gui/simcontrolwidget.h | 1 + 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 95c3878..b771ded 100644 --- a/TODO.md +++ b/TODO.md @@ -51,7 +51,7 @@ - [ ] Program icon/logo - [ ] Desktop integration -- [ ] Implement function to set limit on ion histories or time to run +- [X] Implement function to set limit on ion histories or time to run E.g., the "Ions to run" label can become a ToolButton, allowing the user to set the limit either on the # of ions or in time diff --git a/source/gui/mcdriverobj.cpp b/source/gui/mcdriverobj.cpp index c389d82..e5950c0 100644 --- a/source/gui/mcdriverobj.cpp +++ b/source/gui/mcdriverobj.cpp @@ -2,6 +2,7 @@ #include "mcdriver.h" +#include #include #include @@ -21,7 +22,8 @@ McDriverObj::McDriverObj() max_ions_(100), nThreads_(1), seed_(123456789), - updInterval_(1000) + updInterval_(1000), + max_cpu_time_(0) { // internal start signal connection connect(this, &McDriverObj::startSignal, this, &McDriverObj::start_, Qt::QueuedConnection); @@ -49,6 +51,9 @@ void McDriverObj::setOptions(const mcconfig &opt, bool initFromFile) nThreads_ = opt.Run.threads; seed_ = opt.Run.seed; updInterval_ = opt.Output.storage_interval; + setMaxCpuTime(opt.Run.max_cpu_time > static_cast(INT_MAX) + ? INT_MAX + : static_cast(opt.Run.max_cpu_time)); } emit configChanged(); setModified(true); @@ -61,6 +66,7 @@ std::string McDriverObj::json() const opt.Run.seed = seed_; opt.Run.threads = nThreads_; opt.Output.storage_interval = updInterval_; + opt.Run.max_cpu_time = static_cast(max_cpu_time_); return opt.toJSON(); } @@ -143,6 +149,7 @@ bool McDriverObj::validateOptions(QString *msg) const opt.Run.seed = seed_; opt.Run.threads = nThreads_; opt.Output.storage_interval = updInterval_; + opt.Run.max_cpu_time = static_cast(max_cpu_time_); bool isValid = true; @@ -283,6 +290,7 @@ void McDriverObj::saveJson(const QString &fname) opt.Run.seed = seed_; opt.Run.threads = nThreads_; opt.Output.storage_interval = updInterval_; + opt.Run.max_cpu_time = static_cast(max_cpu_time_); } opt.Output.outfilename = fileName().toStdString(); @@ -347,6 +355,7 @@ void McDriverObj::start(bool b) opt.Run.seed = seed_; opt.Run.threads = nThreads_; opt.Output.storage_interval = updInterval_; + opt.Run.max_cpu_time = static_cast(max_cpu_time_); driver_->init(opt); @@ -360,6 +369,7 @@ void McDriverObj::start(bool b) mcconfig::run_options par = driver_->config().Run; par.max_no_ions = max_ions_; par.threads = nThreads_; + par.max_cpu_time = static_cast(max_cpu_time_); driver_->setRunOptions(par); mcconfig::output_options opts = driver_->config().Output; diff --git a/source/gui/mcdriverobj.h b/source/gui/mcdriverobj.h index 79f3958..3a85273 100644 --- a/source/gui/mcdriverobj.h +++ b/source/gui/mcdriverobj.h @@ -140,6 +140,7 @@ class McDriverObj : public QObject int nThreads() const { return nThreads_; } int seed() const { return seed_; } int updInterval() const { return updInterval_; } + int maxCpuTime() const { return max_cpu_time_; } public slots: @@ -151,6 +152,7 @@ public slots: void setNThreads(int n) { nThreads_ = n; }; void setSeed(int n) { seed_ = n; } void setUpdInterval(int n) { updInterval_ = n; } + void setMaxCpuTime(int n) { max_cpu_time_ = std::max(0, n); } private slots: @@ -199,6 +201,7 @@ private slots: int nThreads_; int seed_; int updInterval_; + int max_cpu_time_; // run info running_sim_info info_; diff --git a/source/gui/simcontrolwidget.cpp b/source/gui/simcontrolwidget.cpp index db777b1..bd16bd0 100644 --- a/source/gui/simcontrolwidget.cpp +++ b/source/gui/simcontrolwidget.cpp @@ -5,6 +5,7 @@ #include "optionsmodel.h" #include "simulationoptionsview.h" +#include #include #include #include @@ -90,6 +91,15 @@ SimControlWidget::SimControlWidget(MainUI *ui, QWidget *parent) sbSeed = (QSpinBox *)item->createEditor(this); simCtrls.push_back(sbSeed); + // 0 means no time limit. + sbMaxTime = new QSpinBox; + sbMaxTime->setRange(0, INT_MAX); + sbMaxTime->setSingleStep(60); + sbMaxTime->setSuffix(" s"); + sbMaxTime->setSpecialValueText("no limit"); + sbMaxTime->setValue(driver_->maxCpuTime()); + sbMaxTime->setToolTip("Stop after this many CPU seconds. With N threads, wall time will be ~1/N of this value. 0 means no time limit."); + /* Create Info items */ QStringList ctrlLabels{ "Ions to run", "Threads", "Upd period (ms)", "Seed" }; @@ -163,6 +173,13 @@ SimControlWidget::SimControlWidget(MainUI *ui, QWidget *parent) icol++; } } + { + QHBoxLayout *hbox3 = new QHBoxLayout; + hbox3->addWidget(new QLabel("Max CPU time (s)")); + hbox3->addWidget(sbMaxTime); + hbox3->addStretch(); + vbox->addLayout(hbox3); + } { QHBoxLayout *hbox2 = new QHBoxLayout; hbox2->addWidget(runIndicator); @@ -203,6 +220,8 @@ SimControlWidget::SimControlWidget(MainUI *ui, QWidget *parent) connect(sbSeed, QOverload::of(&QSpinBox::valueChanged), driver_, &McDriverObj::setSeed); connect(sbUpdInterval, QOverload::of(&QSpinBox::valueChanged), driver_, &McDriverObj::setUpdInterval); + connect(sbMaxTime, QOverload::of(&QSpinBox::valueChanged), driver_, + &McDriverObj::setMaxCpuTime); } void SimControlWidget::onStart(bool b) @@ -289,6 +308,7 @@ void SimControlWidget::onDriverStatusChanged() sbNThreads->setEnabled(st != McDriverObj::mcRunning); sbUpdInterval->setEnabled(st != McDriverObj::mcRunning); sbSeed->setEnabled(st == McDriverObj::mcReset); + sbMaxTime->setEnabled(st != McDriverObj::mcRunning); } QString mytimefmt_(double t, bool ceil = false) @@ -343,4 +363,5 @@ void SimControlWidget::revert() sbNThreads->setValue(driver_->nThreads()); sbSeed->setValue(driver_->seed()); sbUpdInterval->setValue(driver_->updInterval()); + sbMaxTime->setValue(driver_->maxCpuTime()); } diff --git a/source/gui/simcontrolwidget.h b/source/gui/simcontrolwidget.h index 347fb40..a0d41ed 100644 --- a/source/gui/simcontrolwidget.h +++ b/source/gui/simcontrolwidget.h @@ -40,6 +40,7 @@ private slots: QSpinBox *sbNThreads; QSpinBox *sbSeed; QSpinBox *sbUpdInterval; + QSpinBox *sbMaxTime; std::vector simCtrls; std::vector simIndicators; QProgressBar *progressBar;