diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 29 | ||||
-rw-r--r-- | fourier.cpp | 140 | ||||
-rw-r--r-- | fourier.hpp | 39 | ||||
-rw-r--r-- | fourier_integrator.cpp | 81 | ||||
-rw-r--r-- | get_energy.cpp | 3 | ||||
-rw-r--r-- | integrator.cpp | 1 | ||||
-rw-r--r-- | log-fourier.cpp | 197 | ||||
-rw-r--r-- | log-fourier.hpp | 45 | ||||
-rw-r--r-- | log-fourier_integrator.cpp | 183 | ||||
-rw-r--r-- | log_get_energy.cpp | 85 | ||||
-rw-r--r-- | p-spin.cpp | 25 | ||||
-rw-r--r-- | p-spin.hpp | 6 | ||||
-rw-r--r-- | types.hpp | 6 |
14 files changed, 579 insertions, 263 deletions
@@ -2,8 +2,10 @@ *.o correlations fourier_integrator +log-fourier_integrator vgcore.* walk get_energy integrator fftw.wisdom +log_get_energy @@ -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; |