diff --git a/R/readutils.R b/R/readutils.R index 305a30806..f75f964c6 100644 --- a/R/readutils.R +++ b/R/readutils.R @@ -672,6 +672,8 @@ readtextcf <- function(file, Time=48, sym=TRUE, path="", skip=1, check.t=0, ind. #' '0001/mes_contr_2pts', not the lack of the smearing suffix. #' @param smear_combs_to_read Character vector containing the smearing cominations that are to be read. #' These will be attached to the `file_basenames_to_read` in the reading routine. +#' For corrtype = 2pt, the names are added with an underscore, +#' for corrtype = general, the names are added with a slash. #' @param Time Integer, time extent of the lattice. #' @param combs_to_read Data frame containing the indices of the masses and r-paramter combinations to #' be read as well as the name of the spin combination. @@ -682,6 +684,12 @@ readtextcf <- function(file, Time=48, sym=TRUE, path="", skip=1, check.t=0, ind. #' m1_idx \tab m2_idx \tab r1_idx \tab r2_idx \tab spin_comb \cr #' 1 \tab 2 \tab 0 \tab 0 \tab "P5P5" #' } +#' In the case of generalized orperator names, the data frame contains the +#' names of the opreator and the name of the spin combination, like this: +#' \tabular{rrrrr}{ +#' op1_idx \tab op2_idx \tab spin_comb \cr +#' C_H \tab H_H_S_H \tab "P5P5" +#' } #' @param sym.vec Integer or numeric vector. Specifies whether the correlator at #' the given position is symmetric (+1.0) or anti-symmetric (-1.0 ) #' under time reflection. This is passed to \code{symmetrise.cf}. This @@ -691,6 +699,10 @@ readtextcf <- function(file, Time=48, sym=TRUE, path="", skip=1, check.t=0, ind. #' @param symmetrise Boolean, specifies whether averaging over backward and forward #' correlators should be done after the correlator has been read in. #' @param nts Integer, number of time slices to be read from the correlator files. +#' @param corrtype Character. Determines the structure of the correlator names that are read. +#' 2pt reads correlators of the form S0_th0_m0_r0_ll ^ \dag S0_th0_m0_r0_ll, +#' general reads any operator name containing underscores, for example +#' C_H ^ \dag and Dth0_A0_C_P_H_H_S_H #' #' @return #' Returns an object of class `cf`. @@ -702,12 +714,17 @@ readnissatextcf <- function(file_basenames_to_read, combs_to_read, nts = Time, sym.vec = c(1), - symmetrise = FALSE) + symmetrise = FALSE, + corrtype="2pt") { + if (corrtype == "2pt") { corrtypenum=1} + else if (corrtype == "general") { corrtypenum=2} + else { stop("invalid correlation type given! must be either 2pt or general") } tmp <- read_nissa_textcf_kernel(file_basenames_to_read, smear_combs_to_read, nts, - combs_to_read) + combs_to_read, + corrtypenum) total_nts <- nts*length(smear_combs_to_read)*nrow(combs_to_read) diff --git a/src/read_nissa_textcf_kernel.cpp b/src/read_nissa_textcf_kernel.cpp index fd768e937..c13702932 100644 --- a/src/read_nissa_textcf_kernel.cpp +++ b/src/read_nissa_textcf_kernel.cpp @@ -10,6 +10,10 @@ using namespace Rcpp; +// corrtypes: what type of information is read from the file +// 1=2pt: m1, m2, r1, r2, spin_info +// 2=newcorr: op1, op2, spin_info + /** * @brief read 2*nts doubles from a std::ifstream * @@ -52,6 +56,23 @@ inline std::string make_key_2pt(unsigned int m1_idx, unsigned int m2_idx, unsign return std::string(ckey); } +/** + * @brief make a key string of two operators + * + * @param op1_idx name of the first correlator, for example C_H + * @param op2_idx name of the second correlator, for example H_H_S_H + * @param spin_comb name of the spin combination, for example "P5P5" or "V1A0" + * + * @return key of the form "op1_%s_op2_%s_%s" + */ +inline std::string make_key_newcorr(std::string op1_idx, std::string op2_idx, std::string spin_comb) +{ + char ckey[100]; + snprintf(ckey, 100, "op1_%s_op2_%s_%s", + op1_idx.c_str(), op2_idx.c_str(), spin_comb.c_str()); + return std::string(ckey); +} + /** * @brief read correlator meta-data and map to file positions * @description Nissa text correlator files contain meta-data in the form @@ -73,8 +94,9 @@ inline std::string make_key_2pt(unsigned int m1_idx, unsigned int m2_idx, unsign * * @param ifs file to be parsed * @param filemap output, map of file positions for the various correlators in the file + * @param corrtype: what kind of correlator to look for, either 1, with specified m, r, or 2, with any possible string containing an underscore specified */ -inline void map_file(std::ifstream &ifs, std::map & filemap){ +inline void map_file(std::ifstream &ifs, std::map & filemap, const size_t corrtype=1){ if( !ifs.good() ){ stop("map_file: input file stream not in a good state!"); } @@ -82,54 +104,119 @@ inline void map_file(std::ifstream &ifs, std::map lbcopy( linebuf.size() + 1 ); - lbcopy[ linebuf.size() ] = '\0'; - memcpy( lbcopy.data(), linebuf.c_str(), linebuf.size() ); - unsigned int key_components_counter = 0; - char * token = strtok(lbcopy.data(), "_"); - while( key_components_counter != 4 || token != NULL ){ - if( token[0] == 'm' || token[0] == 'r'){ - key_components[key_components_counter] = atoi(token+1); - key_components_counter++; + if(corrtype==1){ + // currently the key for a two-point function consists of four unsigned integers (two mass and two r indices) + // and the name of the spin combination stored in the correlator + // a generalisation of the reader will have to modify this as well as the key construction + // for now we store the numeric key components in this array + unsigned int key_components[4]; + while( ifs.good() ){ + std::getline(ifs, linebuf); + // we search for commented lines + comment_pos = linebuf.find("#"); + if( comment_pos != std::string::npos ){ + // in these commented lines, we extract either + // the current set of mass / r parameter combinations + // or the current spin combination + // the line looks like so: + // " # Contraction of S0_th0_m0_r0_ll ^ \dag and S0_th0_m0_r0_ll" + std::string::size_type contr_pos = linebuf.find("Contraction"); + if( contr_pos != std::string::npos ){ + std::vector lbcopy( linebuf.size() + 1 ); + lbcopy[ linebuf.size() ] = '\0'; + memcpy( lbcopy.data(), linebuf.c_str(), linebuf.size() ); + unsigned int key_components_counter = 0; + char * token = strtok(lbcopy.data(), "_"); + while( key_components_counter != 4 || token != NULL ){ + if( token[0] == 'm' || token[0] == 'r'){ + key_components[key_components_counter] = atoi(token+1); + key_components_counter++; + } + token = strtok(NULL, "_"); } - token = strtok(NULL, "_"); - } - if(key_components_counter != 4 && token == NULL){ - char message[200]; - snprintf(message, 200, "map_file: unable to construct key components in parsing of '%s'", linebuf.c_str()); - stop(message); + if(key_components_counter != 4 && token == NULL){ + char message[200]; + snprintf(message, 200, "map_file: unable to construct key components in parsing of '%s'", linebuf.c_str()); + stop(message); + } + } else { + // the line looks like so: + // " # P5S0" + std::string::size_type last_space_pos = linebuf.find_last_of(" "); + std::string spin_comb = linebuf.substr(last_space_pos+1); + // now we can build the key + std::string key = make_key_2pt(key_components[0], key_components[2], key_components[1], key_components[3], spin_comb); + // and store the position after the current newline as the starting point + // of the present correlator + filemap[ key ] = ifs.tellg(); } - } else { + } // found commented line + } //while good + } // if corrtype==1 + if(corrtype==2){ + // currently the key for any correlator is the name of the first and the second correlator, + // and the name of the spin combination stored in the correlator + std::string key_components[2]; + while( ifs.good() ){ + std::getline(ifs, linebuf); + // we search for commented lines + comment_pos = linebuf.find("#"); + if( comment_pos != std::string::npos ){ + // in these commented lines, we extract either + // the current operators + // or the current spin combination // the line looks like so: - // " # P5S0" - std::string::size_type last_space_pos = linebuf.find_last_of(" "); - std::string spin_comb = linebuf.substr(last_space_pos+1); - // now we can build the key - std::string key = make_key_2pt(key_components[0], key_components[2], key_components[1], key_components[3], spin_comb); - // and store the position after the current newline as the starting point - // of the present correlator - filemap[ key ] = ifs.tellg(); - } - } - } + // " # Contraction of C_H ^ \dag and Dth0_A0_C_P_H_H_S_H " + std::string::size_type contr_pos = linebuf.find("Contraction"); + if( contr_pos != std::string::npos ){ + unsigned int key_components_counter = 0; + std::string token; + std::string delimiter (" \0"); + size_t pos = linebuf.find_first_of(delimiter, 0); + // The different parts of the string are separated by spaces + // Take the part of the string until the first space. + // See if it contains an underscore. + // If it does, this is the name of an operator + // delete first part of line and restart search + // https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c + // If the search reaches the end of the line, + // check if the last part of the line is the name of a correlator by doing the loop one more time + // look through at most 50 words, so the programm exits if there is no operator on the line + size_t last_part=0, j = 0; + while( key_components_counter != 2 && last_part < 2 && j < 50) { + token = linebuf.substr(0, pos); + if( token.find("_") != std::string::npos){ + key_components[key_components_counter] = (std::string)token; + key_components_counter++; + } + linebuf.erase(0, pos+1); + j++; + pos = linebuf.find_first_of(delimiter); + if (pos == std::string::npos) { + last_part++; + pos = linebuf.length(); + } + } + if(key_components_counter != 2){ + char message[200]; + snprintf(message, 200, "map_file: unable to construct key components in parsing of '%s'", linebuf.c_str()); + stop(message); + } + } else { + // the line looks like so: + // " # P5S0" + std::string::size_type last_space_pos = linebuf.find_last_of(" "); + std::string spin_comb = linebuf.substr(last_space_pos+1); + // now we can build the key + std::string key = make_key_newcorr(key_components[0], key_components[1], spin_comb); + + // and store the position after the current newline as the starting point + // of the present correlator + filemap[ key ] = ifs.tellg(); + } + } // found commented line + } //while good + } // if corrtype==2 } /** @@ -142,8 +229,14 @@ NumericMatrix read_nissa_textcf_kernel( CharacterVector file_basenames_to_read, CharacterVector smear_combs_to_read, const unsigned int nts, - DataFrame combs_to_read) + DataFrame combs_to_read, + size_t corrtype = 1) { + if (corrtype != 1 && corrtype != 2){ + char message[200]; + snprintf(message, 200, "No valid corrtype was given! You gave %lu, valid corrtypes are 1 for 2pt and 2 for newcorr", corrtype); + stop(message); + } const unsigned int n_correls = combs_to_read.nrows(); const unsigned int n_smear_combs = smear_combs_to_read.size(); @@ -153,10 +246,19 @@ NumericMatrix read_nissa_textcf_kernel( NumericMatrix cf_data(n_files, 2*nts*n_correls*n_smear_combs ); CharacterVector spin_combs = combs_to_read["spin_comb"]; - IntegerVector r1_idcs = combs_to_read["r1_idx"]; - IntegerVector r2_idcs = combs_to_read["r2_idx"]; - IntegerVector m1_idcs = combs_to_read["m1_idx"]; - IntegerVector m2_idcs = combs_to_read["m2_idx"]; + CharacterVector op1_idcs, op2_idcs; + IntegerVector r1_idcs, r2_idcs, m1_idcs, m2_idcs; + // different correlator naming schemes require different input: type 1 needs info on all r, m, type 2 needs names, both need spin comb + if (corrtype == 1) { + r1_idcs = combs_to_read["r1_idx"]; + r2_idcs = combs_to_read["r2_idx"]; + m1_idcs = combs_to_read["m1_idx"]; + m2_idcs = combs_to_read["m2_idx"]; + } + if (corrtype == 2){ + op1_idcs = combs_to_read["op1_idx"]; + op2_idcs = combs_to_read["op2_idx"]; + } std::vector realbuf(nts); std::vector imagbuf(nts); @@ -164,7 +266,12 @@ NumericMatrix read_nissa_textcf_kernel( for(unsigned int ifile = 0; ifile < n_files; ++ifile ){ for(unsigned int ismear_comb = 0; ismear_comb < n_smear_combs; ++ismear_comb ){ - std::string filename = (std::string)(file_basenames_to_read[ifile]) + std::string("_") + + std::string filename; + + //for type 2: use smear_comb to indicate file ending + if(corrtype == 1) filename = (std::string)(file_basenames_to_read[ifile]) + std::string("_") + + (std::string)(smear_combs_to_read[ismear_comb]); + if(corrtype == 2) filename = (std::string)(file_basenames_to_read[ifile]) + std::string("/") + (std::string)(smear_combs_to_read[ismear_comb]); std::ifstream ifs(filename.c_str(), std::ios::in); @@ -178,7 +285,7 @@ NumericMatrix read_nissa_textcf_kernel( // to a certain position in the file by reading the meta-data // this is a significant overhead incurred on a per-file basis, // but it is robust against changes in the file's structure - map_file(ifs, filemap); + map_file(ifs, filemap, corrtype=corrtype); // bring file back into good state ifs.clear(); @@ -190,11 +297,19 @@ NumericMatrix read_nissa_textcf_kernel( // if we ever support other correlation functions from Nissa, // a simple point to generalise would be here in the way the key is // constructed - std::string key = make_key_2pt((unsigned int)m1_idcs[icorrel], - (unsigned int)m2_idcs[icorrel], - (unsigned int)r1_idcs[icorrel], - (unsigned int)r2_idcs[icorrel], - (std::string)spin_combs[icorrel]); + std::string key; + if(corrtype==1){ + key = make_key_2pt((unsigned int)m1_idcs[icorrel], + (unsigned int)m2_idcs[icorrel], + (unsigned int)r1_idcs[icorrel], + (unsigned int)r2_idcs[icorrel], + (std::string)spin_combs[icorrel]); + } + if(corrtype==2){ + key = make_key_newcorr((std::string)op1_idcs[icorrel], + (std::string)op2_idcs[icorrel], + (std::string)spin_combs[icorrel]); + } if( filemap.count(key) != 1 ){ char message[200]; snprintf(message, 200, "correlator %s does not exist in file %s!", key.c_str(), filename.c_str());