// // XSPEC12 November 2003 // // // location for functions that are in namespace XSGlobal but not part // of the Global class. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #ifdef GUI_SUPPORT #include #include #endif } namespace xstcl { // container definitions for the command set and their // one-line help summaries char xsLogOut[] = "LogOut"; char xsLogErr[] = "ErrOut"; int xs_echo_script = 0; char xsTclPrompt[] = "xs_tcl_prompt"; char* xs_tcl_prompt = 0; Tcl_Trace XS_Echo_Trace = 0; } namespace XSGlobal { GlobalData* globalData = 0; std::map commandMap; std::map summaryMap; std::map pdfMap; //good place for this? } bool XSGlobal::printDocs(const char* command, const char* firstArgument) { bool done = false; if (!firstArgument || (strlen(firstArgument) == 1 && *firstArgument == '?') ) { // print out summary information on blank or '?' tcout << summaryMap[command] << std::endl; done = true; } return done; } void XSGlobal::registerNativeFitMethods() { FitMethod::registerMethod("leven",new LevMarq("10 0.01")); // FitMethod::registerMethod("anneal",new Anneal); summaryMap["method"] = refreshFitMethodNames(); } void XSGlobal::initializeGUILibraries(Tcl_Interp* xsInterp) { int status(TCL_OK); // initialize Tk. If the initialization succeeds, defind the Tk package to Tcl. // If it fails, generally speaking this is because the user does not have access // to and X display, either because of permissions, environment (no DISPLAY variable) // or because they are not running under X. In this case, simply continue silently // and do not initialize Tk. #ifdef GUI_SUPPORT if ( (status = Tk_Init(xsInterp)) == TCL_OK) { char tk[] = "Tk"; Tcl_StaticPackage(xsInterp, tk, Tk_Init, Tk_SafeInit); } // initialize Itcl/Itk // // This is itkwish, so import all [incr Tcl] commands by // default into the global namespace. Fix up the autoloader // to do the same. Use TclInitErr exception to make the flow look simple. // In principle we could load Itcl for the non GUI case, but this is not // too necessary, so we load both or neither. if (status == TCL_OK) { if ( (status = Itk_Init(xsInterp)) == TCL_OK) { char CItk[] = "Itk"; char itkn[] = "::itk::*"; Tcl_StaticPackage(xsInterp, CItk, Itk_Init, (Tcl_PackageInitProc *) NULL); if ((status = Tcl_Import(xsInterp, Tcl_GetGlobalNamespace(xsInterp),itkn, 1)) == TCL_OK) { char mkindex[] = "auto_mkindex_parser::slavehook { _%@namespace import -force ::itcl::* ::itk::* }"; if ( (status = Tcl_Eval(xsInterp,mkindex)) == TCL_ERROR) { throw TclInitErr("Itk Error: constructing script index itcl/itk"); } } else { throw TclInitErr("Itk Error: getting itk namespace"); } } else { throw TclInitErr("Itcl Error: cannot initialize Itk"); } } else { throw TclInitErr("Itcl Error: getting itcl namespace"); } if ( (status = Pow_Init(xsInterp)) == TCL_ERROR) { std::cerr << "Cannot initialize graphical interface.\n"; std::cerr << "Switching to command line mode." << std::endl; globalData->gui(false); } #endif // NB this necessitates "true" as the default // setting since the .xspecrc file hasn't been read yet. } void XSGlobal::registerNativeStatMethods() { using namespace XSContainer; Weight* standard = new StandardWeight; Weight* churazov = new ChurazovWeight; Weight* gehrels = new GehrelsWeight; Weight* modWeight = new ModelWeight; StatMethod::registerWeightingMethod(standard->name(), standard); StatMethod::registerWeightingMethod(churazov->name(), churazov); StatMethod::registerWeightingMethod(gehrels->name(), gehrels); StatMethod::registerWeightingMethod(modWeight->name(), modWeight); StatMethod::registerMethod("chi",new ChiSquare); StatMethod::registerMethod("cstat",new Cstat); StatMethod::registerMethod("lstat",new Lstat); //StatMethod::registerMethod("k-s",new EDF); //StatMethod::registerMethod("c-vm",new EDF); //StatMethod::registerMethod("a-d",new EDF); string doc("set statistic to optimize \n Syntax:statistic [ "); doc += StatMethod::statNames(); doc += " ]"; summaryMap["statistic"] = doc; doc = "set data weighting\n Syntax:weight [ " ; doc += StatMethod::weightNames(); doc += " ]"; summaryMap["weight"] = doc; } void XSGlobal::registerNativePlotCommands(Plot* plot) { std::pair listOfPlotCommands(PlotCommandCreator::registerPlotCommands(plot)); string& primary = listOfPlotCommands.first; string& secondary = listOfPlotCommands.second; string doc ("plot data/models/fits etc\n Syntax: primary plot commands:\n"); size_t fieldWidth(15); size_t npcommands(primary.size() / fieldWidth); size_t cnpl ( npcommands/5); for (size_t j = 0; j < cnpl; ++j) { doc += "\t"; doc += primary.substr( j*5*fieldWidth, 5*fieldWidth ); doc += "\n"; } doc += "\t"; doc += primary.substr(cnpl*5*fieldWidth); doc += "\n"; doc += " secondary options "; doc += "(2-panel data plots - use with (l)data, (l)counts, icounts):\n"; size_t nscommands(secondary.size() / fieldWidth); size_t cnsl ( nscommands/5); for (size_t j = 0; j < cnsl; ++j) { doc += "\t"; doc += secondary.substr( j*5*fieldWidth, 5*fieldWidth ); doc += "\n"; } doc += "\t"; doc += secondary.substr(cnsl*5*fieldWidth); summaryMap["plot"] = doc; } void XSGlobal::registerNativeTables() { TableComponent::registerTableFormat(new OGIPTable("")); } void XSGlobal::registerNativeLineLists() { LineList::registerLineList("apec", new Apec); LineList::registerLineList("bearden", new Bearden); LineList::registerLineList("mekal", new Mekal); } void XSGlobal::startUp() { using namespace XSContainer; string title, buildDate; XSutility::XSVersionString(title, buildDate); tcout << '\n' << "\t\t" << title << std::endl; tcout << '\t' << buildDate << '\n' << std::endl; DataSet::xspecVersion(title); // now we can process the other initial settings. globalData->processSettings(); if (!globalData->gui()) { plot = Plot::Instance(globalData->defaultGraph(),globalData->managerDir()); string waveUnits(globalData->settings("WAVE_PLOT_UNITS")); if (waveUnits.length()) { const string angstroms("angstroms"); if (angstroms.find(XSutility::lowerCase(waveUnits)) == 0) plot->waveUnitsHz(0); } } else { // This will throw a RedAlert for the time being. plot = Plot::Instance(" ",globalData->managerDir()); } string plotDevice (globalData->settings("PLOTDEVICE")); try { if ( plotDevice.length()) { plot->graph()->setDevice(plotDevice); } } catch ( ... ) { // do nothing, the exception will have printed a // message } //register plot commands. Must happen after the plot control object // is instantiated registerNativePlotCommands(plot); } void XSGlobal::cleanUp() { LineList::clearLineLists(); TableComponent::clearTableFormats(); FitMethod::clearMethods(); StatMethod::clearWeightingMethods(); StatMethod::clearMethods(); delete Help::helpTree(); delete DummyResponse::Instance(); delete XspecRegistry::Instance(); // in case the order is important this should be right. delete SignalHandler::instance(); delete XSContainer::plot; delete XSContainer::fit; delete XSContainer::models; delete ParamLinkList::Instance(); delete XSContainer::datasets; delete XSContainer::responses; // Deliberately placing this after the destruction of models. // Not currently necessary (5/08), but model components do carry // generator pointers to model functions, and it's best that these // remain valid throughout the model destruction process. clearFunctionMap(); MathExpression::clearOperatorsMap(); system(string("rm -f " + globalData->undoFile()).c_str()); std::ostringstream cmd; string autosaveFile = globalData->autoSaveFile(); struct stat info; stat(autosaveFile.c_str(), &info); if(info.st_size) cmd << "mv -f " << autosaveFile << ' ' << autosaveFile.substr(0, autosaveFile.rfind("xautosav_") + 8) << ".xcm"; else cmd << "rm -f " << autosaveFile; system((cmd.str()).c_str()); delete globalData; } void XSGlobal::createCommandMap() { const string& managerDir = XSGlobal::globalData->managerDir(); string comfilename = managerDir + "/CommandSummary.txt"; ifstream comfile; comfile.open(comfilename.c_str()); if (!comfile) { string message = "Cannot open " + comfilename; throw RedAlert(message); } string line(""); size_t nlines; string comName; while (!comfile.eof()) { getline(comfile,line); istringstream s(line); s >> comName >> nlines; s.clear(); string doc(""); for(size_t i=0; igui()) { // internal, not documented. commandMap["unknown"] = &xsUnknown; } else { // internal, not documented: used by GUI // which redefines unknown by itself. // XSunknown is the default handler for // unknown commands caught this way. commandMap["XSunknown"] = &xsUnknown; } commandMap["genetic"] = &xsGenetic; commandMap["recornrm"] = &xsRecornrm; commandMap["thleqw"] = &xsThleqw; } void XSGlobal::registerFunctionUtility () { FunctionUtility::managerPath(globalData->managerDir()); const string HEADAS(getenv("HEADAS")); string dataPath (HEADAS + "/../spectral/modelData/"); FunctionUtility::modelDataPath(dataPath); string crossSections; string abundances; FunctionUtility::readInitializers(crossSections,abundances); string xSectDoc("Change/Report the photoionization cross sections\n"); xSectDoc += " Syntax: xsect " + crossSections; summaryMap["xsect"] = xSectDoc; string abundDoc("Change/Report the solar abundance table in use\n"); abundDoc += " Syntax: abund " + abundances +"\n"; abundDoc += " abund \n"; abundDoc += " (define & load new vector from data in )"; summaryMap["abund"] = abundDoc; } string XSGlobal::refreshFitMethodNames() { string fitMethodDoc("set fitting algorithm\n"); fitMethodDoc += " Syntax:method [ "; fitMethodDoc += FitMethod::fitNames(); fitMethodDoc += "] " ; return fitMethodDoc; } void XSGlobal::commonPlotHandler(const StringArray& args, bool isInteractive) { using XSContainer::plot; StringArray plotCmd; //lastCommand defaults to "data" in Plot constructor plotCmd = (args[0] == "" ? plot->lastCommand() : args); const size_t N(plotCmd.size()); string value(""), arg(""); if (N > 0) { arg = XSutility::lowerCase(plotCmd[0]); size_t commaInArg = arg.find_first_of(','); if ( commaInArg != XSparse::NOTFOUND()) { // the "+1" parses off the first comma which is just a separator // between the command and the parameters. value = arg.substr(commaInArg+1); arg = arg.substr(0,commaInArg); } else value = Model::DEFAULT(); } if ( N > 1) { Real dummy; size_t dummy2; bool isModel = (string("model").find(arg) == 0); string tmp, sub = plotCmd[1].substr(0, plotCmd[1].find(',')); if ( !isModel && !XSutility::isReal(sub, dummy) && !XSparse::stringIntPair(sub, tmp, dummy2) && plotCmd[1][0] != ',') { arg += " "; arg += XSutility::lowerCase(sub); } // send this and all subsequent arguments to the value string. // "value" string will be ignored by commands that don't use it // (all the data commands). // commands like "plot model " will use this. // commands like plot contour that are followed by real arguments must // deal with by the command. value = plotCmd[1]; for (size_t j = 2; j < N; ++j) { value += " "; value += plotCmd[j]; } } PlotCommand* pC = PlotCommandCreator::commands(XSutility::lowerCase(arg)); if (!pC) { throw YellowAlert("Plot subcommand does not exist or has not yet been implemented.\n"); } else { //save last command plot->lastCommand(plotCmd); try { plot->graph()->setInteractive(isInteractive); // std::cerr << value << '\n'; pC->execute(value); } catch (YellowAlert &) { // If exception propagates after PlotGroups are created, // but before command has a chance to call plot->makeTheGraph // (which deletes them), then needs to be cleaned up here. plot->resetPlotGroups(); throw; } } } void XSGlobal::saveAll(const string& outFileName) { try { std::ofstream outFile(outFileName.c_str()); // note that xspec11 also prints out gain // information - since the gain command is // not yet implemented in xspec12 this // is not done here but needs to be addressed. // BD 11/16/03 XSContainer::datasets->saveData(outFile); saveModel(outFile); } catch ( std::exception& ) { tcerr << " File cannot be opened for writing\n"; // disable autosave to forbid further messages. globalData->autoSaveFrequency(XSparse::NOTFOUND()); } } void XSGlobal::saveModel(std::ofstream& outStream) { using namespace std; FitMethod* fitMethod (XSContainer::fit->fitMethod()); StatMethod* statMethod (XSContainer::fit->statMethod()); outStream << "statistic " << statMethod->name() << endl; outStream << "method " << fitMethod->selectedSubMethod() << ' ' << fitMethod->settingString() << endl; if(FunctionUtility::abundChanged()) outStream << "cd " << FunctionUtility::abundPath() << "\nabund file " << FunctionUtility::abundanceFile() << endl; else outStream << "abund " << FunctionUtility::ABUND() << endl; outStream << "xsect " << FunctionUtility::XSECT() << endl; outStream << "cosmo " << FunctionUtility::getH0() << " " << FunctionUtility::getq0() << " " << FunctionUtility::getlambda0() << endl; outStream << "xset delta " << XSContainer::models->proportionalDelta() << endl; const map& xsetStrings = FunctionUtility::modelStringDataBase(); map::const_iterator itString = xsetStrings.begin(); map::const_iterator itStringEnd = xsetStrings.end(); while (itString != itStringEnd) { outStream << "xset " << itString->first << " " << itString->second << endl; ++itString; } XSContainer::models->saveData(outStream); } void XSGlobal::registerNativeRandomizingStrategies(Fit* fit) { std::auto_ptr rand(new Randomizer()); // If the following call doesn't throw, relinquish ownership of // rand to the fit container. fit->registerRandomizingStrategy(rand->name(), rand.get()); RandomizerBase* tmp = rand.release(); fit->chainManager()->setChainProposal(tmp->name()); rand.reset(new Randomizer()); fit->registerRandomizingStrategy(rand->name(), rand.get()); rand.release(); rand.reset(new Randomizer()); fit->registerRandomizingStrategy(rand->name(), rand.get()); rand.release(); rand.reset(new Randomizer()); fit->registerRandomizingStrategy(rand->name(), rand.get()); rand.release(); rand.reset(new Randomizer()); fit->registerRandomizingStrategy(rand->name(), rand.get()); rand.release(); rand.reset(new Randomizer()); fit->registerRandomizingStrategy(rand->name(), rand.get()); rand.release(); rand.reset(new Randomizer()); fit->registerRandomizingStrategy(rand->name(), rand.get()); rand.release(); rand.reset(new Randomizer()); fit->registerRandomizingStrategy(rand->name(), rand.get()); rand.release(); // We want to distinguish these native classes from any the // user may add in at a later time. So fill in Fit's // nativeRandomizerNames container with these names. // (This can only be done once.) fit->initNativeRandomizerNames(); }