// // XSPEC12 November 2003 // // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace XSContainer; int XSGlobal::xsData(ClientData cdata,Tcl_Interp* tclInterp,int objc, Tcl_Obj* CONST objv[]) { using namespace std; const char* cmd = static_cast(cdata); int nSpectra (datasets->numberOfSpectra()); //static Memento* dataMemento = 0; if ( objc == 1) { XSGlobal::printDocs(cmd,"?"); return globalData->autoSave(TCL_OK); } else if (objc >= 2) { string firstArg(Tcl_GetString(objv[1])); if (firstArg == "?") { XSGlobal::printDocs(cmd,"?"); return globalData->autoSave(TCL_OK); } if(firstArg != "%MEMENTO") globalData->memento(datasets->CreateMemento()); else { datasets->SetMemento(globalData->memento()); datasets->Notify(); datasets->emptyTrash(); globalData->memento(0); //we don't to write an autosave script here - at the //moment undoing an undo operation is unimplemented. //just save the autosave file. XSGlobal::saveAll(globalData->autoSaveFile()); return TCL_OK; //return globalData->autoSave(TCL_OK); } if(objc == 2) { // if data none was typed, clear the data structure and return. if ( XSutility::lowerCase(firstArg) == XSparse::NONE()) { datasets->dgHistory().initOldArray(datasets->numberOfGroups()); datasets->clear(); //an arg of false makes sure memory for Response* objects aren't //deleted. just their entry in the global ResponseContainer. responses->clear(false); datasets->Notify(); return globalData->autoSave(TCL_OK, 0); } size_t numericArg = XSutility::isInteger(firstArg); // delete all datasets after the number supplied and return. if (numericArg != XSparse::NOTFOUND() ) { if (numericArg >= static_cast(nSpectra)) { tcerr << "XSPEC: Request to delete spectra not yet loaded ... skipped \n"; return globalData->autoSave(TCL_ERROR); } else { datasets->dgHistory().initOldArray(datasets->numberOfGroups()); datasets->deleteRange(numericArg+1,nSpectra); datasets->Notify(); return globalData->autoSave(TCL_OK, 0); } } } } // pull out the case where we have a trailing slash. // but, you can't modify Tcl's obj array... StringArray argArray(objc); for (int j = 0; j < objc; ++j) { argArray[j] = string(Tcl_GetString(objv[j])); string arg = argArray[j]; size_t len = arg.length(); // Check that slash does not appear at the end of // any arg except the last. Also check that slash // is not immediately followed by a comma anywhere. if (len) { for (size_t i=0; iautoSave(TCL_ERROR); } } } if (arg[len-1] == '/' && j != objc-1) { tcerr <<"***Error: Slash (/) can only be entered for the last entry"<autoSave(TCL_ERROR); } } } const string& testForPreserve = argArray[objc-1]; bool preserve(testForPreserve[testForPreserve.length()-1] == '/'); if (preserve) { argArray[objc - 1] = testForPreserve.substr(0,testForPreserve.length()-1); } DataUtility::recordList inputData; try { inputData = DataUtility::parseDataCommandString(argArray,XSutility::PHA); } catch (YellowAlert&) { return globalData->autoSave(TCL_ERROR); } if (inputData.empty()) { // This can happen if user entered a blank string in quotes. return globalData->autoSave(TCL_OK, 0); } // mark datasets as preserved or deleted. // for those spectra with numbers higher than those deleted // (e.g. with data none), renumber. //std::vector markForDeletion(nSpectra,false); // conditions for *removal* of previously read spectra: // a) highest spectrum number requested in the data command // is lower than the current number of spectra, and // i) dataSetNames arguments ending in a '/' character // preserve the datasets with following spectrum numbers. // ii) dataSetNames arguments ending in one or more ',' characters // preserve that number of spectra with following spectrum numbers. // b) a dataSetNames argument is "none" or "none/" . // case (i) "none" - remove all datasets from the current spectrumNumber // to the end of the spectrumNumber array. // case (ii) "none/" - remove the numbered spectrum and decrement the // spectrumNumber of spectra with higher spectrumNumber // values by one. // first pass: correct spectrumNumbers and remove commas. // post-processing of dataSetNames arguments. // correct spectrumNumbers according to commas. // try doing this in two passes. First, read the data from disk. // process the spectrumNumbers and data groups, and then // add correct information to the DataContainer. size_t numSpectraRead = 0; SIGINT_Handler intHandler; SignalHandler* sigContainer = SignalHandler::instance(); EventHandler* oldHandler = sigContainer->registerHandler(SIGINT, &intHandler); DataUtility::recordListIter record = inputData.begin(); DataUtility::recordListIter dataEnd = inputData.end(); // this first loop determines the total number of spectra to be read. while (record != dataEnd ) { // got to fix commas before doing this. string& dsName = record->fileName(); // any records after 'none' will be ignored if ( XSutility::lowerCase(dsName) == XSparse::NONE()) { ++record; // Note that dataEnd is no longer valid after this, // but we are exiting the loop so it's OK. inputData.erase(record, dataEnd); break; } DataPrototype* p = 0; try { p = XSContainer::xsRegistry->returnPrototype(dsName); } catch (XspecRegistry::UnrecognizedFormat) { record = inputData.erase(record); continue; } catch (XspecDataIO::CannotOpen) { string replacement(""); //returns true if a "terminate" string (none, /*) supplied // by user. try { XSparse::getFileNameFromUser(dsName,replacement, XSutility::PHA); if (replacement.length() != 0) { dsName = replacement; p = XSContainer::xsRegistry->returnPrototype(dsName); } else { record = inputData.erase(record); continue; } } catch (XspecDataIO::CannotOpen) { record = inputData.erase(record); continue; } catch (XSparse::SkipThis) { record = inputData.erase(record); continue; } catch (XSparse::AbortLoop) { while (record != dataEnd) record = inputData.erase(record); break; } } try { std::auto_ptr dSet(p->MakeDataSet()); dSet->initialize(p,*record); size_t group = record->groupNumber(); const IntegerArray& SN = record->spectrumNumber(); const IntegerArray& dataRow = record->spectrumRange(); size_t ns = SN.size(); dSet->dataGroup(group); for (size_t j = 0; j < ns; ++j) { dSet->setData(SN[j],dataRow[j]); if (SN[j] <= (int)datasets->numberOfSpectra()) { int n(0); SpectralData* sd=datasets->lookup(SN[j]); int pg=sd->plotGroup(); #ifndef STD_COUNT_DEFECT n = std::count(datasets->plotGroupNums().begin(), datasets->plotGroupNums().end(), pg); #else std::count(datasets->plotGroupNums().begin(), datasets->plotGroupNums().end(), pg, n); #endif if ((n>1) && !dSet->sourceData(dataRow[j])-> energiesEqual(sd)) { std::ostringstream os; os << record->fileName() << " skipped.\n" << "Spectrum " << SN[j] << " is in a plot group with other spectra.\n" << "It cannot be replaced with a spectrum with different" <<" energy bins and/or channel numbers.\n"; throw(XSparse::SkipThis(os.str())); } } ++numSpectraRead; if (numSpectraRead >= 5) { // The backspace characters mess up the log file, // so make sure log output is turned off. XSstream::verbose(tpout,10,999); std:: ostringstream os; os << "Number of spectra read ..... " << numSpectraRead; string backup(os.str().length(), '\b'); tcout << backup << os.str() << std::flush; XSstream::verbose(tpout); } if (intHandler.interrupted()) { dSet->closeSourceFiles(); string msg("\n***Data loading interrupted by user."); msg += string("\n***All spectra loading from currently open file will be lost.\n"); throw XSparse::AbortLoop(msg); } } dSet->closeSourceFiles(); record->data(dSet.release()); ++record; } catch (XSparse::AbortLoop) { // /* was entered, remove the rest of the input arguments // and stop processing this loop. tcout << std::endl; while (record != inputData.end()) record = inputData.erase(record); break; } catch (YellowAlert&) { // problem processing data: remove current iteration // and continue. record = inputData.erase(record); continue; } } // end record list loop sigContainer->registerHandler(SIGINT, oldHandler); DataUtility::fixSequence(inputData,nSpectra); for (DataUtility::recordListIter r = inputData.begin(); r != inputData.end(); ++r) { // diagnostic information for DataInputRecord. r->report(); } std::vector marked = datasets->insertAndDelete(inputData,nSpectra,preserve); DataUtility::recordListIter dataStep = inputData.begin(); datasets->dgHistory().initOldArray(datasets->numberOfGroups()); while (dataStep != dataEnd ) { // all successful, add processed data to global container datasets->addToList(dataStep->data()); ++dataStep; } datasets->deleteRange(marked, preserve); // If any dummy responses existed anywhere, replace them. IntegerArray all(0); datasets->resetDetectors(all); dataStep = inputData.begin(); while (dataStep != dataEnd ) { // Report and clean up the corresponding inputData record. dataStep->data()->reportAll(); dataStep = inputData.erase(dataStep); } datasets->Notify(); return globalData->autoSave(TCL_OK, 0); }