/*! Type II quasisolitons in Lieb-Liniger: rhoxt Purpose: Produce the .x, .t and .rhoxt files respectively containing the coordinate and time vectors, and the rho(x,t) data matrix for (multi-)type II hole wavepackets in Lieb-Liniger. It automatically makes use of available hardware concurrency. 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; class Orchestrator { public: Orchestrator(Real c, Real L, int N, int nholes, int width, int offset, std::string protocol, int Nx, int Nt, Real tmax) : c_(c), L_(L), N_(N) , nholes_(nholes), width_(width), offset_(offset), protocol_(protocol) , Nx_(Nx), Nt_(Nt), tmax_(tmax) , rho_expval_(std::vector>(Nx+1, std::vector(Nt+1))) , x_(std::vector(Nx+1)) , t_(std::vector(Nt+1)) { set_up(); } public: Real c_; Real L_; int N_; int nholes_; int width_; int offset_; std::string protocol_; int Nx_; int Nt_; Real tmax_; int nr_states_; std::vector label_; std::vector iK_; std::vector E_; std::vector> amplitude; std::map>> rho_ME_; std::vector> rho_expval_; std::vector x_; std::vector t_; std::queue ix_queue_; std::mutex ix_mutex_; std::mutex rho_mutex_; void set_up(); void worker(); void save(); }; void Orchestrator::set_up() { for (int i { 0 }; i <= Nx_; ++i) ix_queue_.push(i); // Define the input files std::stringstream filename_base; filename_base << "c_" << c_ << "_N_" << N_ << "_L_" << L_ << "_nholes_" << nholes_ << "_width_" << width_ << "_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(); // Define the output files std::stringstream x_filename; x_filename << filename_base.str() << "_" << protocol_ << "_Nx_" << Nx_ << "_Nt_" << Nt_ << "_tmax_" << tmax_ << ".x"; std::ofstream x_file; x_file.open(x_filename.str(), std::ios::out | std::ios::trunc); x_file << std::setprecision(std::numeric_limits::digits10 + 1); std::stringstream t_filename; t_filename << filename_base.str() << "_" << protocol_ << "_Nx_" << Nx_ << "_Nt_" << Nt_ << "_tmax_" << tmax_ << ".t"; std::ofstream t_file; t_file.open(t_filename.str(), std::ios::out | std::ios::trunc); t_file << std::setprecision(std::numeric_limits::digits10 + 1); // Density as function of space and time for (int ix { 0 }; ix <= Nx_; ++ix) { x_[ix] = -L_/2 + L_ * ix/Nx_; x_file << std::endl << -L_/2 + L_ * ix/Nx_; } x_file.close(); for (int it { 0 }; it <= Nt_; ++it) { t_[it] = tmax_ * it/Nt_; t_file << std::endl << tmax_ * it/Nt_; } t_file.close(); } void Orchestrator::save() { std::stringstream filename_base; filename_base << "c_" << c_ << "_N_" << N_ << "_L_" << L_ << "_nholes_" << nholes_; filename_base << "_width_" << width_; filename_base << "_offset_" << offset_; std::stringstream rhoxt_filename; rhoxt_filename << filename_base.str() << "_" << protocol_ << "_Nx_" << Nx_ << "_Nt_" << Nt_ << "_tmax_" << tmax_ << ".rhoxt"; std::ofstream rhoxt_file; rhoxt_file.open(rhoxt_filename.str(), std::ios::out | std::ios::trunc); rhoxt_file << std::setprecision(std::numeric_limits::digits10 + 1); for (int ix { 0 }; ix <= Nx_; ++ix) { for (IndexU it { 0 }; it <= IndexU(Nt_); ++it) { rhoxt_file << rho_expval_[ix][it] << "\t"; } rhoxt_file << std::endl; } rhoxt_file.close(); } void Orchestrator::worker () { while (!ix_queue_.empty()) { ix_mutex_.lock(); int ix_here { ix_queue_.front() }; ix_queue_.pop(); ix_mutex_.unlock(); std::vector computed_rho_expval; for (int it { 0 }; it < t_.size(); ++it) { Real rho_value { 0 }; for (int ibra { 0 }; ibra < nr_states_; ++ibra) { for (int iket { 0 }; iket < ibra; ++iket) { // first add off-diagonal values rho_value += 2*std::real(std::conj(amplitude[ibra]) * amplitude[iket] * rho_ME_[label_[ibra]][label_[iket]] * std::exp(1_ir * ((E_[ibra] - E_[iket]) * t_[it] - (twopi_r * (iK_[ibra] - iK_[iket]) * x_[ix_here]/L_)))); } // then diagonal one (no factor of 2 here) rho_value += std::norm(amplitude[ibra]) * std::real(rho_ME_[label_[ibra]][label_[ibra]]); } computed_rho_expval.push_back(rho_value); } rho_mutex_.lock(); rho_expval_[ix_here].swap(computed_rho_expval); rho_mutex_.unlock(); } } int main(int argc, char* argv[]) { using namespace std::complex_literals; if (argc != 11) { std::cout << "Executable rhoxt\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 .x, .t and .rhoxt files\n" << " respectively containing the coordinate and time vectors, and the rho(x,t) data matrix\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 << "rhoxt \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"; std::cout << std::left << std::setw(warg) << "Nx" << std::setw(wtype) << "int" << std::setw(wcons) << "> 0" << "Number of spatial sampling points\n"; std::cout << std::left << std::setw(warg) << "Nt" << std::setw(wtype) << "int" << std::setw(wcons) << "> 0" << "Number of time slices\n"; std::cout << std::left << std::setw(warg) << "tmax" << std::setw(wtype) << "Real" << std::setw(wcons) << "> 0" << "Maximal time to reach\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 Nx { std::stoi(argv[8]) }; // number of points for x axis int Nt { std::stoi(argv[9]) }; // number of points for t slices Real tmax { std::stold(argv[10]) }; // time up to which movie is produced Orchestrator orchestrator(c, L, N, nholes, width, offset, protocol, Nx, Nt, tmax); int nr_threads_used { ι(std::thread::hardware_concurrency()*2/3) + 1 }; std::vector threads; for (int i { 0 }; i < nr_threads_used; ++i) threads.emplace_back(&Orchestrator::worker, &orchestrator); for (auto& t : threads) t.join(); orchestrator.save(); return 0; }