summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile29
-rw-r--r--fourier.cpp140
-rw-r--r--fourier.hpp39
-rw-r--r--fourier_integrator.cpp81
-rw-r--r--get_energy.cpp3
-rw-r--r--integrator.cpp1
-rw-r--r--log-fourier.cpp197
-rw-r--r--log-fourier.hpp45
-rw-r--r--log-fourier_integrator.cpp183
-rw-r--r--log_get_energy.cpp85
-rw-r--r--p-spin.cpp25
-rw-r--r--p-spin.hpp6
-rw-r--r--types.hpp6
14 files changed, 579 insertions, 263 deletions
diff --git a/.gitignore b/.gitignore
index 13e1cac..fe5f9c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,10 @@
*.o
correlations
fourier_integrator
+log-fourier_integrator
vgcore.*
walk
get_energy
integrator
fftw.wisdom
+log_get_energy
diff --git a/Makefile b/Makefile
index ad67e7e..6cf8a52 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-all: walk correlations integrator fourier_integrator get_energy log-fourier_integrator
+all: walk correlations integrator fourier_integrator get_energy log-fourier_integrator log_get_energy
CC := clang++ -std=c++17 -flto -Wno-mathematical-notation-identifier-extension -O3 -march=native -mtune=native -fopenmp -DFFTW_THREADS=1
@@ -8,17 +8,26 @@ walk: walk.cpp
correlations: correlations.cpp
$(CC) correlations.cpp -o correlations
-integrator: integrator.cpp fourier.o fourier.hpp
- $(CC) integrator.cpp fourier.o -lfftw3 -lgsl -o integrator
+integrator: integrator.cpp fourier.o p-spin.o fourier.hpp
+ $(CC) integrator.cpp fourier.o p-spin.o -lfftw3 -lgsl -o integrator
-fourier.o: fourier.cpp fourier.hpp
+fourier.o: fourier.cpp fourier.hpp types.hpp p-spin.o
$(CC) fourier.cpp -c -o fourier.o
-fourier_integrator: fourier_integrator.cpp fourier.hpp fourier.o
- $(CC) fourier_integrator.cpp fourier.o -lfftw3 -lgsl -o fourier_integrator
+p-spin.o: p-spin.cpp p-spin.hpp types.hpp
+ $(CC) p-spin.cpp -c -o p-spin.o
-log-fourier_integrator: log-fourier_integrator.cpp fourier.hpp fourier.o
- $(CC) log-fourier_integrator.cpp fourier.o -lfftw3 -lgsl -o log-fourier_integrator
+log-fourier.o: log-fourier.cpp log-fourier.hpp types.hpp
+ $(CC) log-fourier.cpp -c -o log-fourier.o
-get_energy: get_energy.cpp fourier.hpp fourier.o
- $(CC) get_energy.cpp fourier.o -lfftw3 -lgsl -o get_energy
+fourier_integrator: fourier_integrator.cpp fourier.hpp fourier.o p-spin.o
+ $(CC) fourier_integrator.cpp fourier.o p-spin.o -lfftw3 -lgsl -o fourier_integrator
+
+log-fourier_integrator: log-fourier_integrator.cpp log-fourier.hpp log-fourier.o p-spin.o
+ $(CC) log-fourier_integrator.cpp log-fourier.o p-spin.o -lfftw3 -lgsl -o log-fourier_integrator
+
+get_energy: get_energy.cpp fourier.hpp fourier.o p-spin.o
+ $(CC) get_energy.cpp fourier.o p-spin.o -lfftw3 -lgsl -o get_energy
+
+log_get_energy: log_get_energy.cpp log-fourier.hpp log-fourier.o p-spin.o
+ $(CC) log_get_energy.cpp log-fourier.o p-spin.o -lfftw3 -lgsl -o log_get_energy
diff --git a/fourier.cpp b/fourier.cpp
index bb1c92f..3821623 100644
--- a/fourier.cpp
+++ b/fourier.cpp
@@ -1,30 +1,7 @@
#include "fourier.hpp"
+#include "p-spin.hpp"
#include <fftw3.h>
-inline Real fP(unsigned p, Real q) {
- return 0.5 * pow(q, p);
-}
-
-inline Real dfP(unsigned p, Real q) {
- return 0.5 * p * pow(q, p - 1);
-}
-
-inline Real ddfP(unsigned p, Real q) {
- return 0.5 * p * (p - 1) * pow(q, p - 2);
-}
-
-Real f(Real λ, unsigned p, unsigned s, Real q) {
- return (1 - λ) * fP(p, q) + λ * fP(s, q);
-}
-
-Real df(Real λ, unsigned p, unsigned s, Real q) {
- return (1 - λ) * dfP(p, q) + λ * dfP(s, q);
-}
-
-Real ddf(Real λ, unsigned p, unsigned s, Real q) {
- return (1 - λ) * ddfP(p, q) + λ * ddfP(s, q);
-}
-
FourierTransform::FourierTransform(unsigned n, Real Δω, Real Δτ, unsigned flags) : n(n), Δω(Δω), Δτ(Δτ) {
a = fftw_alloc_real(2 * n);
â = reinterpret_cast<Complex*>(fftw_alloc_complex(n + 1));
@@ -100,106 +77,6 @@ void FourierTransform::writeToA(unsigned i, Real ai) {
a[i] = ai;
}
-LogarithmicFourierTransform::LogarithmicFourierTransform(unsigned N, Real k, Real Δτ, unsigned pad) : N(N), pad(pad), k(k), Δτ(Δτ) {
- τₛ = -0.5 * N;
- ωₛ = -0.5 * N;
- sₛ = -0.5 * pad * N;
- a = reinterpret_cast<Complex*>(fftw_alloc_complex(pad*N));
- â = reinterpret_cast<Complex*>(fftw_alloc_complex(pad*N));
- fftw_import_wisdom_from_filename("fftw.wisdom");
- a_to_â = fftw_plan_dft_1d(pad*N, reinterpret_cast<fftw_complex*>(a), reinterpret_cast<fftw_complex*>(â), FFTW_BACKWARD, 0);
- â_to_a = fftw_plan_dft_1d(pad*N, reinterpret_cast<fftw_complex*>(â), reinterpret_cast<fftw_complex*>(a), FFTW_BACKWARD, 0);
- fftw_export_wisdom_to_filename("fftw.wisdom");
-}
-
-LogarithmicFourierTransform::~LogarithmicFourierTransform() {
- fftw_destroy_plan(a_to_â);
- fftw_destroy_plan(â_to_a);
- fftw_free(a);
- fftw_free(â);
- fftw_cleanup();
-}
-
-Real LogarithmicFourierTransform::τ(unsigned n) const {
- return Δτ * (n + τₛ);
-}
-
-Real LogarithmicFourierTransform::ω(unsigned n) const {
- return Δτ * (n + ωₛ);
-}
-
-Real LogarithmicFourierTransform::s(unsigned n) const {
- return (n + sₛ) * 2*M_PI / (pad * N * Δτ);
-}
-
-Real LogarithmicFourierTransform::t(unsigned n) const {
- return exp(τ(n));
-}
-
-Real LogarithmicFourierTransform::ν(unsigned n) const {
- return exp(ω(n));
-}
-
-Complex gamma(Complex z) {
- gsl_sf_result logΓ;
- gsl_sf_result argΓ;
-
- gsl_sf_lngamma_complex_e(z.real(), z.imag(), &logΓ, &argΓ);
-
- return exp(logΓ.val + 1i * argΓ.val);
-}
-
-std::vector<Complex> LogarithmicFourierTransform::fourier(const std::vector<Real>& c, bool symmetric) {
- std::vector<Complex> ĉ(N);
- std::vector<Real> σs = {1};
- if (symmetric){
- σs.push_back(-1);
- }
- for (Real σ : σs) {
- for (unsigned n = 0; n < pad*N; n++) {
- if (n < N) {
- a[n] = c[n] * exp((1 - k) * τ(n));
- } else {
- a[n] = 0;
- }
- }
- fftw_execute(a_to_â);
- for (unsigned n = 0; n < pad*N; n++) {
- â[(pad*N / 2 + n) % (pad*N)] *= pow(1i * σ, 1i * s(n) - k) * gamma(k - 1i * s(n));
- }
- fftw_execute(â_to_a);
- for (unsigned n = 0; n < N; n++) {
- ĉ[n] += exp(-k * ω(n)) * a[(pad - 1)*N+n].real() / (Real)(pad*N);
- }
- }
-
- return ĉ;
-}
-
-std::vector<Real> LogarithmicFourierTransform::inverse(const std::vector<Complex>& ĉ) {
- std::vector<Real> c(N);
- std::vector<Real> σs = {1, -1};
- for (Real σ : σs) {
- for (unsigned n = 0; n < pad * N; n++) {
- if (n < N) {
- a[n] = ĉ[n] * exp((1 - k) * ω(n));
- } else {
- a[n] = 0;
- }
- }
- fftw_execute(a_to_â);
- for (unsigned n = 0; n < pad*N; n++) {
- â[(pad*N / 2 + n) % (pad*N)] *= pow(-1i * σ, 1i * s(n) - k) * gamma(k - 1i * s(n));
- }
- fftw_execute(â_to_a);
- for (unsigned n = 0; n < N; n++) {
- c[n] += exp(-k * τ(n)) * a[(pad - 1)*N+n].real() / (Real)(pad*N) / (2 * M_PI);
- }
- }
-
- return c;
-}
-
std::string fourierFile(std::string prefix, unsigned p, unsigned s, Real λ, Real τ₀, Real y, unsigned log2n, Real τₘₐₓ) {
return prefix + "_" + std::to_string(p) + "_" + std::to_string(s) + "_" + std::to_string(λ) + "_" + std::to_string(τ₀) + "_" + std::to_string(y) + "_" + std::to_string(log2n) + "_" + std::to_string(τₘₐₓ) + ".dat";
}
@@ -207,11 +84,20 @@ std::string fourierFile(std::string prefix, unsigned p, unsigned s, Real λ, Rea
Real energy(const std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ, Real y, Real Δτ) {
Real e = 0;
- for (unsigned i = 0; i < C.size() / 2; i++) {
- e += y * R[i] * df(λ, p, s, C[i]) * M_PI * Δτ;
+ for (unsigned n = 0; n < C.size() / 4 -1; n++) {
+ Real h₂ₙ = M_PI * Δτ;
+ Real h₂ₙ₊₁ = M_PI * Δτ;
+ Real f₂ₙ = R[2*n] * df(λ, p, s, C[2*n]);
+ Real f₂ₙ₊₁ = R[2*n+1] * df(λ, p, s, C[2*n+1]);
+ Real f₂ₙ₊₂ = R[2*n+2] * df(λ, p, s, C[2*n+2]);
+ e += (h₂ₙ + h₂ₙ₊₁) / 6 * (
+ (2 - h₂ₙ₊₁ / h₂ₙ) * f₂ₙ
+ + pow(h₂ₙ + h₂ₙ₊₁, 2) / (h₂ₙ * h₂ₙ₊₁) * f₂ₙ₊₁
+ + (2 - h₂ₙ / h₂ₙ₊₁) * f₂ₙ₊₂
+ );
}
- return e;
+ return y * e;
}
std::tuple<std::vector<Complex>, std::vector<Complex>> RddfCtdfCt(FourierTransform& fft, const std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ) {
diff --git a/fourier.hpp b/fourier.hpp
index 1708667..6be0931 100644
--- a/fourier.hpp
+++ b/fourier.hpp
@@ -1,23 +1,15 @@
#pragma once
+#include "types.hpp"
+
#include <cmath>
#include <fftw3.h>
-#include <complex>
#include <vector>
#include <tuple>
-#include <gsl/gsl_sf_gamma.h>
#ifndef FFTW_THREADS
#define FFTW_THREADS 1
#endif
-using Real = double;
-using Complex = std::complex<Real>;
-using namespace std::complex_literals;
-
-Real f(Real λ, unsigned p, unsigned s, Real q);
-Real df(Real λ, unsigned p, unsigned s, Real q);
-Real ddf(Real λ, unsigned p, unsigned s, Real q);
-
class FourierTransform {
private:
Real* a;
@@ -37,33 +29,6 @@ public:
std::vector<Real> convolve(const std::vector<Real>& Γh, const std::vector<Real>& R);
};
-class LogarithmicFourierTransform {
-private:
- Complex* a;
- Complex* â;
- fftw_plan a_to_â;
- fftw_plan â_to_a;
- unsigned N;
- unsigned pad;
- Real k;
- Real Δτ;
- Real τₛ;
- Real ωₛ;
- Real sₛ;
-public:
- LogarithmicFourierTransform(unsigned N, Real k, Real Δτ, unsigned pad = 4);
- ~LogarithmicFourierTransform();
- Real τ(unsigned n) const;
- Real ω(unsigned n) const;
- Real t(unsigned n) const;
- Real ν(unsigned n) const;
- Real s(unsigned n) const;
- std::vector<Complex> fourier(const std::vector<Real>& c, bool symmetric);
- std::vector<Real> inverse(const std::vector<Complex>& ĉ);
-};
-
-Complex gamma(Complex z);
-
std::string fourierFile(std::string prefix, unsigned p, unsigned s, Real λ, Real τ₀, Real y, unsigned log2n, Real τₘₐₓ);
Real energy(const std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ, Real y, Real Δτ);
std::tuple<std::vector<Complex>, std::vector<Complex>> RddfCtdfCt(FourierTransform& fft, const std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ);
diff --git a/fourier_integrator.cpp b/fourier_integrator.cpp
index 4f4eff5..96fbffd 100644
--- a/fourier_integrator.cpp
+++ b/fourier_integrator.cpp
@@ -8,9 +8,9 @@ int main(int argc, char* argv[]) {
unsigned s = 2;
Real λ = 0.5;
Real τ₀ = 0;
- Real y₀ = 0;
- Real yₘₐₓ = 0.5;
- Real Δy = 0.05;
+ Real β₀ = 0;
+ Real βₘₐₓ = 0.5;
+ Real Δβ = 0.05;
unsigned log2n = 8;
Real τₘₐₓ = 20;
@@ -41,13 +41,13 @@ int main(int argc, char* argv[]) {
τ₀ = atof(optarg);
break;
case '0':
- y₀ = atof(optarg);
+ β₀ = atof(optarg);
break;
case 'y':
- yₘₐₓ = atof(optarg);
+ βₘₐₓ = atof(optarg);
break;
case 'd':
- Δy = atof(optarg);
+ Δβ = atof(optarg);
break;
case 'I':
maxIterations = (unsigned)atof(optarg);
@@ -68,8 +68,11 @@ int main(int argc, char* argv[]) {
Real Δτ = (1 + τ₀ / 2) * τₘₐₓ / M_PI / n;
Real Δω = M_PI / ((1 + τ₀ / 2) * τₘₐₓ);
- Real z = 0.5;
- Real Γ₀ = 1 + τ₀ / 2;
+ Real Γ₀ = 1.0;
+ Real μ = Γ₀;
+ if (τ₀ > 0) {
+ μ = (sqrt(1+4*Γ₀*τ₀)-1)/(2*τ₀);
+ }
std::vector<Real> C(2 * n);
std::vector<Real> R(2 * n);
@@ -78,42 +81,49 @@ int main(int argc, char* argv[]) {
std::vector<Complex> Ct;
std::vector<Complex> Rt;
- Real y = y₀;
+ Real β = β₀;
if (!loadData) {
// start from the exact solution for τ₀ = 0
for (unsigned i = 0; i < n; i++) {
Real τ = i * Δτ * M_PI;
if (τ₀ > 0) {
- C[i] = Γ₀ / 2 * (exp(-z * τ) - z * τ₀ * exp(-τ / τ₀)) / (z - pow(z, 3) * pow(τ₀, 2));
+ C[i] = Γ₀ * (exp(-μ * τ) - μ * τ₀ * exp(-τ / τ₀)) / (μ - pow(μ, 3) * pow(τ₀, 2));
} else {
- C[i] = Γ₀ / 2 * exp(-z * τ) / z;
+ C[i] = Γ₀ * exp(-μ * τ) / μ;
}
if (i > 0) {
C[2 * n - i] = C[i];
}
- R[i] = exp(-z * τ);
+ R[i] = exp(-μ * τ);
}
Ct = fft.fourier(C);
Rt = fft.fourier(R);
} else {
- std::ifstream cfile(fourierFile("C", p, s, λ, τ₀, y, log2n, τₘₐₓ), std::ios::binary);
+ std::ifstream cfile(fourierFile("C", p, s, λ, τ₀, β, log2n, τₘₐₓ), std::ios::binary);
cfile.read((char*)(C.data()), (C.size() / 2) * sizeof(Real));
cfile.close();
for (unsigned i = 1; i < n; i++) {
C[2 * n - i] = C[i];
}
- std::ifstream rfile(fourierFile("R", p, s, λ, τ₀, y, log2n, τₘₐₓ), std::ios::binary);
+ std::ifstream rfile(fourierFile("R", p, s, λ, τ₀, β, log2n, τₘₐₓ), std::ios::binary);
rfile.read((char*)(R.data()), (R.size() / 2) * sizeof(Real));
rfile.close();
Ct = fft.fourier(C);
Rt = fft.fourier(R);
- z = estimateZ(fft, C, Ct, R, Rt, p, s, λ, τ₀, y);
+ μ = estimateZ(fft, C, Ct, R, Rt, p, s, λ, τ₀, β);
}
- while (y += Δy, y <= yₘₐₓ) {
+ std::vector<Real> Cb = C;
+ std::vector<Real> Rb = R;
+ std::vector<Complex> Ctb = Ct;
+ std::vector<Complex> Rtb = Rt;
+ Real μb = μ;
+
+ Real fac = 1;
+ while (β <= βₘₐₓ) {
Real ΔC = 1;
Real ΔCprev = 1000;
unsigned it = 0;
@@ -123,12 +133,12 @@ int main(int argc, char* argv[]) {
for (unsigned i = 0; i < Rt.size(); i++) {
Real ω = i * Δω;
- Rt[i] = (1.0 + pow(y, 2) * RddfCt[i] * Rt[i]) / (z + 1i * ω);
+ Rt[i] = (1.0 + pow(β, 2) * RddfCt[i] * Rt[i]) / (μ + 1i * ω);
}
for (unsigned i = 0; i < Ct.size(); i++) {
Real ω = i * Δω;
- Ct[i] = (Γ₀ * std::conj(Rt[i]) / (1 + pow(τ₀ * ω, 2)) + pow(y, 2) * (RddfCt[i] * Ct[i] + dfCt[i] * std::conj(Rt[i]))) / (z + 1i * ω);
+ Ct[i] = (2 * Γ₀ * std::conj(Rt[i]) / (1 + pow(τ₀ * ω, 2)) + pow(β, 2) * (RddfCt[i] * Ct[i] + dfCt[i] * std::conj(Rt[i]))) / (μ + 1i * ω);
}
std::vector<Real> Cnew = fft.inverse(Ct);
@@ -137,6 +147,8 @@ int main(int argc, char* argv[]) {
Rnew[i] = 0;
}
+ μ *= pow(tanh(C[0]-1)+1, 0.05);
+
ΔC = 0;
for (unsigned i = 0; i < Cnew.size() / 2; i++) {
ΔC += pow(Cnew[i] - C[i], 2);
@@ -151,8 +163,6 @@ int main(int argc, char* argv[]) {
R[i] += γ * (Rnew[i] - R[i]);
}
- z *= Cnew[0];
-
if (it % maxIterations == 0) {
if (ΔC < ΔCprev) {
γ = std::min(1.1 * γ, 1.0);
@@ -163,21 +173,40 @@ int main(int argc, char* argv[]) {
ΔCprev = ΔC;
}
- std::cerr << it << " " << p << " " << s << " " << τ₀ << " " << y << " " << sqrt(2 * ΔC / C.size()) << " " << γ << std::endl;
-
+ std::cerr << "\x1b[2K" << "\r";
+ std::cerr << μ << " " << p << " " << s << " " << τ₀ << " " << β << " " << sqrt(2 * ΔC / C.size()) << " " << γ << " " << C[0];
}
- Real e = energy(C, R, p, s, λ, y, Δτ);
+ if (std::isnan(C[0])) {
+ Δβ /= 2;
+ β -= Δβ;
+ C = Cb;
+ R = Rb;
+ Ct = Ctb;
+ Rt = Rtb;
+ μ = μb;
+ } else {
+
+ std::cerr << "\x1b[2K" << "\r";
- std::cerr << "y " << y << " " << e << " " << z << std::endl;
+ Real e = energy(C, R, p, s, λ, β, Δτ);
- std::ofstream outfile(fourierFile("C", p, s, λ, τ₀, y, log2n, τₘₐₓ), std::ios::out | std::ios::binary);
+ std::cerr << "y " << β << " " << e << " " << μ << std::endl;
+
+ std::ofstream outfile(fourierFile("C", p, s, λ, τ₀, β, log2n, τₘₐₓ), std::ios::out | std::ios::binary);
outfile.write((const char*)(C.data()), (C.size() / 2) * sizeof(Real));
outfile.close();
- std::ofstream outfileR(fourierFile("R", p, s, λ, τ₀, y, log2n, τₘₐₓ), std::ios::out | std::ios::binary);
+ std::ofstream outfileR(fourierFile("R", p, s, λ, τ₀, β, log2n, τₘₐₓ), std::ios::out | std::ios::binary);
outfileR.write((const char*)(R.data()), (R.size() / 2) * sizeof(Real));
outfileR.close();
+ β += Δβ;
+ Cb = C;
+ Rb = R;
+ Rtb = Rt;
+ Ctb = Ct;
+ μb = μ;
+ }
}
return 0;
diff --git a/get_energy.cpp b/get_energy.cpp
index c33c04e..70b8eb8 100644
--- a/get_energy.cpp
+++ b/get_energy.cpp
@@ -2,6 +2,7 @@
#include <getopt.h>
#include <iostream>
#include <fstream>
+#include <iomanip>
int main(int argc, char* argv[]) {
unsigned p = 2;
@@ -60,6 +61,8 @@ int main(int argc, char* argv[]) {
std::vector<Real> C(2 * n);
std::vector<Real> R(2 * n);
+ std::cout << std::setprecision(15);
+
while (y += Δy, y <= yₘₐₓ) {
std::ifstream cfile(fourierFile("C", p, s, λ, τ₀, y, log2n, τₘₐₓ), std::ios::binary);
if (cfile.is_open()) {
diff --git a/integrator.cpp b/integrator.cpp
index 7e5c512..4f8246d 100644
--- a/integrator.cpp
+++ b/integrator.cpp
@@ -1,4 +1,5 @@
#include "fourier.hpp"
+#include "p-spin.hpp"
#include <fstream>
#include <fftw3.h>
#include <getopt.h>
diff --git a/log-fourier.cpp b/log-fourier.cpp
new file mode 100644
index 0000000..47d5c5c
--- /dev/null
+++ b/log-fourier.cpp
@@ -0,0 +1,197 @@
+#include "log-fourier.hpp"
+#include "p-spin.hpp"
+#include <complex>
+#include <fstream>
+
+LogarithmicFourierTransform::LogarithmicFourierTransform(unsigned N, Real k, Real Δτ, unsigned pad) : N(N), pad(pad), k(k), Δτ(Δτ) {
+ τₛ = -0.5 * N;
+ ωₛ = -0.5 * N;
+ sₛ = -0.5 * pad * N;
+ a = reinterpret_cast<Complex*>(fftw_alloc_complex(pad*N));
+ â = reinterpret_cast<Complex*>(fftw_alloc_complex(pad*N));
+ fftw_import_wisdom_from_filename("fftw.wisdom");
+ a_to_â = fftw_plan_dft_1d(pad*N, reinterpret_cast<fftw_complex*>(a), reinterpret_cast<fftw_complex*>(â), FFTW_BACKWARD, 0);
+ â_to_a = fftw_plan_dft_1d(pad*N, reinterpret_cast<fftw_complex*>(â), reinterpret_cast<fftw_complex*>(a), FFTW_BACKWARD, 0);
+ fftw_export_wisdom_to_filename("fftw.wisdom");
+}
+
+LogarithmicFourierTransform::~LogarithmicFourierTransform() {
+ fftw_destroy_plan(a_to_â);
+ fftw_destroy_plan(â_to_a);
+ fftw_free(a);
+ fftw_free(â);
+ fftw_cleanup();
+}
+
+Real LogarithmicFourierTransform::τ(unsigned n) const {
+ return Δτ * (n + τₛ);
+}
+
+Real LogarithmicFourierTransform::ω(unsigned n) const {
+ return Δτ * (n + ωₛ);
+}
+
+Real LogarithmicFourierTransform::s(unsigned n) const {
+ return (n + sₛ) * 2*M_PI / (pad * N * Δτ);
+}
+
+Real LogarithmicFourierTransform::t(unsigned n) const {
+ return exp(τ(n));
+}
+
+Real LogarithmicFourierTransform::ν(unsigned n) const {
+ return exp(ω(n));
+}
+
+Complex Γ(Complex z) {
+ gsl_sf_result logΓ;
+ gsl_sf_result argΓ;
+
+ gsl_sf_lngamma_complex_e(z.real(), z.imag(), &logΓ, &argΓ);
+
+ return exp(logΓ.val + 1i * argΓ.val);
+}
+
+std::vector<Complex> LogarithmicFourierTransform::fourier(const std::vector<Real>& c, bool symmetric) {
+ std::vector<Complex> ĉ(N);
+ std::vector<Real> σs = {1};
+ /* c is either even or zero for negative arguments */
+ if (symmetric){
+ σs.push_back(-1);
+ }
+ for (Real σ : σs) {
+ for (unsigned n = 0; n < pad*N; n++) {
+ if (n < N) {
+ a[n] = c[n] * exp((1 - k) * τ(n));
+ } else {
+ a[n] = 0;
+ }
+ }
+ fftw_execute(a_to_â);
+ for (unsigned n = 0; n < pad*N; n++) {
+ â[(pad*N / 2 + n) % (pad*N)] *= pow(1i * σ, 1i * s(n) - k) * Γ(k - 1i * s(n));
+ }
+ fftw_execute(â_to_a);
+ for (unsigned n = 0; n < N; n++) {
+ ĉ[n] += exp(-k * ω(n)) * a[(pad - 1)*N+n] / (Real)(pad*N);
+ }
+ }
+
+ return ĉ;
+}
+
+std::vector<Real> LogarithmicFourierTransform::inverse(const std::vector<Complex>& ĉ) {
+ std::vector<Real> c(N);
+ std::vector<Real> σs = {1, -1};
+ for (Real σ : σs) {
+ for (unsigned n = 0; n < pad * N; n++) {
+ if (n < N) {
+ if (σ < 0) {
+ a[n] = std::conj(ĉ[n]) * exp((1 - k) * ω(n));
+ } else {
+ a[n] = ĉ[n] * exp((1 - k) * ω(n));
+ }
+ } else {
+ a[n] = 0;
+ }
+ }
+ fftw_execute(a_to_â);
+ for (unsigned n = 0; n < pad*N; n++) {
+ â[(pad*N / 2 + n) % (pad*N)] *= pow(-1i * σ, 1i * s(n) - k) * Γ(k - 1i * s(n));
+ }
+ fftw_execute(â_to_a);
+ for (unsigned n = 0; n < N; n++) {
+ c[n] += exp(-k * τ(n)) * a[(pad - 1)*N+n].real() / (Real)(pad*N) / (2 * M_PI);
+ }
+ }
+
+ return c;
+}
+
+std::string logFourierFile(std::string prefix, unsigned p, unsigned s, Real λ, Real τ₀, Real β, unsigned log2n, Real Δτ, Real k) {
+ return prefix + "_" + std::to_string(p) + "_" + std::to_string(s) + "_" + std::to_string(λ) + "_" + std::to_string(τ₀) + "_" + std::to_string(β) + "_" + std::to_string(log2n) + "_" + std::to_string(Δτ) + "_" + std::to_string(k) + ".dat";
+}
+
+void logFourierSave(const std::vector<Real>& C, const std::vector<Real>& R, const std::vector<Complex>& Ct, const std::vector<Complex>& Rt, unsigned p, unsigned s, Real λ, Real τ₀, Real β, unsigned log2n, Real Δτ, Real k) {
+ unsigned N = pow(2, log2n);
+ std::ofstream outfile(logFourierFile("C", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::out | std::ios::binary);
+ outfile.write((const char*)(C.data()), N * sizeof(Real));
+ outfile.close();
+
+ std::ofstream outfileCt(logFourierFile("Ct", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::out | std::ios::binary);
+ outfileCt.write((const char*)(Ct.data()), N * sizeof(Complex));
+ outfileCt.close();
+
+ std::ofstream outfileR(logFourierFile("R", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::out | std::ios::binary);
+ outfileR.write((const char*)(R.data()), N * sizeof(Real));
+ outfileR.close();
+
+ std::ofstream outfileRt(logFourierFile("Rt", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::out | std::ios::binary);
+ outfileRt.write((const char*)(Rt.data()), N * sizeof(Complex));
+ outfileRt.close();
+}
+
+bool logFourierLoad(std::vector<Real>& C, std::vector<Real>& R, std::vector<Complex>& Ct, std::vector<Complex>& Rt, unsigned p, unsigned s, Real λ, Real τ₀, Real β, unsigned log2n, Real Δτ, Real k) {
+ std::ifstream cfile(logFourierFile("C", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::binary);
+ std::ifstream rfile(logFourierFile("R", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::binary);
+ std::ifstream ctfile(logFourierFile("Ct", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::binary);
+ std::ifstream rtfile(logFourierFile("Rt", p, s, λ, τ₀, β, log2n, Δτ, k), std::ios::binary);
+
+ if ((!cfile.is_open() || !rfile.is_open()) || (!ctfile.is_open() || !rtfile.is_open())) {
+ return false;
+ }
+
+ unsigned N = pow(2, log2n);
+
+ cfile.read((char*)(C.data()), N * sizeof(Real));
+ cfile.close();
+
+ rfile.read((char*)(R.data()), N * sizeof(Real));
+ rfile.close();
+
+ ctfile.read((char*)(Ct.data()), N * sizeof(Complex));
+ ctfile.close();
+
+ rtfile.read((char*)(Rt.data()), N * sizeof(Complex));
+ rtfile.close();
+
+ return true;
+}
+
+std::tuple<std::vector<Complex>, std::vector<Complex>> RddfCtdfCt(LogarithmicFourierTransform& fft, const std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ) {
+ std::vector<Real> dfC(C.size());
+ std::vector<Real> RddfC(C.size());
+ for (unsigned n = 0; n < C.size(); n++) {
+ RddfC[n] = R[n] * ddf(λ, p, s, C[n]);
+ dfC[n] = df(λ, p, s, C[n]);
+ }
+ std::vector<Complex> RddfCt = fft.fourier(RddfC, false);
+ std::vector<Complex> dfCt = fft.fourier(dfC, true);
+
+ return {RddfCt, dfCt};
+}
+
+Real estimateZ(LogarithmicFourierTransform& fft, const std::vector<Real>& C, const std::vector<Complex>& Ct, const std::vector<Real>& R, const std::vector<Complex>& Rt, unsigned p, unsigned s, Real λ, Real τ₀, Real β) {
+ auto [RddfCt, dfCt] = RddfCtdfCt(fft, C, R, p, s, λ);
+ Real Γ₀ = 1.0;
+
+ return ((2 * Γ₀ * std::conj(Rt[0]) + pow(β, 2) * (RddfCt[0] * Ct[0] + dfCt[0] * std::conj(Rt[0]))) / Ct[0]).real();
+}
+
+Real energy(const LogarithmicFourierTransform& fft, std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ, Real β) {
+ Real E = 0;
+ for (unsigned n = 0; n < C.size()/2-1; n++) {
+ Real h₂ₙ = fft.t(2*n+1) - fft.t(2*n);
+ Real h₂ₙ₊₁ = fft.t(2*n+2) - fft.t(2*n+1);
+ Real f₂ₙ = R[2*n] * df(λ, p, s, C[2*n]);
+ Real f₂ₙ₊₁ = R[2*n+1] * df(λ, p, s, C[2*n+1]);
+ Real f₂ₙ₊₂ = R[2*n+2] * df(λ, p, s, C[2*n+2]);
+ E += (h₂ₙ + h₂ₙ₊₁) / 6 * (
+ (2 - h₂ₙ₊₁ / h₂ₙ) * f₂ₙ
+ + pow(h₂ₙ + h₂ₙ₊₁, 2) / (h₂ₙ * h₂ₙ₊₁) * f₂ₙ₊₁
+ + (2 - h₂ₙ / h₂ₙ₊₁) * f₂ₙ₊₂
+ );
+ }
+ return β * E;
+}
+
diff --git a/log-fourier.hpp b/log-fourier.hpp
new file mode 100644
index 0000000..e232bd6
--- /dev/null
+++ b/log-fourier.hpp
@@ -0,0 +1,45 @@
+#pragma once
+#include "types.hpp"
+
+#include <cmath>
+#include <fftw3.h>
+#include <vector>
+#include <tuple>
+#include <gsl/gsl_sf_gamma.h>
+
+class LogarithmicFourierTransform {
+private:
+ Complex* a;
+ Complex* â;
+ fftw_plan a_to_â;
+ fftw_plan â_to_a;
+ unsigned N;
+ unsigned pad;
+ Real k;
+ Real Δτ;
+ Real τₛ;
+ Real ωₛ;
+ Real sₛ;
+public:
+ LogarithmicFourierTransform(unsigned N, Real k, Real Δτ, unsigned pad = 4);
+ ~LogarithmicFourierTransform();
+ Real τ(unsigned n) const;
+ Real ω(unsigned n) const;
+ Real t(unsigned n) const;
+ Real ν(unsigned n) const;
+ Real s(unsigned n) const;
+ std::vector<Complex> fourier(const std::vector<Real>& c, bool symmetric);
+ std::vector<Real> inverse(const std::vector<Complex>& ĉ);
+};
+
+std::string logFourierFile(std::string prefix, unsigned p, unsigned s, Real λ, Real τ₀, Real β, unsigned log2n, Real Δτ, Real k);
+
+void logFourierSave(const std::vector<Real>& C, const std::vector<Real>& R, const std::vector<Complex>& Ct, const std::vector<Complex>& Rt, unsigned p, unsigned s, Real λ, Real τ₀, Real β, unsigned log2n, Real Δτ, Real k);
+
+bool logFourierLoad(std::vector<Real>& C, std::vector<Real>& R, std::vector<Complex>& Ct, std::vector<Complex>& Rt, unsigned p, unsigned s, Real λ, Real τ₀, Real β, unsigned log2n, Real Δτ, Real k);
+
+std::tuple<std::vector<Complex>, std::vector<Complex>> RddfCtdfCt(LogarithmicFourierTransform& fft, const std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ);
+
+Real estimateZ(LogarithmicFourierTransform& fft, const std::vector<Real>& C, const std::vector<Complex>& Ct, const std::vector<Real>& R, const std::vector<Complex>& Rt, unsigned p, unsigned s, Real λ, Real τ₀, Real β);
+
+Real energy(const LogarithmicFourierTransform& fft, std::vector<Real>& C, const std::vector<Real>& R, unsigned p, unsigned s, Real λ, Real β);
diff --git a/log-fourier_integrator.cpp b/log-fourier_integrator.cpp
index 177db46..4cd18ee 100644
--- a/log-fourier_integrator.cpp
+++ b/log-fourier_integrator.cpp
@@ -1,25 +1,31 @@
-#include "fourier.hpp"
+#include "log-fourier.hpp"
#include <getopt.h>
#include <iostream>
int main(int argc, char* argv[]) {
+ /* Model parameters */
unsigned p = 2;
unsigned s = 2;
Real λ = 0.5;
Real τ₀ = 0;
+ /* Log-Fourier parameters */
unsigned log2n = 8;
Real Δτ = 0.1;
Real k = 0.1;
- Real ε = 1e-16;
- Real γ = 1;
+ /* Iteration parameters */
+ Real ε = 1e-14;
+ Real γ₀ = 1;
+ Real β₀ = 0;
Real βₘₐₓ = 0.7;
Real Δβ = 0.01;
+ bool loadData = false;
+ unsigned stepsToRespond = 1000;
int opt;
- while ((opt = getopt(argc, argv, "p:s:2:T:t:b:d:g:k:D:")) != -1) {
+ while ((opt = getopt(argc, argv, "p:s:2:T:t:b:d:g:k:D:e:0:lS:")) != -1) {
switch (opt) {
case 'p':
p = atoi(optarg);
@@ -40,7 +46,7 @@ int main(int argc, char* argv[]) {
Δβ = atof(optarg);
break;
case 'g':
- γ = atof(optarg);
+ γ₀ = atof(optarg);
break;
case 'k':
k = atof(optarg);
@@ -48,6 +54,18 @@ int main(int argc, char* argv[]) {
case 'D':
Δτ = atof(optarg);
break;
+ case 'e':
+ ε = atof(optarg);
+ break;
+ case '0':
+ β₀ = atof(optarg);
+ break;
+ case 'l':
+ loadData = true;
+ break;
+ case 'S':
+ stepsToRespond = atoi(optarg);
+ break;
default:
exit(1);
}
@@ -58,78 +76,117 @@ int main(int argc, char* argv[]) {
LogarithmicFourierTransform fft(N, k, Δτ, 4);
Real Γ₀ = 1.0;
- Real μ = Γ₀;
+ Real μₜ₋₁ = Γ₀;
if (τ₀ > 0) {
- μ = (sqrt(1+4*Γ₀*τ₀)-1)/(2*τ₀);
+ μₜ₋₁ = (sqrt(1+4*Γ₀*τ₀)-1)/(2*τ₀);
}
- std::vector<Real> C(N);
- std::vector<Real> R(N);
- std::vector<Complex> Ct(N);
- std::vector<Complex> Rt(N);
+ std::vector<Real> Cₜ₋₁(N);
+ std::vector<Real> Rₜ₋₁(N);
+ std::vector<Complex> Ĉₜ₋₁(N);
+ std::vector<Complex> Ȓₜ₋₁(N);
- // start from the exact solution for β = 0
- for (unsigned n = 0; n < N; n++) {
- if (τ₀ > 0) {
- C[n] = Γ₀ * (exp(-μ * fft.t(n)) - μ * τ₀ * exp(-fft.t(n) / τ₀)) / (μ - pow(μ, 3) * pow(τ₀, 2));
- } else {
- C[n] = Γ₀ * exp(-μ * fft.t(n)) / μ;
+ if (!loadData) {
+ /* Start from the exact solution for β = 0 */
+ for (unsigned n = 0; n < N; n++) {
+ if (τ₀ > 0) {
+ if (τ₀ == 2) {
+ Cₜ₋₁[n] = Γ₀ * exp(-fft.t(n) / 2) * (1 + fft.t(n) / 2);
+ } else {
+ Cₜ₋₁[n] = Γ₀ * (exp(-μₜ₋₁ * fft.t(n)) - μₜ₋₁ * τ₀ * exp(-fft.t(n) / τ₀)) / (μₜ₋₁ - pow(μₜ₋₁, 3) * pow(τ₀, 2));
+ }
+ } else {
+ Cₜ₋₁[n] = Γ₀ * exp(-μₜ₋₁ * fft.t(n)) / μₜ₋₁;
+ }
+ Rₜ₋₁[n] = exp(-μₜ₋₁ * fft.t(n));
+
+ Ĉₜ₋₁[n] = 2 * Γ₀ / (pow(μₜ₋₁, 2) + pow(fft.ν(n), 2)) / (1 + pow(τ₀ * fft.ν(n), 2));
+ Ȓₜ₋₁[n] = 1.0 / (μₜ₋₁ + 1i * fft.ν(n));
}
- R[n] = exp(-μ * fft.t(n));
-
- Ct[n] = 2 * Γ₀ / (pow(μ, 2) + pow(fft.ν(n), 2)) / (1 + pow(τ₀ * fft.ν(n), 2));
- Rt[n] = 1.0 / (μ + 1i * fft.ν(n));
+ } else {
+ logFourierLoad(Cₜ₋₁, Rₜ₋₁, Ĉₜ₋₁, Ȓₜ₋₁, p, s, λ, τ₀, β₀, log2n, Δτ, k);
+ μₜ₋₁ = estimateZ(fft, Cₜ₋₁, Ĉₜ₋₁, Rₜ₋₁, Ȓₜ₋₁, p, s, λ, τ₀, β₀);
}
- Real β = 0;
+ std::vector<Real> Cₜ = Cₜ₋₁;
+ std::vector<Real> Rₜ = Rₜ₋₁;
+ std::vector<Complex> Ĉₜ = Ĉₜ₋₁;
+ std::vector<Complex> Ȓₜ = Ȓₜ₋₁;
+ Real μₜ = μₜ₋₁;
+
+ Real β = β₀ + Δβ;
while (β < βₘₐₓ) {
- Real ΔC = 100;
- while (ΔC > ε) {
- std::vector<Real> RddfC(N);
- std::vector<Real> dfC(N);
- for (unsigned n = 0; n < N; n++) {
- RddfC[n] = R[n] * ddf(λ, p, s, C[n]);
- dfC[n] = df(λ, p, s, C[n]);
+ Real γ = γ₀;
+ Real ΔCmin = 1000;
+ Real ΔCₜ = 100;
+ unsigned stepsUp = 0;
+ while (ΔCₜ > ε) {
+ auto [RddfCt, dfCt] = RddfCtdfCt(fft, Cₜ, Rₜ, p, s, λ);
+
+ std::vector<Complex> Ĉₜ₊₁(N);
+ std::vector<Complex> Ȓₜ₊₁(N);
+ for (unsigned n = 0; n < N; n++) {
+ Ȓₜ₊₁[n] = (1.0 + pow(β, 2) * RddfCt[n] * Ȓₜ[n]) / (μₜ + 1i * fft.ν(n));
+ Ĉₜ₊₁[n] = (2 * Γ₀ * std::conj(Ȓₜ[n]) / (1 + pow(τ₀ * fft.ν(n), 2)) + pow(β, 2) * (RddfCt[n] * Ĉₜ[n] + dfCt[n] * std::conj(Ȓₜ[n]))) / (μₜ + 1i * fft.ν(n));
+ }
+ std::vector<Real> Rₜ₊₁ = fft.inverse(Ȓₜ₊₁);
+ std::vector<Real> Cₜ₊₁ = fft.inverse(Ĉₜ₊₁);
+
+ μₜ *= pow(tanh(Cₜ₊₁[0]-1)+1, 0.5);
+
+ ΔCₜ = 0;
+ for (unsigned i = 0; i < N; i++) {
+ ΔCₜ += std::norm(Cₜ[i] - Cₜ₊₁[i]);
+ ΔCₜ += std::norm(Rₜ[i] - Rₜ₊₁[i]);
+ }
+ ΔCₜ = sqrt(ΔCₜ) / (2*N);
+
+ if (ΔCₜ < 0.9 * ΔCmin) {
+ ΔCmin = ΔCₜ;
+ stepsUp = 0;
+ } else {
+ stepsUp++;
+ }
+
+ if (stepsUp > stepsToRespond) {
+ γ = std::max(γ/2, 1e-4);
+ stepsUp = 0;
+ ΔCmin = ΔCₜ;
+ }
+
+ for (unsigned i = 0; i < N; i++) {
+ Cₜ[i] += γ * (Cₜ₊₁[i] - Cₜ[i]);
+ Rₜ[i] += γ * (Rₜ₊₁[i] - Rₜ[i]);
+ Ĉₜ[i] += γ * (Ĉₜ₊₁[i] - Ĉₜ[i]);
+ Ȓₜ[i] += γ * (Ȓₜ₊₁[i] - Ȓₜ[i]);
+ }
+
+ std::cerr << "\x1b[2K" << "\r";
+ std::cerr << β << " " << μₜ << " " << ΔCₜ << " " << γ << " " << Cₜ[0];
}
- std::vector<Complex> RddfCt = fft.fourier(RddfC, false);
- std::vector<Complex> dfCt = fft.fourier(dfC, true);
-
- std::vector<Complex> Rtnew(N);
- std::vector<Complex> Ctnew(N);
- for (unsigned n = 0; n < N; n++) {
- Rtnew[n] = (1.0 + pow(β, 2) * RddfCt[n] * Rt[n]) / (μ + 1i * fft.ν(n));
- Ctnew[n] = (2 * Γ₀ * std::conj(Rt[n]) / (1 + pow(τ₀ * fft.ν(n), 2)) + pow(β, 2) * (RddfCt[n] * Ct[n] + dfCt[n] * std::conj(Rt[n]))) / (μ + 1i * fft.ν(n));
- }
+ if (std::isnan(Cₜ[0])) {
+ γ₀ /= 2;
+ Cₜ = Cₜ₋₁;
+ Rₜ = Rₜ₋₁;
+ Ĉₜ = Ĉₜ₋₁;
+ Ȓₜ = Ȓₜ₋₁;
+ μₜ = μₜ₋₁;
+ } else {
+ Real E = energy(fft, Cₜ, Rₜ, p, s, λ, β);
- std::vector<Real> Cnew = fft.inverse(Ctnew);
- std::vector<Real> Rnew = fft.inverse(Rtnew);
+ std::cerr << "\x1b[2K" << "\r";
+ std::cerr << β << " " << μₜ << " " << Ĉₜ[0].real() << " " << E << " " << γ << std::endl;
- ΔC = 0;
- for (unsigned i = 0; i < N; i++) {
- ΔC += std::norm(Ct[i] - Ctnew[i]);
- ΔC += std::norm(Rt[i] - Rtnew[i]);
- }
- ΔC = sqrt(ΔC) / (2*N);
+ logFourierSave(Cₜ, Rₜ, Ĉₜ, Ȓₜ, p, s, λ, τ₀, β, log2n, Δτ, k);
- for (unsigned i = 0; i < N; i++) {
- C[i] += γ * (Cnew[i] - C[i]);
- R[i] += γ * (Rnew[i] - R[i]);
- Ct[i] += γ * (Ctnew[i] - Ct[i]);
- Rt[i] += γ * (Rtnew[i] - Rt[i]);
+ β += Δβ;
+ Cₜ₋₁ = Cₜ;
+ Rₜ₋₁ = Rₜ;
+ Ĉₜ₋₁ = Ĉₜ;
+ Ȓₜ₋₁ = Ȓₜ;
+ μₜ₋₁ = μₜ;
}
-
- μ *= C[0];
-
-// std::cerr << ΔC << std::endl;
- }
-
- std::cerr << β << " " << μ << " " << Ct[0].real() << std::endl;
- β += Δβ;
- }
-
- for (unsigned i = 0; i < N; i++) {
- std::cout << fft.t(i) << " " << Rt[i].imag() << std::endl;
}
return 0;
diff --git a/log_get_energy.cpp b/log_get_energy.cpp
new file mode 100644
index 0000000..ae17f6f
--- /dev/null
+++ b/log_get_energy.cpp
@@ -0,0 +1,85 @@
+#include "log-fourier.hpp"
+#include <getopt.h>
+#include <iomanip>
+#include <iostream>
+#include <iomanip>
+
+int main(int argc, char* argv[]) {
+ /* Model parameters */
+ unsigned p = 2;
+ unsigned s = 2;
+ Real λ = 0.5;
+ Real τ₀ = 0;
+
+ /* Log-Fourier parameters */
+ unsigned log2n = 8;
+ Real Δτ = 0.1;
+ Real k = 0.1;
+
+ /* Iteration parameters */
+ Real β₀ = 0;
+ Real βₘₐₓ = 0.7;
+ Real Δβ = 0.01;
+
+ int opt;
+
+ while ((opt = getopt(argc, argv, "p:s:2:T:t:b:d:k:D:0:")) != -1) {
+ switch (opt) {
+ case 'p':
+ p = atoi(optarg);
+ break;
+ case 's':
+ s = atoi(optarg);
+ break;
+ case '2':
+ log2n = atoi(optarg);
+ break;
+ case 't':
+ τ₀ = atof(optarg);
+ break;
+ case 'b':
+ βₘₐₓ = atof(optarg);
+ break;
+ case 'd':
+ Δβ = atof(optarg);
+ break;
+ case 'k':
+ k = atof(optarg);
+ break;
+ case 'D':
+ Δτ = atof(optarg);
+ break;
+ case '0':
+ β₀ = atof(optarg);
+ break;
+ default:
+ exit(1);
+ }
+ }
+
+ unsigned N = pow(2, log2n);
+
+ LogarithmicFourierTransform fft(N, k, Δτ, 4);
+
+ std::vector<Real> C(N);
+ std::vector<Real> R(N);
+ std::vector<Complex> Ct(N);
+ std::vector<Complex> Rt(N);
+
+ Real β = β₀;
+
+ std::cout << std::setprecision(16);
+
+ while (β += Δβ, β <= βₘₐₓ) {
+ if (logFourierLoad(C, R, Ct, Rt, p, s, λ, τ₀, β, log2n, Δτ, k)) {
+
+ Real e = energy(fft, C, R, p, s, λ, β);
+
+ Real μ = estimateZ(fft, C, Ct, R, Rt, p, s, λ, τ₀, β);
+
+ std::cout << p << " " << s << " " << λ << " " << τ₀ << " " << β << " " << μ << " " << Ct[0].real() << " " << e << " " << Rt[0].real() << std::endl;
+ }
+ }
+
+ return 0;
+}
diff --git a/p-spin.cpp b/p-spin.cpp
new file mode 100644
index 0000000..3691ed6
--- /dev/null
+++ b/p-spin.cpp
@@ -0,0 +1,25 @@
+#include "p-spin.hpp"
+
+inline Real fP(unsigned p, Real q) {
+ return 0.5 * pow(q, p);
+}
+
+inline Real dfP(unsigned p, Real q) {
+ return 0.5 * p * pow(q, p - 1);
+}
+
+inline Real ddfP(unsigned p, Real q) {
+ return 0.5 * p * (p - 1) * pow(q, p - 2);
+}
+
+Real f(Real λ, unsigned p, unsigned s, Real q) {
+ return (1 - λ) * fP(p, q) + λ * fP(s, q);
+}
+
+Real df(Real λ, unsigned p, unsigned s, Real q) {
+ return (1 - λ) * dfP(p, q) + λ * dfP(s, q);
+}
+
+Real ddf(Real λ, unsigned p, unsigned s, Real q) {
+ return (1 - λ) * ddfP(p, q) + λ * ddfP(s, q);
+}
diff --git a/p-spin.hpp b/p-spin.hpp
new file mode 100644
index 0000000..c293d65
--- /dev/null
+++ b/p-spin.hpp
@@ -0,0 +1,6 @@
+#pragma once
+#include "types.hpp"
+
+Real f(Real λ, unsigned p, unsigned s, Real q);
+Real df(Real λ, unsigned p, unsigned s, Real q);
+Real ddf(Real λ, unsigned p, unsigned s, Real q);
diff --git a/types.hpp b/types.hpp
new file mode 100644
index 0000000..05eceb4
--- /dev/null
+++ b/types.hpp
@@ -0,0 +1,6 @@
+#pragma once
+#include <complex>
+
+using Real = double;
+using Complex = std::complex<Real>;
+using namespace std::complex_literals;