/*! Type II quasisolitons in Lieb-Liniger: velocity_lifetime
Purpose:
Compute the expected group velocity, and lifetime from time series
and produces the .vgtau file containing this information
for (multi-)type II hole wavepackets in Lieb-Liniger.
This executable requires Abacus version 2.
See README for compilation instructions.
Copyright © Jean-Sébastien Caux, Anahita Sarvi and Cesare Vianello.
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see .
*/
import std;
import abacus;
int main(int argc, char* argv[])
{
using namespace std::complex_literals;
if (argc != 8) {
std::cout << "Executable velocity_lifetime\n"
<< " part of the Type II quasisolitons in Lieb-Liniger software suite\n"
<< " copyright © Jean-Sébastien Caux, Anahita Sarvi and Cesare Vianello.\n";
std::cout << "\nPurpose:\n"
<< " Produce the .vgtau file containing group velocity,\n"
<< " time series coefficients and resulting lifetime estimates\n"
<< " for (multi-)type II hole wavepackets in Lieb-Liniger.\n";
std::cout << "\nPrerequirements:\n----------------\n"
<< " - .states and .rho files produced by executable rho\n"
<< " - .amplitudes file for the required protocol, produced by executable amplitudes_[protocol type]\n";
std::cout << "\nUsage:\n------\n";
std::cout << "velocity_lifetime \n\n";
int warg { 16 }, wtype { 10 }, wcons { 32 };
std::cout << std::left << std::setw(warg) << "Argument" << std::setw(wtype) << "Type"
<< std::setw(wcons) << "Constraints" << "Description\n";
std::cout << std::left << std::setw(warg) << "--------" << std::setw(wtype) << "----"
<< std::setw(wcons) << "-----------" << "-----------\n";
std::cout << std::left << std::setw(warg) << "c" << std::setw(wtype) << "Real"
<< std::setw(wcons) << "> 0"
<< "Value of the interaction parameter\n";
std::cout << std::left << std::setw(warg) << "L" << std::setw(wtype) << "Real"
<< std::setw(wcons) << "> 0"
<< "System size\n";
std::cout << std::left << std::setw(warg) << "N" << std::setw(wtype) << "int"
<< std::setw(wcons) << "> 0"
<< "Number of particles\n";
std::cout << std::left << std::setw(warg) << "nr holes" << std::setw(wtype) << "int"
<< std::setw(wcons) << "1 <= nr holes <= N"
<< "Number of holes (Type II modes)\n";
std::cout << std::left << std::setw(warg) << "width" << std::setw(wtype) << "int"
<< std::setw(wcons) << "nr holes < width <= N"
<< "Width of the hole window\n";
std::cout << std::left << std::setw(warg) << "offset" << std::setw(wtype) << "int"
<< std::setw(wcons) << "0 <= offset <= N-width"
<< "Offset of the hole window w/r to the right Fermi edge\n";
std::cout << std::left << std::setw(warg) << "protocol" << std::setw(wtype) << "string"
<< std::setw(wcons) << "(see amplitudes executables)"
<< "Protocol used for defining the amplitudes in the wavepacket\n";
return 0;
}
std::cout << std::setprecision(std::numeric_limits::digits10 + 1);
Real c_ { std::stold(argv[1]) };
Real L_ { std::stold(argv[2]) };
int N_ { std::stoi(argv[3]) };
int nholes_ { std::stoi(argv[4]) };
int width_ { std::stoi(argv[5]) };
int offset_ { std::stoi(argv[6]) };
std::string protocol_ { argv[7] }; // protocol used to define the amplitudes
int nr_states_;
std::vector label_;
std::vector iK_;
std::vector E_;
std::vector> amplitude;
std::map>> rho_ME_;
std::stringstream filename_base;
filename_base << "c_" << c_ << "_N_" << N_ << "_L_" << L_ << "_nholes_" << nholes_;
filename_base << "_width_" << width_;
filename_base << "_offset_" << offset_;
std::stringstream states_filename;
states_filename << filename_base.str() << ".states";
std::ifstream states_file;
states_file.open(states_filename.str());
states_file >> std::setprecision(std::numeric_limits::digits10 + 1);
std::stringstream amplitudes_filename;
amplitudes_filename << filename_base.str() << "_" << protocol_ << ".amplitudes";
std::ifstream amplitudes_file;
amplitudes_file.open(amplitudes_filename.str());
amplitudes_file >> std::setprecision(std::numeric_limits::digits10 + 1);
std::stringstream rho_ME_filename;
rho_ME_filename << filename_base.str() << ".rho";
std::ifstream rho_ME_file;
rho_ME_file.open(rho_ME_filename.str());
rho_ME_file >> std::setprecision(std::numeric_limits::digits10 + 1);
// Input the states info
std::string tmp_label;
int tmp_iK;
Real tmp_E;
states_file >> tmp_label;
do {
states_file >> tmp_iK >> tmp_E;
label_.push_back(tmp_label);
iK_.push_back(tmp_iK);
E_.push_back(tmp_E);
} while (states_file >> tmp_label);
states_file.close();
nr_states_ = int(label_.size());
// Input the amplitudes
std::complex tmp_amplitude;
for (int is { 0 }; is < nr_states_; ++is) {
amplitudes_file >> tmp_amplitude;
amplitude.push_back(tmp_amplitude);
}
amplitudes_file.close();
// Input the density operator matrix elements
for (int ibra { 0 }; ibra < nr_states_; ++ibra) {
for (int iket { 0 }; iket <= ibra; ++iket) {
rho_ME_file >> rho_ME_[label_[ibra]][label_[iket]];
}
}
rho_ME_file.close();
// Compute the weighed averages of energy*k and momentum^2
// Logic: in the time power expansion, we put
// (d/dt)(d/dx) rho(x+vgt, t)
// to zero.
std::complex omegakBar { 0 };
std::complex ksqBar { 0 };
for (int ibra { 0 }; ibra < nr_states_; ++ibra) {
for (int iket { 0 }; iket < ibra; ++iket) {
omegakBar += std::conj(amplitude[ibra]) * amplitude[iket]
* rho_ME_[label_[ibra]][label_[iket]]
* (E_[ibra] - E_[iket]) * (twopi_r * (iK_[ibra] - iK_[iket])/L_);
ksqBar += std::conj(amplitude[ibra]) * amplitude[iket]
* rho_ME_[label_[ibra]][label_[iket]]
* std::pow(twopi_r * (iK_[ibra] - iK_[iket])/L_, 2);
}
}
// Define the group velocity as vg putting linear in t term to zero
Real vg { std::real(omegakBar)/std::real(ksqBar) };
// Compute the weighed average of moments of Galilean-shifted energy
int maxpower { 16 };
Real omegaminvgk;
std::vector> moment(maxpower+1, std::complex(0));
for (int ibra { 0 }; ibra < nr_states_; ++ibra) {
for (int iket { 0 }; iket < ibra; ++iket) {
omegaminvgk = E_[ibra] - E_[iket] - vg * twopi_r * (iK_[ibra] - iK_[iket])/L_;
for (int power { 0 }; power <= maxpower; power++) {
moment[power] += std::conj(amplitude[ibra]) * amplitude[iket]
* rho_ME_[label_[ibra]][label_[iket]]
* std::pow(omegaminvgk, power);
}
}
}
// Extract rescaled coefficients of the power series in t
std::vector coefficients(maxpower+1);
for (int power { 0 }; power <= maxpower; power++) {
coefficients[power] = 2* std::real(std::pow(1_ir, power) * moment[power])/std::tgamma(power+1);
}
// Estimated radius of convergence:
// time at which order 2, 4, 6 terms are ~ 0.1 (forgetting about higher terms)
Real t10c2 { std::pow(std::abs(0.1/coefficients[2]), 0.5) };
Real t10c4 { std::pow(std::abs(0.1/coefficients[4]), 0.25) };
Real t10c6 { std::pow(std::abs(0.1/coefficients[6]), 1.0/6) };
// time at which order 2, 4, 6 terms are ~ 0.1 of original depletion depth, which is |coefficients[0]|
Real t10c2r { std::pow(std::abs(0.1*coefficients[0]/coefficients[2]), 0.5) };
Real t10c4r { std::pow(std::abs(0.1*coefficients[0]/coefficients[4]), 0.25) };
Real t10c6r { std::pow(std::abs(0.1*coefficients[0]/coefficients[6]), 1.0/6) };
std::cout << std::setprecision(5);
std::cout << "amplitudes+matrix elements-aware group velocity vg = " << vg << std::endl;
std::cout << "quadratic time dependence coefficient c2 = " << coefficients[2] << std::endl;
std::cout << "times at which a given order term is 0.1: t=t10c2 when c2 * t^2 = 0.1 (and similarly for t10c4, t10c6)" << std::endl;
std::cout << "t10c2 (t at which o2 ~ 0.1) = " << t10c2 << std::endl;
std::cout << "t10c4 (t at which o4 ~ 0.1) = " << t10c4 << std::endl;
std::cout << "t10c6 (t at which o6 ~ 0.1) = " << t10c6 << std::endl;
std::cout << "t10c2r (t at which o2 ~ 0.1*o0) = " << t10c2r << std::endl;
std::cout << "t10c4r (t at which o4 ~ 0.1*o0) = " << t10c4r << std::endl;
std::cout << "t10c6r (t at which o6 ~ 0.1*o0) = " << t10c6r << std::endl;
std::cout << coefficients << std::endl;
// Define the output file
std::stringstream vgtau_filename;
vgtau_filename << filename_base.str() << "_" << protocol_ << ".vgtau";
std::ofstream vgtau_file;
vgtau_file.open(vgtau_filename.str(), std::ios::out | std::ios::trunc);
vgtau_file << std::setprecision(std::numeric_limits::digits10 + 1);
vgtau_file << "vg\t" << vg << std::endl;
vgtau_file << "t10c2\t" << t10c2 << std::endl;
vgtau_file << "t10c4\t" << t10c4 << std::endl;
vgtau_file << "t10c6\t" << t10c6 << std::endl;
vgtau_file << "t10c2r\t" << t10c2r << std::endl;
vgtau_file << "t10c4r\t" << t10c4r << std::endl;
vgtau_file << "t10c6r\t" << t10c6r << std::endl;
for (int power { 0 }; power <= maxpower; power++) {
vgtau_file << std::endl << "c" << power << "\t" << std::real(coefficients[power]);
}
vgtau_file.close();
return 0;
}