/*! 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; }