#ifndef agn_hpp #define agn_hpp #include #include #include #include #include #include #include #include #include #include #include #include #include namespace agn { const bool debug = false; const bool line_debug = false; const bool verbose=true; // General constants const double PI=3.14159265358979323846; const double PLANCK_CONST=4.135668e-15; // in eV * s const double BOLTZMANN_CONST=0.00008617332385; // in eV / K const double RYDBERG_CONST=1.0973731568539e7; // in 1 / m const double RYDBERG_UNIT_EV=13.60569252; // in eV const double RYDBERG_UNIT_ANGSTROM=1e10/RYDBERG_CONST; // in A // line label header lengths based on cloudy version // For cloudy 17, the characters reserved for the output quantities: // Label: 0-9 // Wavelength: 10-20 // radiated energy: 21-26 // eq width: 27-36 // Cloudy 13 had: 1,13; 17,5; 22,11; // c17: 0,18; 18,9; 27, 10 // c13 settings //int labelstr_pos = 1; //int labelstr_len = 13; //int radiatedenergystr_pos = 14; //int radiatedenergystr_len = 8; //int eqwidthstr_pos = 22; //int eqwidthstr_len = 9; // c17 settings int LABELSTR_POS = 0; int LABELSTR_LEN = 18; int RADIATEDENERGYSTR_POS = 18; int RADIATEDENERGYSTR_LEN = 9; int EQWIDTHSTR_POS = 27; int EQWIDTHSTR_LEN = 10; // Trims whitespace from line labels std::string label_trim(std::string); // Some useful containers and functions. typedef std::map table1d; typedef table1d::iterator iterator1d; std::string format_table1d(table1d); typedef std::map table2d; typedef table2d::iterator iterator2d; typedef std::pair coord2d; typedef std::list gridcoordlist; // Seeks an instream to the line after the first occurrence of seek_string. void seek_to(std::string,std::istream&); struct cloudy_line_data { double radiated_energy,eq_width; int index; bool has_duplicates; }; typedef std::map cloudy_line_output; struct cloudy_result { std::string header, footer; std::list intrinsic_line_raw_text; std::list emergent_line_raw_text; // Not currently collected std::list cautions; cloudy_line_output emergent_line_intensity; cloudy_line_output intrinsic_line_intensity; cloudy_line_output intrinsic_line_inward_intensity; int iterations; double phi,hden,colden; cloudy_result(): header(""), footer(""), intrinsic_line_raw_text(), cautions(), iterations(0), phi(0), hden(0), colden(0) {} }; typedef std::map cloudy_grid; // Easiest to read the entire grid from the file at once. cloudy_grid read_cloudy_grid(std::ifstream&); // Operator<< prints general info about the run result. std::ostream& operator<< (std::ostream&, cloudy_result); } // end namespace agn // Definitions std::string agn::label_trim(std::string label) { std::stringstream newlabel; newlabel << label[0] << label[1] << label[2] << label[3] << " " << label[agn::LABELSTR_LEN-8] << label[agn::LABELSTR_LEN-7] << label[agn::LABELSTR_LEN-6] << label[agn::LABELSTR_LEN-5] << label[agn::LABELSTR_LEN-4] << label[agn::LABELSTR_LEN-3] << label[agn::LABELSTR_LEN-2] << label[agn::LABELSTR_LEN-1]; for (int i=agn::LABELSTR_LEN; ifirst << "\t" << x->second << "\n"; x++; } return output.str(); } std::ostream& agn::operator<< (std::ostream& outstream, cloudy_result output) { outstream.width(5); outstream << std::fixed << std::setprecision(2) << output.hden << " x " << output.phi << " (colden " << std::fixed << std::setprecision(0) << output.colden << "): " << output.intrinsic_line_intensity.size() << " intrinsic emission lines, " << output.cautions.size() << " cautions present."; return outstream; } std::ifstream& operator>> (std::ifstream& inputfile,agn::cloudy_grid& grid) { grid = agn::read_cloudy_grid(inputfile); return inputfile; } agn::cloudy_grid agn::read_cloudy_grid(std::ifstream& inputfile) { if(agn::debug) std::cout << "Constructing cloudy output grid from file.\n"; inputfile.clear(); inputfile.seekg(0); std::string inputline; int line_num=0; getline(inputfile,inputline); std::string curstr = inputline.substr(0,23); std::string seek_string = "Producing grid output."; int pos = curstr.find(seek_string); while(line_num < 1000) { line_num++; getline(inputfile,inputline); curstr = inputline.substr(0,30); pos = inputline.find(seek_string); if (pos != std::string::npos) break; } if(agn::debug) std::cout << "Collecting grid meta data starting on line " << line_num << std::endl; agn::gridcoordlist coordlist; std::pair xy (0,0); // collect parameter coordinates seek_string="**************************************************"; while(!inputfile.eof()) { while (inputline.find(seek_string) == std::string::npos) getline(inputfile,inputline); while(inputfile.peek() == ' ') inputfile.get(); // Skip blank space // Break for first grid if (inputline.find("GRID_DELIMIT") != std::string::npos) break; char nextchar = inputfile.peek(); //bool hascoords = nextchar != '*' && nextchar != ' ' && nextchar != '\n'; bool hascoords = isalnum(nextchar); if (hascoords) { //if(agn::debug) std::cout << "Has coords.\n"; while (!isdigit(inputfile.peek())) inputfile.get(); inputfile >> xy.first; while (!isdigit(inputfile.peek())) inputfile.get(); inputfile >> xy.second; std::pair newentry (xy); coordlist.push_back(newentry); getline(inputfile,inputline); } else { getline(inputfile,inputline); while (inputline.find(seek_string) == std::string::npos) getline(inputfile,inputline); } } if(agn::debug) std::cout << "Reached first grid. " << coordlist.size() << " coordinate pairs found.\n"; agn::cloudy_grid grid; agn::gridcoordlist::iterator coords = coordlist.begin(); while(grid.size() < coordlist.size()) { bool failmode = false; agn::cloudy_result point; point.hden = coords->first; point.phi = coords->second; seek_string = "Intrinsic line intensities"; std::string fail_string = "PROBLEM DISASTER"; if(agn::debug) std::cout << "Grabbing header and cautions."; std::string header=""; std::list cautions; while (inputline.find(seek_string) == std::string::npos) { getline(inputfile,inputline); if (inputline.find(fail_string) != std::string::npos) { if(agn::debug) std::cout << " Found broken model."; failmode = true; break; } header.append(inputline); header.append("\n"); if((inputline[1] == 'C' && inputline[2] == '-') || (inputline[1] == ' ' && inputline[2] == '!' )) cautions.push_back(inputline); } if (failmode) { grid[*coords] = point; coords++; //agn::seek_to("c ======================",inputfile); //agn::seek_to("c ======================",inputfile); continue; } point.header = header; point.cautions = cautions; std::stringstream headerstr; headerstr << header; std::string headerword=""; headerstr.clear(); headerstr.seekg(0); int iterations; while(!headerstr.eof()) { headerstr >> headerword; //std::cout << "looking for iterations in " << headerword << "\n"; if(headerword == "Iteration") { headerstr >> iterations; break; } } if(agn::debug) std::cout << " Found " << iterations << " iterations."; point.iterations = iterations; headerstr.clear(); headerstr.seekg(0); double colden; while(!headerstr.eof()) { headerstr >> headerword; //std::cout << "checking "<> headerword; //std::cout << "found "<> colden; break; } } } if(agn::debug) std::cout << std::setprecision(2) << " Found 10^"< intrinsic_line_raw_text; getline(inputfile,inputline); while (inputline != "") { if(inputline.find("..") != std::string::npos) { getline(inputfile,inputline); continue; } intrinsic_line_raw_text.push_back(inputline); getline(inputfile,inputline); } point.intrinsic_line_raw_text.swap(intrinsic_line_raw_text); std::list::iterator linetext_it=point.intrinsic_line_raw_text.begin(); std::list duplicate_labels; int index=0; std::string label; // For cloudy 17, the characters reserved for the output quantities: // Label: 0-9 // Wavelength: 10-20 // radiated energy: 21-26 // eq width: 27-36 // Cloudy 13 had: 1,13; 17,5; 22,11; // c17: 0,18; 18,9; 27, 10 // c13 settings //int labelstr_pos = 1; //int labelstr_len = 13; //int radiatedenergystr_pos = 14; //int radiatedenergystr_len = 8; //int eqwidthstr_pos = 22; //int eqwidthstr_len = 9; // c17 settings int labelstr_pos = 0; int labelstr_len = 18; int radiatedenergystr_pos = 18; int radiatedenergystr_len = 9; int eqwidthstr_pos = 27; int eqwidthstr_len = 10; while(linetext_it != point.intrinsic_line_raw_text.end()) { // This section is also only written for the "final case" as alerted below if ((*linetext_it).substr(labelstr_pos,4) == "Inwd") { agn::cloudy_line_data inwddata; inwddata.index = ++index; inwddata.radiated_energy = atof((*linetext_it).substr( radiatedenergystr_pos, radiatedenergystr_len).c_str() ); inwddata.eq_width = atof((*linetext_it).substr( eqwidthstr_pos, eqwidthstr_len).c_str() ); if(line_debug) { std::cout << std::setprecision(5) << "Inwd " << (*linetext_it).substr(5) << ": " << label << "; " << inwddata.radiated_energy << " from " << (*linetext_it).substr( radiatedenergystr_pos, radiatedenergystr_len).c_str() << "; " << inwddata.eq_width << " from " << (*linetext_it).substr( eqwidthstr_pos, eqwidthstr_len).c_str() << "\n"; } point.intrinsic_line_inward_intensity[label] = inwddata; linetext_it++; continue; } label=(*linetext_it).substr( labelstr_pos, labelstr_len ); agn::cloudy_line_data data; data.index = ++index; //std::stringstream values; data.radiated_energy = atof((*linetext_it).substr( radiatedenergystr_pos, radiatedenergystr_len).c_str() ); data.eq_width = atof((*linetext_it).substr( eqwidthstr_pos, eqwidthstr_len).c_str() ); if(line_debug) { std::cout << std::setprecision(5) << *linetext_it << ": " << label << "; " << data.radiated_energy << " from " << (*linetext_it).substr( radiatedenergystr_pos, radiatedenergystr_len).c_str() << "; " << data.eq_width << " from " << (*linetext_it).substr( eqwidthstr_pos, eqwidthstr_len).c_str() << "\n"; } if(point.intrinsic_line_intensity.count(label) == 0) { data.has_duplicates = false; point.intrinsic_line_intensity[label] = data; } else { duplicate_labels.push_back(label); std::stringstream zerolabel(label); zerolabel << " j=0"; point.intrinsic_line_intensity[zerolabel.str()] = point.intrinsic_line_intensity[label]; point.intrinsic_line_intensity[zerolabel.str()].has_duplicates = true; point.intrinsic_line_intensity.erase(label); int j=1; data.has_duplicates = true; while(true) { std::stringstream newlabel; newlabel << label; newlabel << " j=" << j; if(point.intrinsic_line_intensity.count(newlabel.str()) != 0) { j++; // RED ALERT // To ease work in summer 2017, this line sets the // final instance of the emission line value // to the original label, this was to get around // the 3645.00A and 3647.00A being reported with // different values in c17 version 1 point.intrinsic_line_intensity[label] = data; continue; } else { point.intrinsic_line_intensity[newlabel.str()] = data; break; } } } linetext_it++; } if(agn::debug) std::cout << " Duplicates found: " << duplicate_labels.size(); if(agn::line_debug) { std::list::iterator dup_it = duplicate_labels.begin(); while (dup_it != duplicate_labels.end() ) { std::cout << std::endl; std::cout << *dup_it; dup_it++; } std::cout << " Grabbing footer."; } while (inputline == "") getline(inputfile,inputline); std::string footer=""; seek_string="GRID_DELIMIT"; while (inputline.find(seek_string) == std::string::npos){ footer.append(inputline); footer.append("\n"); getline(inputfile,inputline); } if(agn::debug) std::cout << "\nAdding point to grid (" << grid.size() << " of " << coordlist.size() << ") at " << coords->first << ": " << point << std::endl; grid[*coords] = point; coords++; } if(agn::debug) std::cout << "Grid captured. " << grid.size() << " points compiled.\n"; return grid; } #endif