diff --git a/.clang-format b/.clang-format
index 0a9d5a9..c744508 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,6 +1,6 @@
---
Language: Cpp
-Standard: c++23
+Standard: Latest
BasedOnStyle: LLVM
# Indentation
@@ -31,8 +31,7 @@ AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
# Pointers and references
-PointerAlignment: Right
-DereferenceBindsToType: true
+PointerAlignment: Left
ReferenceAlignment: Pointer
# Line breaks
@@ -50,7 +49,7 @@ IncludeCategories:
Priority: 3
# Constructor initialization
-ConstructorInitializerAllOnOneLineIfFitsOnLine: false
+PackConstructorInitializers: CurrentLine
ConstructorInitializerIndentWidth: 4
# Penalty adjustments
diff --git a/.clang-tidy b/.clang-tidy
index e3aec7f..cfcf01e 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -1,5 +1,5 @@
---
-Checks: '-*,readability-*,performance-*,bugprone-*,modernize-*'
+Checks: '-*,readability-*,performance-*,bugprone-*,modernize-*,-modernize-use-trailing-return-type'
HeaderFilterRegex: 'include/(stochfit|levmar)/.*\.h'
WarningsAsErrors: ''
FormatStyle: file
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..b410477
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,416 @@
+
+
+
+
+
+StochFit — Stochastic Reflectivity Fitting
+
+
+
+
+
+
+
+
+
+
+ What is StochFit
+ StochFit fits specular X-ray and neutron reflectivity curves using simulated-annealing-based stochastic optimization, with both model-independent (electron density profile) and model-dependent (box model) fitting. It provides an interactive GUI for building a layer model, running the fit live, and inspecting the resulting reflectivity and density profile.
+
+
+
+ A ground-up modernization
+ The original StochFit (2008–2013) was a Windows-only .NET application. The current codebase is a full rewrite: a native C++20 computation core, a cross-platform Electron/React GUI, and a reproducible CMake + vcpkg build — while preserving the same underlying stochastic fitting algorithms described in the original paper.
+
+
+
Rebuilt computation core
+
Simulated annealing (Greedy / SA / STUN policies), unified Parratt recursion, and electron density profile generation reimplemented in modern, OpenMP-parallel C++20 with optional GPU acceleration hooks.
+
+
+
Cross-platform GUI
+
Electron + React + TypeScript replaces the old WinForms UI, driven by a FlatBuffers-serialized FFI bridge into the native library — runs on Windows, macOS, and Linux.
+
+
+
Standardized build
+
CMake 3.21+ with named presets and vcpkg-managed dependencies (LAPACK, levmar, FlatBuffers) replace hand-maintained Visual Studio project files and vendored DLLs.
+
+
+
Real test coverage
+
GTest-based regression tests for the reflectivity math and fitting harness, plus a standalone console utility (mirefl) for manual spot-checks — the original shipped with none.
+
+
+
+
+
+ Notable fixes since the last public release
+
+ - Fixed a heap buffer overflow when Q critical-edge / high-Q offsets were nonzero during simulated annealing
+ - Fixed reflectivity offset handling so the full data range is displayed and saved regardless of Q offsets
+ - Fixed a null-pointer crash path when initialization failed early in the fitting harness
+ - Worker thread exceptions are now caught and reported instead of silently crashing the process
+ - Fixed session save/resume state (temperature, roughness, absorption) that had been miscomputed in the legacy port
+ - Replaced blocking data polling with a bounded wait, eliminating a GUI freeze when the fitting thread stalled
+ - Fixed a macOS arm64 crash in the LevMar covariance solver caused by an integer-width mismatch in the LAPACK bridge
+ - General clang-tidy / clang-format cleanup and compiler-warning fixes across the C++ core
+
+ Looking for the legacy .NET releases (1.6.5 / 1.7.0)? They're still archived on SourceForge, but are unmaintained — the current, actively developed releases are on GitHub.
+
+
+
+ Architecture
+ Electron GUI (React / TypeScript)
+ ↕ IPC (FlatBuffers)
+Koffi FFI (Node.js ↔ stochfit.dll / .so / .dylib)
+ ↕ C-style exports
+stochfit_core (static library, C++20)
+ ├─ StochFitHarness — top-level orchestrator, worker thread
+ ├─ Anneal<Policy> — Greedy / SimulatedAnnealing / STUN
+ ├─ ParrattReflectivity — recursive reflectivity, OpenMP + Q-smearing
+ ├─ CEDP — electron density profile generation
+ └─ levmardll — Levenberg-Marquardt post-refinement
+
+
+
+ Building from source
+ Builds use CMake 3.21+ with named presets; dependencies are managed by vcpkg and bootstrapped automatically on first configure.
+ # Windows
+cmake --preset windows
+cmake --build --preset windows --target stochfit_shared
+
+# macOS / Linux
+cmake --preset default
+cmake --build --preset default --target stochfit_shared
+
+# GUI (Electron)
+cd gui
+npm install
+npm start # dev mode with hot reload
+npm run make # package a distributable installer
+
+ Full build instructions, presets, and architecture notes are in the README.
+
+
+
+ Citing StochFit
+
+ S. M. Danauskas, D. Li, M. Meron, B. Lin and K. Y. C. Lee
+ Stochastic fitting of specular X-ray reflectivity data using StochFit.
+ J. Appl. Cryst. (2008). 41, 1187–1193.
+
+
+
+
+ Get involved
+ Issues, feature requests, and pull requests are welcome on GitHub — that's now the home for all development, downloads, and bug tracking (this SourceForge page previously pointed to its own forums, which are retired).
+
+
+
+
+
+
+
+
+
diff --git a/include/levmar/BoxLayerBuild.h b/include/levmar/BoxLayerBuild.h
index 52e660e..19b7763 100644
--- a/include/levmar/BoxLayerBuild.h
+++ b/include/levmar/BoxLayerBuild.h
@@ -1,20 +1,22 @@
#pragma once
-#include "Settings.h"
-#include "stochfit/LayerStack.h"
#include
#include
#include
+#include "Settings.h"
+#include "stochfit/LayerStack.h"
+
// Compact representation of a box-model layer stack.
// All rho values are pre-multiplied by 2 to match the m_DEDP convention used
// by ParrattReflectivity (rho[i] = 2 * real_SLD_i in reduced units).
// length_mult[i] = {0, -2*length[i]} — precomputed for the Parratt ak term.
// sigma_sq[i] = -2*sigma[i]^2 — precomputed for the Nevot-Croce factor.
-struct BoxLayers {
- std::vector> rho; // size = boxes + 2
- std::vector> length_mult; // size = boxes + 2
- std::vector sigma_sq; // size = boxes + 1 (per interface)
+struct BoxLayers
+{
+ std::vector> rho; // size = boxes + 2
+ std::vector> length_mult; // size = boxes + 2
+ std::vector sigma_sq; // size = boxes + 1 (per interface)
double normfactor = 1.0;
// Returns a LayerStack view over this object.
@@ -27,7 +29,4 @@ struct BoxLayers {
// one_sigma=true: single global roughness p[0]; stride is 2 per box (length, rho_frac).
// one_sigma=false: per-interface roughness; stride is 3 per box (length, rho_frac, sigma).
// In both cases the last parameter p.back() is the normalization factor.
-void BuildBoxLayers(const BoxReflSettings& rs,
- std::span p,
- bool one_sigma,
- BoxLayers& out);
+void BuildBoxLayers(const BoxReflSettings& rs, std::span p, bool one_sigma, BoxLayers& out);
diff --git a/include/levmar/LevMardll.h b/include/levmar/LevMardll.h
index 44c95f4..1d9ca92 100644
--- a/include/levmar/LevMardll.h
+++ b/include/levmar/LevMardll.h
@@ -24,11 +24,12 @@
// Output: result table — returns bytes written into outBuf.
#pragma once
-#include "platform.h"
#include
-extern "C" EXPORT int FastReflfit (const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
+#include "platform.h"
+
+extern "C" EXPORT int FastReflfit(const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
extern "C" EXPORT int FastReflGenerate(const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
-extern "C" EXPORT int Rhofit (const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
-extern "C" EXPORT int RhoGenerate (const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
+extern "C" EXPORT int Rhofit(const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
+extern "C" EXPORT int RhoGenerate(const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
extern "C" EXPORT int StochFitBoxModel(const uint8_t* inBuf, int inLen, uint8_t* outBuf, int maxLen);
diff --git a/include/levmar/RhoCalc.h b/include/levmar/RhoCalc.h
index 93cd61c..06f6fab 100644
--- a/include/levmar/RhoCalc.h
+++ b/include/levmar/RhoCalc.h
@@ -1,58 +1,58 @@
-/*
+/*
* Copyright (C) 2008 Stephen Danauskas
- *
+ *
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
- *
+ *
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
-#include "Settings.h"
#include
+#include "Settings.h"
+
class RhoCalc
{
-private:
- vector distarray;
- vector rhoarray;
- vector rougharray;
- vector MIRho;
- vector ZIncrement;
-
- vector m_LengthArray;
- vector m_RhoArray;
- vector m_SigmaArray;
-
- bool onesigma;
- double SubSLD;
- double m_dSupSLD;
- int boxnumber;
- int Zlength;
-
-
- void Rhocalculate(double SubRough,double Zoffset);
-
-public:
- //Member functions
- ~RhoCalc();
+ private:
+ vector distarray;
+ vector rhoarray;
+ vector rougharray;
+ vector MIRho;
+ vector ZIncrement;
+
+ vector m_LengthArray;
+ vector m_RhoArray;
+ vector m_SigmaArray;
+
+ bool onesigma;
+ double SubSLD;
+ double m_dSupSLD;
+ int boxnumber;
+ int Zlength;
+
+ void Rhocalculate(double SubRough, double Zoffset);
+
+ public:
+ // Member functions
+ ~RhoCalc();
void init(const BoxReflSettings& InitStruct);
- void mkdensityboxmodel(std::span p);
+ void mkdensityboxmodel(std::span p);
void mkdensity(std::span p);
- static void objective(double *p, double *x, int m, int n, void *data);
+ static void objective(double* p, double* x, int m, int n, void* data);
- vector nk;
- vector nkb;
+ vector nk;
+ vector nkb;
};
\ No newline at end of file
diff --git a/include/levmar/Settings.h b/include/levmar/Settings.h
index e7efda6..10066cf 100644
--- a/include/levmar/Settings.h
+++ b/include/levmar/Settings.h
@@ -3,7 +3,7 @@
struct BoxReflSettings
{
- std::string Directory;
+ std::string Directory;
vector Q;
vector Refl;
vector ReflError;
@@ -11,20 +11,20 @@ struct BoxReflSettings
vector UL;
vector LL;
vector ParamPercs;
- int QPoints = 0;
- bool OneSigma = false;
- double SubSLD = 0;
- double SupSLD = 0;
- int Boxes = 0;
+ int QPoints = 0;
+ bool OneSigma = false;
+ double SubSLD = 0;
+ double SupSLD = 0;
+ int Boxes = 0;
double Wavelength = 0;
double QSpread = 0;
- bool ImpNorm = false;
- int FitFunc = 0;
+ bool ImpNorm = false;
+ int FitFunc = 0;
int LowQOffset = 0;
int HighQOffset = 0;
int Iterations = 0;
// EDP Specific Settings
vector MIEDP;
vector ZIncrement;
- int ZLength = 0;
+ int ZLength = 0;
};
diff --git a/include/platform.h b/include/platform.h
index 187e9f2..729285a 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -10,29 +10,30 @@
// are either stubbed out or replaced with C++23 equivalents.
// ── Standard C/C++ includes ────────────────────────────────────────────────
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include
#include
-#include
#include
-#include
-#include
-#include
-#include
#include
-#include
#include
#include
+#include
#include
-#include
-#include
-#include
-#include
#include
-#include
+#include
#include
-#include
+#include
+#include
+#include
#include
+#include
+
#include
// std::jthread is NOT used — replaced with std::thread + std::atomic
@@ -43,7 +44,7 @@
// ── OMP thread limit ────────────────────────────────────────────────────────
#ifndef MAX_OMP_THREADS
-# define MAX_OMP_THREADS 8
+ #define MAX_OMP_THREADS 8
#endif
// ── Debug flags ──────────────────────────────────────────────────────────────
@@ -51,14 +52,16 @@ inline constexpr bool kSingleProcDebug = false;
// ── Export macro ────────────────────────────────────────────────────────────
#if defined(_MSC_VER)
-# define EXPORT __declspec(dllexport)
+ #define EXPORT __declspec(dllexport)
#else
-# define EXPORT __attribute__((visibility("default")))
+ #define EXPORT __attribute__((visibility("default")))
#endif
// ── MessageBox replacement ──────────────────────────────────────────────────
-inline void platform_error(const char* msg) { std::cerr << msg << std::endl; }
+inline void platform_error(const char* msg)
+{
+ std::cerr << msg << std::endl;
+}
// ── Convenience namespaces (matching existing codebase convention) ──────────
using namespace std;
-
diff --git a/include/stochfit/Algorithm.h b/include/stochfit/Algorithm.h
index eec81fc..74fd841 100644
--- a/include/stochfit/Algorithm.h
+++ b/include/stochfit/Algorithm.h
@@ -1,20 +1,26 @@
#pragma once
enum class SaAlgorithm : int {
- Greedy = 0,
+ Greedy = 0,
Simulated = 1,
- Stun = 2,
+ Stun = 2,
};
-inline constexpr SaAlgorithm AlgorithmFromInt(int v) {
+inline constexpr SaAlgorithm AlgorithmFromInt(int v)
+{
switch (v) {
- case 0: return SaAlgorithm::Greedy;
- case 1: return SaAlgorithm::Simulated;
- case 2: return SaAlgorithm::Stun;
- default: return SaAlgorithm::Greedy;
+ case 0:
+ return SaAlgorithm::Greedy;
+ case 1:
+ return SaAlgorithm::Simulated;
+ case 2:
+ return SaAlgorithm::Stun;
+ default:
+ return SaAlgorithm::Greedy;
}
}
-inline constexpr int AlgorithmToInt(SaAlgorithm a) {
+inline constexpr int AlgorithmToInt(SaAlgorithm a)
+{
return static_cast(a);
}
diff --git a/include/stochfit/Anneal.h b/include/stochfit/Anneal.h
index 46fe8a4..3a66390 100644
--- a/include/stochfit/Anneal.h
+++ b/include/stochfit/Anneal.h
@@ -1,37 +1,39 @@
#pragma once
+#include
+#include
+#include
+#include
+
#include "AnnealPolicies.h"
#include "CEDP.h"
#include "ParameterStepper.h"
#include "ReflectivityObjective.h"
#include "UnifiedReflectivity.h"
-#include
-#include
-#include
-#include
-
-struct AnnealDeps {
+struct AnnealDeps
+{
std::span yi, eyi;
- std::span reflBuf;
+ std::span reflBuf;
bool impNorm = false;
};
-template
-class Anneal {
-public:
+template class Anneal
+{
+ public:
template
- Anneal(CEDP& edp,
- ParrattReflectivity& parratt,
- const ReflectivityObjective& objective,
- ParameterStepper& stepper,
- const ParamVector& initParams,
- AnnealDeps deps,
- PolicyArgs&&... policyArgs)
- : m_edp(&edp), m_parratt(&parratt), m_objective(&objective),
- m_stepper(&stepper), m_tempParams(initParams), m_deps(std::move(deps)),
+ Anneal(CEDP& edp, ParrattReflectivity& parratt, const ReflectivityObjective& objective, ParameterStepper& stepper,
+ const ParamVector& initParams, AnnealDeps deps, PolicyArgs&&... policyArgs)
+ : m_edp(&edp),
+ m_parratt(&parratt),
+ m_objective(&objective),
+ m_stepper(&stepper),
+ m_tempParams(initParams),
+ m_deps(std::move(deps)),
m_rng(std::random_device{}()),
- m_policy(std::forward(policyArgs)...) {}
+ m_policy(std::forward(policyArgs)...)
+ {
+ }
void InitEnergy(ParamVector& params);
@@ -44,50 +46,75 @@ class Anneal {
void ComputeSharedRefl();
bool EvaluateAndAccept(ParamVector& params);
- double GetTemperature() const { return m_policy.GetTemperature(); }
- void SetTemperature(double t) { m_policy.SetTemperature(t); }
- double GetRawTemperature() const { return m_policy.GetRawTemperature(); }
- double GetAverageFSTUN() const { return m_policy.GetAverageFSTUN(); }
- void SetAverageFSTUN(double f) { m_policy.SetAverageFSTUN(f); }
- double GetLowestEnergy() const { return m_bestEnergy; }
- double GetCurrentEnergy() const { return m_currentEnergy; }
- double GetLastChiSquare() const { return m_lastChiSquare; }
-
-private:
- CEDP* m_edp;
- ParrattReflectivity* m_parratt;
+ double GetTemperature() const
+ {
+ return m_policy.GetTemperature();
+ }
+ void SetTemperature(double t)
+ {
+ m_policy.SetTemperature(t);
+ }
+ double GetRawTemperature() const
+ {
+ return m_policy.GetRawTemperature();
+ }
+ double GetAverageFSTUN() const
+ {
+ return m_policy.GetAverageFSTUN();
+ }
+ void SetAverageFSTUN(double f)
+ {
+ m_policy.SetAverageFSTUN(f);
+ }
+ double GetLowestEnergy() const
+ {
+ return m_bestEnergy;
+ }
+ double GetCurrentEnergy() const
+ {
+ return m_currentEnergy;
+ }
+ double GetLastChiSquare() const
+ {
+ return m_lastChiSquare;
+ }
+
+ private:
+ CEDP* m_edp;
+ ParrattReflectivity* m_parratt;
const ReflectivityObjective* m_objective;
- ParameterStepper* m_stepper;
- ParamVector m_tempParams;
- AnnealDeps m_deps;
- std::mt19937 m_rng;
- double m_bestEnergy = std::numeric_limits::max();
+ ParameterStepper* m_stepper;
+ ParamVector m_tempParams;
+ AnnealDeps m_deps;
+ std::mt19937 m_rng;
+ double m_bestEnergy = std::numeric_limits::max();
double m_currentEnergy = std::numeric_limits::max();
double m_lastChiSquare = 0.0;
[[no_unique_address]] Policy m_policy;
- void ComputeModel(ParamVector& p) {
+ void ComputeModel(ParamVector& p)
+ {
auto result = m_parratt->CalculateReflectivity(*m_edp);
std::ranges::copy(result, m_deps.reflBuf.begin());
if (m_deps.impNorm) {
- for (auto& v : m_deps.reflBuf) v *= p.GetImpNorm();
+ for (auto& v : m_deps.reflBuf)
+ v *= p.GetImpNorm();
}
}
};
-template
-void Anneal::InitEnergy(ParamVector& params) {
+template void Anneal::InitEnergy(ParamVector& params)
+{
m_edp->GenerateEDP(params);
ComputeModel(params);
- m_bestEnergy = m_currentEnergy =
- m_objective->Evaluate(m_deps.reflBuf, m_deps.yi, m_deps.eyi);
+ m_bestEnergy = m_currentEnergy = m_objective->Evaluate(m_deps.reflBuf, m_deps.yi, m_deps.eyi);
m_lastChiSquare = ComputeChiSquare(m_deps.reflBuf, m_deps.yi, m_deps.eyi);
}
// ── Cooperative methods for persistent OMP parallel regions ──────────────────
-template
-void Anneal::PrepareCandidate(ParamVector& params) {
+template void Anneal::PrepareCandidate(ParamVector& params)
+{
#pragma omp single
{
m_tempParams = params;
@@ -100,20 +127,21 @@ void Anneal::PrepareCandidate(ParamVector& params) {
// implicit barrier: all threads see completed EDP
}
-template
-void Anneal::ComputeSharedRefl() {
+template void Anneal::ComputeSharedRefl()
+{
auto result = m_parratt->CalculateReflectivityCooperative(*m_edp);
#pragma omp single
{
std::ranges::copy(result, m_deps.reflBuf.begin());
if (m_deps.impNorm) {
- for (auto& v : m_deps.reflBuf) v *= m_tempParams.GetImpNorm();
+ for (auto& v : m_deps.reflBuf)
+ v *= m_tempParams.GetImpNorm();
}
}
}
-template
-bool Anneal::EvaluateAndAccept(ParamVector& params) {
+template bool Anneal::EvaluateAndAccept(ParamVector& params)
+{
const double candE = m_objective->Evaluate(m_deps.reflBuf, m_deps.yi, m_deps.eyi);
if (candE < m_bestEnergy) {
@@ -132,4 +160,3 @@ bool Anneal::EvaluateAndAccept(ParamVector& params) {
return false;
}
-
diff --git a/include/stochfit/AnnealPolicies.h b/include/stochfit/AnnealPolicies.h
index d3a99d3..3e68fdd 100644
--- a/include/stochfit/AnnealPolicies.h
+++ b/include/stochfit/AnnealPolicies.h
@@ -6,71 +6,122 @@
// ── Greedy ────────────────────────────────────────────────────────────────────
// Accepts any move that lowers the energy. No temperature schedule.
-struct GreedyPolicy {
- bool Accept(double curE, double candE, double /*bestE*/, std::mt19937& /*rng*/) const {
+struct GreedyPolicy
+{
+ bool Accept(double curE, double candE, double /*bestE*/, std::mt19937& /*rng*/) const
+ {
return candE < curE;
}
- double GetTemperature() const { return 0.0; }
- void SetTemperature(double) {}
- double GetRawTemperature() const { return 0.0; }
- double GetAverageFSTUN() const { return 0.0; }
- void SetAverageFSTUN(double) {}
+ double GetTemperature() const
+ {
+ return 0.0;
+ }
+ void SetTemperature(double)
+ {
+ }
+ double GetRawTemperature() const
+ {
+ return 0.0;
+ }
+ double GetAverageFSTUN() const
+ {
+ return 0.0;
+ }
+ void SetAverageFSTUN(double)
+ {
+ }
};
// ── Simulated Annealing ───────────────────────────────────────────────────────
// Standard Metropolis acceptance with geometric cooling.
// m_dTemp stores β = 1/T. ProbCalc = exp(-β·ΔE)·100.
-struct SimulatedPolicy {
+struct SimulatedPolicy
+{
SimulatedPolicy(double initTemp, double slope, int platIter);
bool Accept(double curE, double candE, double /*bestE*/, std::mt19937& rng);
- double GetTemperature() const { return 1.0 / m_dTemp; }
- void SetTemperature(double t) { m_dTemp = t; } // t is raw β (from session)
- double GetRawTemperature() const { return m_dTemp; } // β, for session save
- double GetAverageFSTUN() const { return 0.0; }
- void SetAverageFSTUN(double) {}
+ double GetTemperature() const
+ {
+ return 1.0 / m_dTemp;
+ }
+ void SetTemperature(double t)
+ {
+ m_dTemp = t;
+ } // t is raw β (from session)
+ double GetRawTemperature() const
+ {
+ return m_dTemp;
+ } // β, for session save
+ double GetAverageFSTUN() const
+ {
+ return 0.0;
+ }
+ void SetAverageFSTUN(double)
+ {
+ }
-private:
+ private:
double m_dTemp;
double m_slope;
- int m_platIter;
- int m_iter = 0;
+ int m_platIter;
+ int m_iter = 0;
- void Schedule();
- double ProbCalc(double deltaE) const { return std::exp(-m_dTemp * deltaE) * 100.0; }
+ void Schedule();
+ double ProbCalc(double deltaE) const
+ {
+ return std::exp(-m_dTemp * deltaE) * 100.0;
+ }
};
// ── STUN (Stochastic Tunneling) ───────────────────────────────────────────────
// Transforms the energy landscape via fSTUN to tunnel through barriers.
// Supports adaptive temperature control via a sliding window average.
// m_dTemp stores β = 1/T, same convention as SimulatedPolicy.
-struct StunPolicy {
- StunPolicy(double initTemp, double slope, int platIter,
- double gamma, int stunFunc, int tempIter, bool adaptive);
+struct StunPolicy
+{
+ StunPolicy(double initTemp, double slope, int platIter, double gamma, int stunFunc, int tempIter, bool adaptive);
bool Accept(double curE, double candE, double bestE, std::mt19937& rng);
- double GetTemperature() const { return 1.0 / m_dTemp; }
- void SetTemperature(double t) { m_dTemp = t; }
- double GetRawTemperature() const { return m_dTemp; }
- double GetAverageFSTUN() const { return m_averageFSTUN; }
- void SetAverageFSTUN(double f) { m_averageFSTUN = f; }
+ double GetTemperature() const
+ {
+ return 1.0 / m_dTemp;
+ }
+ void SetTemperature(double t)
+ {
+ m_dTemp = t;
+ }
+ double GetRawTemperature() const
+ {
+ return m_dTemp;
+ }
+ double GetAverageFSTUN() const
+ {
+ return m_averageFSTUN;
+ }
+ void SetAverageFSTUN(double f)
+ {
+ m_averageFSTUN = f;
+ }
-private:
+ private:
double m_dTemp;
double m_slope;
- int m_platIter;
- int m_iter = 0;
+ int m_platIter;
+ int m_iter = 0;
double m_gamma;
double m_averageFSTUN;
- int m_stunFunc;
- int m_tempIter;
- bool m_adaptive;
+ int m_stunFunc;
+ int m_tempIter;
+ bool m_adaptive;
std::deque m_qWindow;
double fSTUN(double val, double bestE) const;
- void AdjustTemp(double averageSTUN);
- void Schedule();
- double ProbCalc(double deltaE) const { return std::exp(-m_dTemp * deltaE) * 100.0; }
+ void AdjustTemp(double averageSTUN);
+ void Schedule();
+ double ProbCalc(double deltaE) const
+ {
+ return std::exp(-m_dTemp * deltaE) * 100.0;
+ }
};
diff --git a/include/stochfit/CEDP.h b/include/stochfit/CEDP.h
index a72aefd..34006b1 100644
--- a/include/stochfit/CEDP.h
+++ b/include/stochfit/CEDP.h
@@ -9,75 +9,79 @@
#include "LayerStack.h"
#include "ParamVector.h"
-class CEDP {
-private:
- vector m_fDistArray;
- vector m_fRhoArray;
- vector m_fImagRhoArray;
- vector m_fEDSpacingArray;
-
- // Precomputed per-layer length multiplier {0, -2*dz} for BuildLayerStack.
- vector> m_length_mult;
-
- double m_dRho;
- double m_dLambda;
- double m_dDz0;
- double m_dBeta;
- double m_dBeta_Sup;
- double m_dBeta_Sub;
- double m_dWaveConstant;
-
- int m_iLayers;
-
- bool m_bUseSurfAbs;
-
- // Cached flat-region offsets; updated at end of GenerateEDP.
- mutable int m_supOff = 0;
- mutable int m_subOff = 0;
-
- template
- void BuildEDP(ParamVector &g);
- template
- void FillBoxArraysImpl(ParamVector &g);
-
-public:
- CEDP() = default;
- explicit CEDP(const ReflSettings &s) { Init(s); }
-
- void Init(const ReflSettings &InitStruct);
- int GetLayerCount() const { return m_iLayers; }
-
- // Standalone EDP build — includes serial setup, parallel EDP loop, and offset caching.
- void GenerateEDP(ParamVector &g);
-
- // Cooperative path (SA persistent-team use):
- // 1. Call FillBoxArrays(g) inside your omp single block before the parallel section.
- // 2. Call GenerateEDPCooperative(g) — runs only the parallel omp for.
- // 3. Call BuildLayerStackFull() inside the next omp single — computes offsets fresh.
- void FillBoxArrays(ParamVector &g); // serial setup only, no omp pragma
- void GenerateEDPCooperative(ParamVector &g); // omp for only, no serial omp singles
-
- int Get_EDPPointCount() const;
- bool Get_UseABS() const;
- double Get_FilmAbs() const;
- double Get_FilmAbsInput()
- const; // returns m_dBeta / m_dWaveConstant — inverse of Set_FilmAbs
- double Get_Dz() const;
- double Get_LeftOffset() const; // superphase padding = 6 * RoughnessMax
- double Get_WaveConstant() const;
- void Set_FilmAbs(double absorption);
- std::pair GetOffSets() const;
-
- // Returns a zero-copy view of m_DEDP suitable for ParrattReflectivity.
- // Valid only after a GenerateEDP() call. No roughness (σ=0), sup/sub offsets
- // from the most recent GenerateEDP, transparent flag from m_bUseSurfAbs.
- LayerStack BuildLayerStack() const;
-
- // Like BuildLayerStack but computes sup/sub offsets fresh from m_DEDP — use
- // in the cooperative SA path where GenerateEDPCooperative skipped GetOffSets.
- // Const (m_supOff/m_subOff are mutable); call from within an omp single.
- LayerStack BuildLayerStackFull() const;
-
- vector> m_EDP;
- vector> m_DEDP;
+class CEDP
+{
+ private:
+ vector m_fDistArray;
+ vector m_fRhoArray;
+ vector m_fImagRhoArray;
+ vector m_fEDSpacingArray;
+
+ // Precomputed per-layer length multiplier {0, -2*dz} for BuildLayerStack.
+ vector> m_length_mult;
+
+ double m_dRho;
+ double m_dLambda;
+ double m_dDz0;
+ double m_dBeta;
+ double m_dBeta_Sup;
+ double m_dBeta_Sub;
+ double m_dWaveConstant;
+
+ int m_iLayers;
+
+ bool m_bUseSurfAbs;
+
+ // Cached flat-region offsets; updated at end of GenerateEDP.
+ mutable int m_supOff = 0;
+ mutable int m_subOff = 0;
+
+ template void BuildEDP(ParamVector& g);
+ template void FillBoxArraysImpl(ParamVector& g);
+
+ public:
+ CEDP() = default;
+ explicit CEDP(const ReflSettings& s)
+ {
+ Init(s);
+ }
+
+ void Init(const ReflSettings& InitStruct);
+ int GetLayerCount() const
+ {
+ return m_iLayers;
+ }
+
+ // Standalone EDP build — includes serial setup, parallel EDP loop, and offset caching.
+ void GenerateEDP(ParamVector& g);
+
+ // Cooperative path (SA persistent-team use):
+ // 1. Call FillBoxArrays(g) inside your omp single block before the parallel section.
+ // 2. Call GenerateEDPCooperative(g) — runs only the parallel omp for.
+ // 3. Call BuildLayerStackFull() inside the next omp single — computes offsets fresh.
+ void FillBoxArrays(ParamVector& g); // serial setup only, no omp pragma
+ void GenerateEDPCooperative(ParamVector& g); // omp for only, no serial omp singles
+
+ int Get_EDPPointCount() const;
+ bool Get_UseABS() const;
+ double Get_FilmAbs() const;
+ double Get_FilmAbsInput() const; // returns m_dBeta / m_dWaveConstant — inverse of Set_FilmAbs
+ double Get_Dz() const;
+ double Get_LeftOffset() const; // superphase padding = 6 * RoughnessMax
+ double Get_WaveConstant() const;
+ void Set_FilmAbs(double absorption);
+ std::pair GetOffSets() const;
+
+ // Returns a zero-copy view of m_DEDP suitable for ParrattReflectivity.
+ // Valid only after a GenerateEDP() call. No roughness (σ=0), sup/sub offsets
+ // from the most recent GenerateEDP, transparent flag from m_bUseSurfAbs.
+ LayerStack BuildLayerStack() const;
+
+ // Like BuildLayerStack but computes sup/sub offsets fresh from m_DEDP — use
+ // in the cooperative SA path where GenerateEDPCooperative skipped GetOffSets.
+ // Const (m_supOff/m_subOff are mutable); call from within an omp single.
+ LayerStack BuildLayerStackFull() const;
+
+ vector> m_EDP;
+ vector> m_DEDP;
};
diff --git a/include/stochfit/LayerStack.h b/include/stochfit/LayerStack.h
index 6d18f3a..3a77f5f 100644
--- a/include/stochfit/LayerStack.h
+++ b/include/stochfit/LayerStack.h
@@ -13,12 +13,13 @@
// Parratt loop pays only one std::exp() call per interface without extra ops.
// sigma_sq[i] = -2·sigma[i]² — precomputed for the same reason; empty span when
// has_roughness is false (Nevot-Croce term is skipped at compile time).
-struct LayerStack {
+struct LayerStack
+{
std::span> rho; // 2·EDP density per interface
std::span> length_mult; // {0, -2·length[i]}
- std::span sigma_sq; // -2·σ[i]²; empty when !has_roughness
- int sup_offset = 0;
- int sub_offset = 0;
- bool transparent = true; // imag(rho) all zero → real-only fast path eligible
- bool has_roughness = false; // any σ != 0 → Nevot-Croce multiplied into Fresnel rj
+ std::span sigma_sq; // -2·σ[i]²; empty when !has_roughness
+ int sup_offset = 0;
+ int sub_offset = 0;
+ bool transparent = true; // imag(rho) all zero → real-only fast path eligible
+ bool has_roughness = false; // any σ != 0 → Nevot-Croce multiplied into Fresnel rj
};
diff --git a/include/stochfit/ParamVector.h b/include/stochfit/ParamVector.h
index 7de6b8d..c2835e5 100644
--- a/include/stochfit/ParamVector.h
+++ b/include/stochfit/ParamVector.h
@@ -27,64 +27,89 @@
// on all mutations. All public API uses double.
#include
-#include "platform.h"
+
#include "SettingsStruct.h"
+#include "platform.h"
class ParamVector
{
-public:
+ public:
explicit ParamVector(const ReflSettings&);
// EDP grid (supphase, box1..boxN, subphase) — used by CEDP.
- int RealParamsSize() const { return m_boxes + 2; }
- double GetRealParams(int i) const;
- std::span RealParams() const;
+ int RealParamsSize() const
+ {
+ return m_boxes + 2;
+ }
+ double GetRealParams(int i) const;
+ std::span RealParams() const;
// Mutable SA search space (per-box SLDs + optional roughness/surfabs/impnorm).
- int ParamCount() const { return m_paramCount; }
- int BoxCount() const { return m_boxes; }
+ int ParamCount() const
+ {
+ return m_paramCount;
+ }
+ int BoxCount() const
+ {
+ return m_boxes;
+ }
double GetMutatableParameter(int i) const;
- void SetMutatableParameter(int i, double val); // clamps to bounds
+ void SetMutatableParameter(int i, double val); // clamps to bounds
// Named parameter accessors.
double GetRoughness() const;
- void SetRoughness(double rough); // no-op if roughness is fixed
- double GetImpNorm() const;
- void SetImpNorm(double norm); // no-op if impnorm disabled
- double GetSurfAbs() const;
- void SetSurfAbs(double surfabs); // no-op if surfabs disabled
+ void SetRoughness(double rough); // no-op if roughness is fixed
+ double GetImpNorm() const;
+ void SetImpNorm(double norm); // no-op if impnorm disabled
+ double GetSurfAbs() const;
+ void SetSurfAbs(double surfabs); // no-op if surfabs disabled
// Phase-endpoint values (not part of the SA mutable space).
- void SetSubphase(double subval) { m_edpValues[m_boxes + 1] = subval; }
- void SetSupphase(double supval) { m_edpValues[0] = supval; }
+ void SetSubphase(double subval)
+ {
+ m_edpValues[m_boxes + 1] = subval;
+ }
+ void SetSupphase(double supval)
+ {
+ m_edpValues[0] = supval;
+ }
// Bounds.
double GetUpperBounds(int index) const;
double GetLowerBounds(int index) const;
- void UpdateBoundaries();
+ void UpdateBoundaries();
// Feature flags.
- bool IsRoughnessFixed() const { return m_fixRoughness; }
- bool IsImpNormFixed() const { return m_fixImpNorm; }
- bool UsesSurfAbs() const { return m_useSurfAbs; }
+ bool IsRoughnessFixed() const
+ {
+ return m_fixRoughness;
+ }
+ bool IsImpNormFixed() const
+ {
+ return m_fixImpNorm;
+ }
+ bool UsesSurfAbs() const
+ {
+ return m_useSurfAbs;
+ }
-private:
- std::vector m_edpValues; // [supphase, box1..boxN, subphase]
+ private:
+ std::vector m_edpValues; // [supphase, box1..boxN, subphase]
std::vector m_mutableParams;
std::vector m_high;
std::vector m_low;
- int m_boxes = 0;
- int m_paramCount = 0;
- int m_roughnessIdx = -1;
- int m_surfAbsIdx = -1;
- int m_impNormIdx = -1;
- double m_roughness = 0.0; // fixed roughness value (when m_fixRoughness)
+ int m_boxes = 0;
+ int m_paramCount = 0;
+ int m_roughnessIdx = -1;
+ int m_surfAbsIdx = -1;
+ int m_impNormIdx = -1;
+ double m_roughness = 0.0; // fixed roughness value (when m_fixRoughness)
double m_roughnessMax = 8.0;
- bool m_fixRoughness = false;
- bool m_useSurfAbs = false;
- bool m_fixImpNorm = false;
- bool m_xrOnly = false;
+ bool m_fixRoughness = false;
+ bool m_useSurfAbs = false;
+ bool m_fixImpNorm = false;
+ bool m_xrOnly = false;
void SetBounds(double lowrough, double highrough, double highimp, double highabs);
};
diff --git a/include/stochfit/ParameterStepper.h b/include/stochfit/ParameterStepper.h
index 2412615..b3b14e1 100644
--- a/include/stochfit/ParameterStepper.h
+++ b/include/stochfit/ParameterStepper.h
@@ -1,21 +1,24 @@
#pragma once
-#include "ParamVector.h"
#include
-class ParameterStepper {
-public:
- struct Config {
- int sigmaSearch;
- int absSearch;
- int normSearch;
+#include "ParamVector.h"
+
+class ParameterStepper
+{
+ public:
+ struct Config
+ {
+ int sigmaSearch;
+ int absSearch;
+ int normSearch;
double stepSize;
};
explicit ParameterStepper(Config cfg);
void Step(ParamVector& params);
-private:
- Config m_cfg;
+ private:
+ Config m_cfg;
std::mt19937 m_rng;
};
diff --git a/include/stochfit/QSmear.h b/include/stochfit/QSmear.h
index fd6e600..97c292f 100644
--- a/include/stochfit/QSmear.h
+++ b/include/stochfit/QSmear.h
@@ -1,46 +1,43 @@
#pragma once
-#include "platform.h"
#include
#include
+#include "platform.h"
+
namespace QSmear {
-inline constexpr int Points = 13;
+inline constexpr int Points = 13;
inline constexpr double WeightsSum = 6.211;
// Fills qspreadsinthetai[Points*i .. Points*i+12] and qspreadsinsquaredthetai
// for each data point. sinthetai must already be filled (size: datapoints).
// Pass a non-empty qerror span for per-point Q errors; empty span uses a
// constant fractional spread (qspread). Center point is at index 6.
-inline void BuildArrays(
- double lambda, double qspread,
- std::span sinthetai,
- std::span qerror,
- std::span qspreadsinthetai,
- std::span qspreadsinsquaredthetai)
+inline void BuildArrays(double lambda, double qspread, std::span sinthetai, std::span qerror,
+ std::span qspreadsinthetai, std::span qspreadsinsquaredthetai)
{
- for (int i = 0; i < (int)sinthetai.size(); i++) {
- const double s = sinthetai[i];
+ for (int i = 0; i < (int) sinthetai.size(); i++) {
+ const double s = sinthetai[i];
const double ds = qerror.empty() ? s * qspread : (lambda / (4.0 * std::numbers::pi)) * qerror[i];
- qspreadsinthetai[13*i] = s - 1.2*ds;
- qspreadsinthetai[13*i+1] = s - 1.0*ds;
- qspreadsinthetai[13*i+2] = s - 0.8*ds;
- qspreadsinthetai[13*i+3] = s - 0.6*ds;
- qspreadsinthetai[13*i+4] = s - 0.4*ds;
- qspreadsinthetai[13*i+5] = s - 0.2*ds;
- qspreadsinthetai[13*i+6] = s;
- qspreadsinthetai[13*i+7] = s + 0.2*ds;
- qspreadsinthetai[13*i+8] = s + 0.4*ds;
- qspreadsinthetai[13*i+9] = s + 0.6*ds;
- qspreadsinthetai[13*i+10] = s + 0.8*ds;
- qspreadsinthetai[13*i+11] = s + 1.0*ds;
- qspreadsinthetai[13*i+12] = s + 1.2*ds;
- if (qspreadsinthetai[13*i] < 0.0)
+ qspreadsinthetai[13 * i] = s - 1.2 * ds;
+ qspreadsinthetai[13 * i + 1] = s - 1.0 * ds;
+ qspreadsinthetai[13 * i + 2] = s - 0.8 * ds;
+ qspreadsinthetai[13 * i + 3] = s - 0.6 * ds;
+ qspreadsinthetai[13 * i + 4] = s - 0.4 * ds;
+ qspreadsinthetai[13 * i + 5] = s - 0.2 * ds;
+ qspreadsinthetai[13 * i + 6] = s;
+ qspreadsinthetai[13 * i + 7] = s + 0.2 * ds;
+ qspreadsinthetai[13 * i + 8] = s + 0.4 * ds;
+ qspreadsinthetai[13 * i + 9] = s + 0.6 * ds;
+ qspreadsinthetai[13 * i + 10] = s + 0.8 * ds;
+ qspreadsinthetai[13 * i + 11] = s + 1.0 * ds;
+ qspreadsinthetai[13 * i + 12] = s + 1.2 * ds;
+ if (qspreadsinthetai[13 * i] < 0.0)
platform_error("Error in QSpread please contact the author - the program will now crash :(");
}
- for (int l = 0; l < 13 * (int)sinthetai.size(); l++)
+ for (int l = 0; l < 13 * (int) sinthetai.size(); l++)
qspreadsinsquaredthetai[l] = qspreadsinthetai[l] * qspreadsinthetai[l];
}
@@ -49,22 +46,22 @@ inline void BuildArrays(
// refl: size datapoints (output)
inline void Apply(std::span qspreadreflpt, std::span refl)
{
- for (int i = 0; i < (int)refl.size(); i++) {
- double c = 0.056 * qspreadreflpt[13*i];
- c += 0.135 * qspreadreflpt[13*i+1];
- c += 0.278 * qspreadreflpt[13*i+2];
- c += 0.487 * qspreadreflpt[13*i+3];
- c += 0.726 * qspreadreflpt[13*i+4];
- c += 0.923 * qspreadreflpt[13*i+5];
- c += qspreadreflpt[13*i+6];
- c += 0.923 * qspreadreflpt[13*i+7];
- c += 0.726 * qspreadreflpt[13*i+8];
- c += 0.487 * qspreadreflpt[13*i+9];
- c += 0.278 * qspreadreflpt[13*i+10];
- c += 0.135 * qspreadreflpt[13*i+11];
- c += 0.056 * qspreadreflpt[13*i+12];
+ for (int i = 0; i < (int) refl.size(); i++) {
+ double c = 0.056 * qspreadreflpt[13 * i];
+ c += 0.135 * qspreadreflpt[13 * i + 1];
+ c += 0.278 * qspreadreflpt[13 * i + 2];
+ c += 0.487 * qspreadreflpt[13 * i + 3];
+ c += 0.726 * qspreadreflpt[13 * i + 4];
+ c += 0.923 * qspreadreflpt[13 * i + 5];
+ c += qspreadreflpt[13 * i + 6];
+ c += 0.923 * qspreadreflpt[13 * i + 7];
+ c += 0.726 * qspreadreflpt[13 * i + 8];
+ c += 0.487 * qspreadreflpt[13 * i + 9];
+ c += 0.278 * qspreadreflpt[13 * i + 10];
+ c += 0.135 * qspreadreflpt[13 * i + 11];
+ c += 0.056 * qspreadreflpt[13 * i + 12];
refl[i] = c / WeightsSum;
}
}
-} // namespace QSmear
+} // namespace QSmear
diff --git a/include/stochfit/ReflectivityObjective.h b/include/stochfit/ReflectivityObjective.h
index 312c91d..9b3227a 100644
--- a/include/stochfit/ReflectivityObjective.h
+++ b/include/stochfit/ReflectivityObjective.h
@@ -2,36 +2,31 @@
#include
-class ReflectivityObjective {
-public:
+class ReflectivityObjective
+{
+ public:
enum class Type : int {
- LogDiff = 0,
- InvRatio = 1,
- LogDiffErr = 2,
+ LogDiff = 0,
+ InvRatio = 1,
+ LogDiffErr = 2,
InvRatioErr = 3,
};
- explicit ReflectivityObjective(Type t) : m_type(t) {}
+ explicit ReflectivityObjective(Type t) : m_type(t)
+ {
+ }
// Returns sum(residual[i]²) / (n+1).
- double Evaluate(std::span model,
- std::span yi,
- std::span eyi) const;
+ double Evaluate(std::span model, std::span yi, std::span eyi) const;
// Fills residuals[i] for i in [low_q_offset, n - high_q_offset).
// Indices outside that range are zero-filled (already set by caller or here).
// Non-finite values are clamped to ±1e6.
- void FillResiduals(std::span model,
- std::span yi,
- std::span eyi,
- std::span residuals,
- int low_q_offset = 0,
- int high_q_offset = 0) const;
+ void FillResiduals(std::span model, std::span yi, std::span eyi, std::span residuals,
+ int low_q_offset = 0, int high_q_offset = 0) const;
-private:
+ private:
Type m_type;
};
-double ComputeChiSquare(std::span model,
- std::span yi,
- std::span eyi);
+double ComputeChiSquare(std::span model, std::span yi, std::span eyi);
diff --git a/include/stochfit/SettingsStruct.h b/include/stochfit/SettingsStruct.h
index c962f0d..e096bfe 100644
--- a/include/stochfit/SettingsStruct.h
+++ b/include/stochfit/SettingsStruct.h
@@ -4,61 +4,65 @@
// ReflSettings: passed by const reference into all C++ classes.
// StochRunState: optional resume state passed to StochFit constructor (nullptr = fresh start).
-#include "platform.h"
#include
#include
+#include "platform.h"
+
// Forward declarations for FlatBuffer-based constructors (implemented in SettingsStruct.cpp).
-namespace StochFitProto { struct ReflSettings; struct StochRunState; }
+namespace StochFitProto {
+struct ReflSettings;
+struct StochRunState;
+} // namespace StochFitProto
struct ReflSettings
{
- std::string Directory;
- std::vector Q;
- std::vector Refl;
- std::vector ReflError;
- std::vector QError;
- // Q.size() replaces the old QPoints field
- double SubSLD;
- double FilmSLD;
- double SupSLD;
- int Boxes;
- double FilmAbs;
- double SubAbs;
- double SupAbs;
- double Wavelength;
- bool UseSurfAbs;
- double QErr;
- double Forcesig;
- double RoughnessMax = 8.0; // upper bound for roughness search; determines EDP padding (6× this value)
- bool XRonly;
- int Resolution;
- double FilmLength;
- bool Impnorm;
- int Objectivefunction;
- double Paramtemp;
+ std::string Directory;
+ std::vector Q;
+ std::vector Refl;
+ std::vector ReflError;
+ std::vector QError;
+ // Q.size() replaces the old QPoints field
+ double SubSLD;
+ double FilmSLD;
+ double SupSLD;
+ int Boxes;
+ double FilmAbs;
+ double SubAbs;
+ double SupAbs;
+ double Wavelength;
+ bool UseSurfAbs;
+ double QErr;
+ double Forcesig;
+ double RoughnessMax = 8.0; // upper bound for roughness search; determines EDP padding (6× this value)
+ bool XRonly;
+ int Resolution;
+ double FilmLength;
+ bool Impnorm;
+ int Objectivefunction;
+ double Paramtemp;
- //Annealing parameters
- int Sigmasearch;
- int NormalizationSearchPerc;
- int AbsorptionSearchPerc;
- int Algorithm;
- double Inittemp;
- int Platiter;
- double Slope;
- double Gamma;
- int STUNfunc;
- bool Adaptive;
- int Tempiter;
- int STUNdeciter;
- double Gammadec;
+ // Annealing parameters
+ int Sigmasearch;
+ int NormalizationSearchPerc;
+ int AbsorptionSearchPerc;
+ int Algorithm;
+ double Inittemp;
+ int Platiter;
+ double Slope;
+ double Gamma;
+ int STUNfunc;
+ bool Adaptive;
+ int Tempiter;
+ int STUNdeciter;
+ double Gammadec;
- int CritEdgeOffset;
- int HighQOffset;
- int Iterations; // SA iteration count; also used by LevMar
+ int CritEdgeOffset;
+ int HighQOffset;
+ int Iterations; // SA iteration count; also used by LevMar
- ReflSettings() = default;
- explicit ReflSettings(const StochFitProto::ReflSettings*);
+ ReflSettings() = default;
+ explicit ReflSettings(const StochFitProto::ReflSettings*);
};
// Session state for resuming a previous SA run.
@@ -67,19 +71,20 @@ struct ReflSettings
// filmAbsInput = m_dBeta / m_dWaveConstant (inverse of Set_FilmAbs multiplication).
// temperature = raw m_dTemp (not 1/m_dTemp — passed directly to SetTemp()).
// surfAbs saved independently so it is not baked into filmAbsInput across save/load cycles.
-struct StochRunState {
- double roughness;
- double filmAbsInput; // pre-multiplication value: Set_FilmAbs(filmAbsInput) → m_dBeta = filmAbsInput * WC
- double surfAbs; // params->getSurfAbs() — saved independently
- double temperature; // raw m_dTemp (passed directly to SetTemp())
- double impNorm;
- double avgfSTUN;
- double bestSolution;
- double chiSquare;
- double goodnessOfFit;
- int iteration;
- std::vector edValues; // Boxes+2 doubles: [supphase, box1..boxN, subphase]
+struct StochRunState
+{
+ double roughness;
+ double filmAbsInput; // pre-multiplication value: Set_FilmAbs(filmAbsInput) → m_dBeta = filmAbsInput * WC
+ double surfAbs; // params->getSurfAbs() — saved independently
+ double temperature; // raw m_dTemp (passed directly to SetTemp())
+ double impNorm;
+ double avgfSTUN;
+ double bestSolution;
+ double chiSquare;
+ double goodnessOfFit;
+ int iteration;
+ std::vector edValues; // Boxes+2 doubles: [supphase, box1..boxN, subphase]
- StochRunState() = default;
- explicit StochRunState(const StochFitProto::StochRunState*);
+ StochRunState() = default;
+ explicit StochRunState(const StochFitProto::StochRunState*);
};
diff --git a/include/stochfit/StochFitDll.h b/include/stochfit/StochFitDll.h
index 8ecd303..b45adc4 100644
--- a/include/stochfit/StochFitDll.h
+++ b/include/stochfit/StochFitDll.h
@@ -29,13 +29,14 @@
// GetRunState() → Destroy() Cancel (no save): Init() → Start() → Cancel()
#pragma once
-#include "platform.h"
#include
+#include "platform.h"
+
// SA lifecycle
-extern "C" EXPORT void Init(const uint8_t *buf,
- int len); // StochFitProto::InitRequest
-extern "C" EXPORT const char *GetInitError();
+extern "C" EXPORT void Init(const uint8_t* buf,
+ int len); // StochFitProto::InitRequest
+extern "C" EXPORT const char* GetInitError();
extern "C" EXPORT void Start(int iterations);
extern "C" EXPORT void Stop();
extern "C" EXPORT void Destroy();
@@ -43,8 +44,7 @@ extern "C" EXPORT void Cancel();
// SA polling — returns bytes written into outBuf; outBuf must be pre-allocated
// by caller
-extern "C" EXPORT int GetData(uint8_t *outBuf, int maxLen); // → GetDataResult
-extern "C" EXPORT int
-GetRunState(uint8_t *outBuf,
- int maxLen); // → GetRunStateResult (call after Stop())
-extern "C" EXPORT int SAParams(uint8_t *outBuf, int maxLen); // → SAParamsResult
+extern "C" EXPORT int GetData(uint8_t* outBuf, int maxLen); // → GetDataResult
+extern "C" EXPORT int GetRunState(uint8_t* outBuf,
+ int maxLen); // → GetRunStateResult (call after Stop())
+extern "C" EXPORT int SAParams(uint8_t* outBuf, int maxLen); // → SAParamsResult
diff --git a/include/stochfit/StochFitHarness.h b/include/stochfit/StochFitHarness.h
index a3e1110..5d2dcfb 100644
--- a/include/stochfit/StochFitHarness.h
+++ b/include/stochfit/StochFitHarness.h
@@ -27,6 +27,8 @@
// On stop: call Stop() to block until worker exits, then GetRunState() to read
// the raw internal values, then Destroy() to clean up the object.
+#include
+
#include
#include
#include
@@ -42,92 +44,103 @@
#include "ParameterStepper.h"
#include "ReflectivityObjective.h"
#include "UnifiedReflectivity.h"
-#include
-using AnnealVariant = std::variant,
- Anneal, Anneal>;
-
-struct DataSnapshot {
- std::vector Q;
- std::vector refl;
- std::vector z;
- std::vector rho;
- double roughness = 0.0;
- double chiSquare = 0.0;
- double goodnessOfFit = 0.0;
- bool isFinished = false;
- int iteration = 0;
-};
+using AnnealVariant = std::variant, Anneal, Anneal>;
-class StochFit {
-public:
- StochFit(const ReflSettings &InitStruct,
- const std::unique_ptr &state = {});
- ~StochFit();
- int Start(int iterations);
- int Cancel();
- void Stop();
- DataSnapshot GetData();
- StochRunState GetRunState();
- tl::expected GetInitError() const { return m_initError; }
-
- const ReflSettings& Settings() const { return m_initStruct; }
- int GetDataCount() const { return m_datapoints; }
-
- // GetTemperature() = 1/β (display value, same as old Get_Temp())
- // GetRawTemperature() = β (for session save, same as old Get_RawTemp())
- // SetTemperature(β) = set β directly (session restore)
- double GetTemperature() const;
- double GetRawTemperature() const;
- void SetTemperature(double t);
- double GetLowestEnergy() const;
- double GetAverageFSTUN() const;
- void SetAverageFSTUN(double f);
-
-private:
- DataSnapshot GetCurrentState();
- int Processing();
-
- tl::expected m_initError;
-
- std::thread m_thread;
- std::atomic m_stop_requested;
- std::atomic m_icurrentiteration{0};
-
- string m_Directory;
- int m_itotaliterations = 0;
-
- // m_initStruct must be declared before m_parratt, which holds a const ref to it.
- ReflSettings m_initStruct;
-
- // Measured data sliced by CritEdgeOffset/HighQOffset, owned by StochFit.
- int m_datapoints = 0;
- std::vector m_xi; // Q values
- std::vector m_yi; // reflectivity
- std::vector m_eyi; // reflectivity errors
-
- CEDP m_cEDP; // SA scoring — worker thread only (via annealer)
- CEDP m_displayEDP; // display EDP — main thread only (GetCurrentState)
- ParamVector params; // SA state — worker thread only
-
- // Snapshot of the latest accepted solution, readable from the main thread.
- // Guarded by m_displayMutex; copy only the minimum inside the lock.
- struct DisplayState {
- explicit DisplayState(const ReflSettings &s) : params(s) {}
- ParamVector params;
- std::vector refl; // SA-computed reflectivity at accepted solution
+struct DataSnapshot
+{
+ std::vector Q;
+ std::vector refl;
+ std::vector z;
+ std::vector rho;
+ double roughness = 0.0;
double chiSquare = 0.0;
- double goF = 0.0;
- };
- mutable std::mutex m_displayMutex;
- DisplayState m_displayState;
-
- ParrattReflectivity m_parratt;
- ReflectivityObjective m_objective;
- ParameterStepper m_stepper;
-
- std::optional m_annealer;
+ double goodnessOfFit = 0.0;
+ bool isFinished = false;
+ int iteration = 0;
+};
- // SA scratch buffer (one entry per measured Q point)
- std::vector m_saReflBuf;
+class StochFit
+{
+ public:
+ StochFit(const ReflSettings& InitStruct, const std::unique_ptr& state = {});
+ ~StochFit();
+ int Start(int iterations);
+ int Cancel();
+ void Stop();
+ DataSnapshot GetData();
+ StochRunState GetRunState();
+ tl::expected GetInitError() const
+ {
+ return m_initError;
+ }
+
+ const ReflSettings& Settings() const
+ {
+ return m_initStruct;
+ }
+ int GetDataCount() const
+ {
+ return m_datapoints;
+ }
+
+ // GetTemperature() = 1/β (display value, same as old Get_Temp())
+ // GetRawTemperature() = β (for session save, same as old Get_RawTemp())
+ // SetTemperature(β) = set β directly (session restore)
+ double GetTemperature() const;
+ double GetRawTemperature() const;
+ void SetTemperature(double t);
+ double GetLowestEnergy() const;
+ double GetAverageFSTUN() const;
+ void SetAverageFSTUN(double f);
+
+ private:
+ DataSnapshot GetCurrentState();
+ int Processing();
+
+ tl::expected m_initError;
+
+ std::thread m_thread;
+ std::atomic m_stop_requested;
+ std::atomic m_icurrentiteration{0};
+
+ string m_Directory;
+ int m_itotaliterations = 0;
+
+ // m_initStruct must be declared before m_parratt, which holds a const ref to it.
+ ReflSettings m_initStruct;
+
+ // Measured data sliced by CritEdgeOffset/HighQOffset, owned by StochFit.
+ int m_datapoints = 0;
+ std::vector m_xi; // Q values
+ std::vector m_yi; // reflectivity
+ std::vector m_eyi; // reflectivity errors
+
+ CEDP m_cEDP; // SA scoring — worker thread only (via annealer)
+ CEDP m_displayEDP; // display EDP — main thread only (GetCurrentState)
+ ParamVector params; // SA state — worker thread only
+
+ // Snapshot of the latest accepted solution, readable from the main thread.
+ // Guarded by m_displayMutex; copy only the minimum inside the lock.
+ struct DisplayState
+ {
+ explicit DisplayState(const ReflSettings& s) : params(s)
+ {
+ }
+ ParamVector params;
+ std::vector refl; // SA-computed reflectivity at accepted solution
+ double chiSquare = 0.0;
+ double goF = 0.0;
+ };
+ mutable std::mutex m_displayMutex;
+ DisplayState m_displayState;
+
+ ParrattReflectivity m_parratt;
+ ReflectivityObjective m_objective;
+ ParameterStepper m_stepper;
+
+ std::optional m_annealer;
+
+ // SA scratch buffer (one entry per measured Q point)
+ std::vector m_saReflBuf;
};
diff --git a/include/stochfit/UnifiedReflectivity.h b/include/stochfit/UnifiedReflectivity.h
index e5a1742..fe4ad32 100644
--- a/include/stochfit/UnifiedReflectivity.h
+++ b/include/stochfit/UnifiedReflectivity.h
@@ -4,69 +4,69 @@
#include "LayerStack.h"
#include "QSmear.h"
-struct ReflConstants {
- double k0;
- double sup_sld;
- double indexsup;
- double indexsupsquared;
- bool qsmear_enabled = false;
- std::vector sinthetai, sinsquaredthetai;
+struct ReflConstants
+{
+ double k0;
+ double sup_sld;
+ double indexsup;
+ double indexsupsquared;
+ bool qsmear_enabled = false;
+ std::vector sinthetai, sinsquaredthetai;
- explicit ReflConstants(const ReflSettings &s);
+ explicit ReflConstants(const ReflSettings& s);
};
-template struct WaveScratch {
- std::vector kk, ak, rj, Rj;
- int edp_points = 0;
- int num_threads = 0;
+template struct WaveScratch
+{
+ std::vector kk, ak, rj, Rj;
+ int edp_points = 0;
+ int num_threads = 0;
- void resize(int new_edp_points, int new_num_threads) {
- if (new_edp_points == edp_points && new_num_threads == num_threads)
- return;
- const int n = new_edp_points * new_num_threads;
- kk.resize(n);
- ak.resize(n);
- rj.resize(n);
- Rj.resize(n);
- edp_points = new_edp_points;
- num_threads = new_num_threads;
- }
+ void resize(int new_edp_points, int new_num_threads)
+ {
+ if (new_edp_points == edp_points && new_num_threads == num_threads)
+ return;
+ const int n = new_edp_points * new_num_threads;
+ kk.resize(n);
+ ak.resize(n);
+ rj.resize(n);
+ Rj.resize(n);
+ edp_points = new_edp_points;
+ num_threads = new_num_threads;
+ }
};
-class ParrattReflectivity {
-public:
- explicit ParrattReflectivity(const ReflSettings &settings);
- ParrattReflectivity(const ReflSettings &settings, int n_layers);
+class ParrattReflectivity
+{
+ public:
+ explicit ParrattReflectivity(const ReflSettings& settings);
+ ParrattReflectivity(const ReflSettings& settings, int n_layers);
- // Standalone entry points — creates its own OMP parallel team.
- // Safe to call from any context (no enclosing parallel required).
- auto CalculateReflectivity(const LayerStack &ls) -> std::span;
- auto CalculateReflectivity(const CEDP &EDP) -> std::span;
+ // Standalone entry points — creates its own OMP parallel team.
+ // Safe to call from any context (no enclosing parallel required).
+ auto CalculateReflectivity(const LayerStack& ls) -> std::span;
+ auto CalculateReflectivity(const CEDP& EDP) -> std::span;
- // Cooperative entry point — must be called by ALL threads of an enclosing
- // OMP parallel region. Shares the caller's thread team (no fork/join).
- // BuildLayerStack runs in omp single internally.
- auto CalculateReflectivityCooperative(const CEDP &EDP) -> std::span;
+ // Cooperative entry point — must be called by ALL threads of an enclosing
+ // OMP parallel region. Shares the caller's thread team (no fork/join).
+ // BuildLayerStack runs in omp single internally.
+ auto CalculateReflectivityCooperative(const CEDP& EDP) -> std::span;
-private:
- template
- void ReflectivityCalcCoreImpl(const LayerStack &ls,
- std::span