bool ALSBL8XASFileLoaderPlugin::load(AMScan *scan, const QString &userDataFolder, AMErrorMon *errorMonitor){

	if(columns2fileFormatHeaders_.count() == 0) {
		columns2fileFormatHeaders_.set("eV", "Mono Energy");
		columns2fileFormatHeaders_.set("ringCurrent", "Beam Current");
		columns2fileFormatHeaders_.set("I0", "Counter 0");
		columns2fileFormatHeaders_.set("TEY", "Counter 1");
		columns2fileFormatHeaders_.set("TFY", "Counter 2");
	}

	if(!scan)
		return false;

	// Clear the old scan axes to ensure we don't have any extras.
	scan->clearRawDataCompletely();
	scan->rawData()->addScanAxis( AMAxisInfo("eV", 0, "Incident Energy", "eV") );

	QFileInfo sourceFileInfo(scan->filePath());
	if(sourceFileInfo.isRelative()){
		sourceFileInfo.setFile(userDataFolder + "/" + scan->filePath());
	}

	// used in parsing the data file
	QString line;
	QStringList lp;

	// names of the columns, taken from headers in the data file.
	QStringList colNames1;

	// open the file:
	QFile f(sourceFileInfo.filePath());
	if(!f.open(QIODevice::ReadOnly)) {
		errorMonitor->exteriorReport(AMErrorReport(0, AMErrorReport::Serious, ALSBL8XASFileLoaderPLUGIN_CANNOT_OPEN_FILE, "ALSBL8XASFileLoader parse error while loading scan data from file. Missing file."));
		return false;
	}
	QTextStream fs(&f);

	// find out what columns exist. Looking for line starting with 'Time (s)'
	while(!fs.atEnd() && !line.startsWith("Time (s)"))
		line = fs.readLine();
	if(fs.atEnd()) {
		errorMonitor->exteriorReport(AMErrorReport(0, AMErrorReport::Serious, ALSBL8XASFileLoaderPLUGIN_BAD_FORMAT_NO_EVENT1_HEADER, "ALSBL8XASFileLoader parse error while loading scan data from file. Missing the Column Header line."));
		return false;	// bad format. Missing the column header
	}
	colNames1 = line.split(QChar('\t'));

	// translate header names into meaningful column names (ex: "Counter 0" ---> "I0".... "Counter1"--->"tey")
	for(int i=0; i<colNames1.count(); i++)
		header2columnName(colNames1[i]);

	// ensure that we have the basic "eV" column
	int eVIndex = colNames1.indexOf("eV");
	if(eVIndex < 0) {
		errorMonitor->exteriorReport(AMErrorReport(0, AMErrorReport::Serious, ALSBL8XASFileLoaderPLUGIN_BAD_FORMAT_NO_ENERGY_COLUMN, "ALSBL8XASFileLoader parse error while loading scan data from file. I couldn't find the energy (eV) column."));
		return false;	// bad format. No primary column

	}

	scan->clearRawDataPointsAndMeasurements();

	// There is a rawData scan axis called "eV" created in the constructor.  AMAxisInfo("eV", 0, "Incident Energy", "eV")
	/// \todo What if there isn't? Should we check, and create the axis if none exist? What if there's more than one scan axis? Can't remove from AMDataStore... [The rest of this code assumes a single scan axis]

	// add scalar (0D) measurements to the raw data store, for each data column.  Also add raw data sources to the scan, which expose this data.
	foreach(QString colName, colNames1) {
		if(colName != "eV" && colName != "Event-ID") {
			scan->rawData()->addMeasurement(AMMeasurementInfo(colName, colName));	/// \todo nice descriptions for the common column names. Not just 'tey' or 'tfy'.
		}
	}

	int eVAxisIndex = 0;	// counter for each datapoint along the scan axis.

	// read all the data. Add to data columns or scan properties depending on the event-ID.
	while(!fs.atEnd()) {

		line = fs.readLine();

		// Data line. If there are the correct number of columns:
		if( (lp = line.split('\t', QString::SkipEmptyParts)).count() == colNames1.count() ) {

			// append a new datapoint to the data tree (supply primary eV value here)
			scan->rawData()->beginInsertRows(1, -1);
			scan->rawData()->setAxisValue(0, eVAxisIndex, lp.at(eVIndex).toDouble());	// insert eV

			// add all columns (but ignore the eV column)
			int measurementId = 0;
			for(int i=1; i<colNames1.count(); i++) {
				if(i!=eVIndex)
					scan->rawData()->setValue(eVAxisIndex, measurementId++, AMnDIndex(), lp.at(i).toDouble());
			}
			eVAxisIndex++;
			scan->rawData()->endInsertRows();
		}
	}

	/// Not supposed to create the raw data sources.  Do an integrity check on the pre-existing data sources instead... If there's a raw data source, but it's pointing to a non-existent measurement in the data store, that's a problem. Remove it.  \todo Is there any way to incorporate this at a higher level, so that import-writers don't need to bother?

	for(int i=0; i<scan->rawDataSources()->count(); i++) {
		if(scan->rawDataSources()->at(i)->measurementId() >= scan->rawData()->measurementCount()) {
			errorMonitor->exteriorReport(AMErrorReport(scan, AMErrorReport::Debug, ALSBL8XASFileLoaderPLUGIN_DATA_COLUMN_MISMATCH, QString("The data in the file didn't match the raw data columns we were expecting. Removing the raw data column '%1')").arg(scan->rawDataSources()->at(i)->name())));
			scan->deleteRawDataSource(i);
		}
	}

	return true;
}
Example #2
0
bool ALSBL8XASFileLoader::loadFromFile(const QString& filepath, bool setMetaData, bool setRawDataSources, bool createDefaultAnalysisBlocks) {

	// not initialized to have a scan target, or scan target is not an AMXASScan...
	AMXASScan* scan = qobject_cast<AMXASScan*>(scan_);
	if(!scan)
		return false;

	// Clear the old scan axes to ensure we don't have any extras.
	scan->clearRawDataCompletely();
	scan->rawData()->addScanAxis( AMAxisInfo("eV", 0, "Incident Energy", "eV") );

	// information about the scan we hope to locate:
	QString comments;
	double integrationTime;

	// used in parsing the data file
	QString line;
	QStringList lp;

	// names of the columns, taken from headers in the data file.
	QStringList colNames1;

	// open the file:
	QFile f(filepath);
	if(!f.open(QIODevice::ReadOnly)) {
		AMErrorMon::report(AMErrorReport(0, AMErrorReport::Serious, -1, "ALSBL8XASFileLoader parse error while loading scan data from file. Missing file."));
		return false;
	}
	QTextStream fs(&f);

	if(setMetaData) {
		// Start reading the file. look for the count-time line.
		while( !fs.atEnd() && !(line = fs.readLine()).startsWith("Count Time (s):") )
			;
		if(fs.atEnd()) {
			AMErrorMon::report(AMErrorReport(0, AMErrorReport::Debug, -2, "ALSBL8XASFileLoader parse error while loading scan data from file. Could not find the count time (integration time)."));
			fs.seek(0);
			// return false;	// bad format; missing the count time string
		}
		else {
			// read it
			integrationTime = line.split(':').at(1).trimmed().toDouble();
		}


		// Keep reading the file. look for the comment line.
		while( !fs.atEnd() && !(line = fs.readLine()).startsWith("Description Length:") )
			;
		if(fs.atEnd()) {
			AMErrorMon::report(AMErrorReport(0, AMErrorReport::Debug, -2, "ALSBL8XASFileLoader parse error while loading scan data from file. Could not find the description."));
			fs.seek(0);
			// return false;	// bad format; missing the comment string
		}
		else {

			// read the comment
			bool descriptionLengthOk;
			int descriptionLength = line.split(':').at(1).trimmed().toInt(&descriptionLengthOk);
			// read this many characters now...
			if(descriptionLengthOk)
				comments = fs.read(descriptionLength);
		}
	}


	// find out what columns exist. Looking for line starting with 'Time (s)'
	line.clear();
	while(!fs.atEnd() && !line.startsWith("Time (s)"))
		line = fs.readLine();
	if(fs.atEnd()) {
		AMErrorMon::report(AMErrorReport(0, AMErrorReport::Serious, -2, "ALSBL8XASFileLoader parse error while loading scan data from file. Missing the Column Header line."));
		return false;	// bad format; missing the column header
	}
	colNames1 = line.split(QChar('\t'));

	// translate header names into meaningful column names (ex: "Counter 0" ---> "I0".... "Counter1"--->"tey")
	for(int i=0; i<colNames1.count(); i++)
		header2columnName(colNames1[i]);

	// ensure that we have the basic "eV" column
	int eVIndex = colNames1.indexOf("eV");
	if(eVIndex < 0) {
		AMErrorMon::report(AMErrorReport(0, AMErrorReport::Serious, -3, "ALSBL8XASFileLoader parse error while loading scan data from file. I couldn't find the energy (eV) column."));
		return false;	// bad format; no primary column

	}

	// clear the existing raw data (and raw data sources, if we're supposed to)
	if(setRawDataSources)
		scan->clearRawDataPointsAndMeasurementsAndDataSources();
	else
		scan->clearRawDataPointsAndMeasurements();

	// There is a rawData scan axis called "eV" created in the constructor.  AMAxisInfo("eV", 0, "Incident Energy", "eV")
	/// \todo What if there isn't? Should we check, and create the axis if none exist? What if there's more than one scan axis? Can't remove from AMDataStore... [The rest of this code assumes a single scan axis]

	// add scalar (0D) measurements to the raw data store, for each data column.  Also add raw data sources to the scan, which expose this data.
	foreach(QString colName, colNames1) {
		if(colName != "eV" && colName != "Event-ID") {
			scan->rawData()->addMeasurement(AMMeasurementInfo(colName, colName));	/// \todo nice descriptions for the common column names; not just 'tey' or 'tfy'.
		}
	}

	int eVAxisIndex = 0;	// counter for each datapoint along the scan axis.

	// read all the data. Add to data columns or scan properties depending on the event-ID.
	while(!fs.atEnd()) {

		line = fs.readLine();

		// Data line. If there are the correct number of columns:
		if( (lp = line.split('\t', QString::SkipEmptyParts)).count() == colNames1.count() ) {

			// append a new datapoint to the data tree (supply primary eV value here)
			scan->rawData()->beginInsertRows(1, -1);
			scan->rawData()->setAxisValue(0, eVAxisIndex, lp.at(eVIndex).toDouble());	// insert eV

			// add all columns (but ignore the eV column)
			int measurementId = 0;
			for(int i=1; i<colNames1.count(); i++) {
				if(i!=eVIndex)
					scan->rawData()->setValue(eVAxisIndex, measurementId++, AMnDIndex(), lp.at(i).toDouble());
			}
			eVAxisIndex++;
			scan->rawData()->endInsertRows();
		}
	}


	if(setMetaData) {
		scan->setNotes(comments);
		// for a date-time, there is no information saved inside the file format, so the best we can do is look at the file's creation date-time...
		QFileInfo fi(filepath);
		scan->setDateTime(fi.lastModified());
		/// \todo integration time... do what with?
	}

	// If we need to create the raw data sources...
	if(setRawDataSources) {
		// expose the raw data that might be useful to the users
		foreach(QString visibleColumn, defaultUserVisibleColumns_) {
			int measurementId = scan->rawData()->idOfMeasurement(visibleColumn);
			if(measurementId >= 0)
				scan->addRawDataSource(new AMRawDataSource(scan->rawData(), measurementId));
		}
	}