//**************************************************************************// //* FRIDA: fast reliable interactive data analysis *// //* rssm.cpp: read SPHERES raw data *// //* (C) Joachim Wuttke 1990-, v2(C++) 2001- *// //* http://frida.sourceforge.net *// //**************************************************************************// #include <stdlib.h> #include <stdio.h> #include <time.h> #include <string> #include <vector> #include <algorithm> #include <libxml/xmlmemory.h> #include <libxml/parser.h> #include "olm.h" #include "asi.h" #include "gar.h" #include "rssm.h" using namespace std; class RssmRawFile { public: int ReadRaw( string fnam ); double daq_time_step; time_t measured_from; time_t measured_until; int measured_at; double measured_during; bool incremental; vector<double> rawdata[6]; vector<double> angles; double temp0, temp1; double final_setp; int maj_syntax, min_syntax, maj_outform, min_outform; }; // Read raw data file, store contents as class variables int RssmRawFile::ReadRaw( string fnam ) { xmlChar *key, *val, *txt, *syntax, *outform, *format, *axis, *contents, *categ, *txt1, *txt2; xmlDocPtr doc; xmlNodePtr cur, sub; char date_string[24]; struct tm date_broken; if( !(doc = xmlParseFile( fnam.c_str() ) ) ){ xmlFreeDoc( doc ); return 1; } if( !(cur = xmlDocGetRootElement( doc ) ) ){ fprintf( stderr, "Data file has no root element.\n" ); xmlFreeDoc( doc ); return -1; } if( xmlStrcmp( cur->name, (const xmlChar*) "data" ) ){ fprintf( stderr, "Data file of the wrong type, root node != data\n" ); xmlFreeDoc( doc ); return -1; } if( (syntax = xmlGetProp( cur, (const xmlChar*)"syntax" )) ){ if( !xmlStrcmp( syntax, (const xmlChar*)"wuml 4.1" ) ){ maj_syntax = 4; min_syntax = 1; } else { fprintf( stderr, "Recognition of new syntax not yet implemented\n" ); xmlFreeDoc( doc ); return -1; } if( !(outform = xmlGetProp( cur, (const xmlChar*)"generator" )) ){ fprintf( stderr, "Missing 'generator' information\n" ); xmlFreeDoc( doc ); return -1; } if( !xmlStrcmp( outform, (const xmlChar*)"acq 4.1" ) ){ maj_outform = 4; min_outform = 1; } else { fprintf( stderr, "Recognition of new output not yet implemented\n" ); xmlFreeDoc( doc ); return -1; } } else { if( !(format = xmlGetProp( cur, (const xmlChar*)"format" )) ){ fprintf( stderr, "Old file has no format specification\n" ); xmlFreeDoc( doc ); return -1; } if( !xmlStrcmp( format, (const xmlChar*)"2007-04-12" ) ){ maj_syntax = 2; min_syntax = 0; maj_outform = 2; min_outform = 0; } else if( !xmlStrcmp( format, (const xmlChar*)"2008-03-03" ) ){ maj_syntax = 3; min_syntax = 0; maj_outform = 3; min_outform = 0; } else { fprintf( stderr, "Old file has unexpected format\n" ); xmlFreeDoc( doc ); return -1; } } // *** scan parameters *** daq_time_step=0; incremental = true; measured_until = -999; temp0 = -1; temp1 = -1; final_setp = -1; // Scan parameters in header sub = cur->xmlChildrenNode; while( sub != NULL ){ if( (!xmlStrcmp( sub->name, (const xmlChar*)"par" ) ) ){ key = xmlGetProp( sub, (const xmlChar*)"key" ); val = xmlGetProp( sub, (const xmlChar*)"value" ); if ( !xmlStrcmp( key, (const xmlChar*)"temp.temp0" ) ){ sscanf( (const char*)val, "%lg", &temp0 ); } else if ( !xmlStrcmp( key, (const xmlChar*)"temp.temp1" ) ){ sscanf( (const char*)val, "%lg", &temp1 ); } else if ( !xmlStrcmp( key, (const xmlChar*)"final_setp" ) ){ sscanf( (const char*)val, "%lg", &final_setp ); } else if ( !xmlStrcmp( key, (const xmlChar*)"daq_time_step" ) ){ sscanf( (const char*)val, "%lg", &daq_time_step ); } else if ( !xmlStrcmp( key, (const xmlChar*)"incremental" ) ){ sscanf( (const char*)val, "%i", &incremental ); } else if ( !xmlStrcmp( key, (const xmlChar*)"incremental save" ) ){ // PROVISIONAL: only for data before R51-6 sscanf( (const char*)val, "%i", &incremental ); } else if ( !xmlStrcmp( key, (const xmlChar*)"measured_until" ) ){ sscanf( (const char*)val, "%24c", date_string ); strptime( date_string, "%F %A %H:%M:%S", &date_broken ); measured_until = mktime( &date_broken ); // strftime( tstrg, 30, "%F %b %H:%M:%S", // localtime( &measured_until ) ); // printf( "measured until %s\n", tstrg ); // PROVISIONAL: later data include measured_from } xmlFree( key ); xmlFree( val ); } sub = sub->next; } if( !daq_time_step ){ fprintf( stderr, "Data file has no parameter \"daq_time_step\".\n" ); xmlFreeDoc( doc ); return -1; } // Scan arrays sub = cur->xmlChildrenNode; int iaxisE=0, iaxisP=4, iaxis; if( maj_outform<=2 ){ angles.resize(19); for( int j=0; j<19; ++j ) angles[j] = j; } while( sub != NULL ){ if( (!xmlStrcmp(sub->name, (const xmlChar*)"array" ) ) ){ axis = xmlGetProp( sub, (const xmlChar*)"xaxis" ); contents = xmlGetProp( sub, (const xmlChar*)"contents" ); categ = xmlGetProp( sub, (const xmlChar*)"categorization" ); if( !axis && !contents ){ printf( "array has neither old axis nor new contents " "attribute\n" ); return -1; } else if( axis && contents ){ printf( "array has conflicting attributes: " "old axis and new contents\n" ); return -1; } else if( !xmlStrcmp( axis, (const xmlChar*)"angle" ) || !xmlStrcmp( contents, (const xmlChar*)"detector-info" ) ){ if( axis ) xmlFree( axis ); if( contents ) xmlFree( contents ); txt = xmlNodeListGetString( doc, sub->xmlChildrenNode, 1 ); vector<double> aux; if( mystd::str2vec( (const char*)txt, &aux, 0, false) ){ printf( "str2vec( array text ) failed\n" ); } xmlFree( txt ); angles.clear(); for( int i=0; i<aux.size(); i+=(axis? 2 : 3 ) ) angles.push_back( aux[i] ); sub = sub->next; continue; } else if( !xmlStrcmp( axis, (const xmlChar*)"energy" ) || !xmlStrcmp( contents, (const xmlChar*)"histogram" ) && !xmlStrcmp( categ, (const xmlChar*)"energy" ) ){ txt1 = xmlGetProp( sub, (const xmlChar*)"halfspace" ); if( txt1==NULL ) txt1 = xmlGetProp( sub, (const xmlChar*)"Doppler_halfspace" ); txt2 = xmlGetProp( sub, (const xmlChar*)"chopper_phase" ); if( !txt1 || !txt2 ){ printf( "array with erg axis missing some attribute\n" ); return -1; } iaxis = iaxisE++; if( !(iaxis%2==0 && !xmlStrcmp(txt1,(const xmlChar*)"left") || iaxis%2==1 && !xmlStrcmp(txt1,(const xmlChar*)"right"))){ printf( "unexpected halfspace in energy array\n" ); // return -1; } if( !(iaxis/2==0 && !xmlStrcmp(txt2,(const xmlChar*)"refl") || iaxis/2==1 && !xmlStrcmp(txt2,(const xmlChar*)"open")) ){ printf( "unexpected chopper_phase in energy array\n" ); return -1; } xmlFree( txt1 ); xmlFree( txt2 ); } else if( !xmlStrcmp( axis, (const xmlChar*)"chop_phase" ) || !xmlStrcmp( contents, (const xmlChar*)"histogram" ) && !xmlStrcmp( categ, (const xmlChar*)"chopper_phase" ) ){ txt1 = xmlGetProp( sub, (const xmlChar*)"energy_range" ); if( !txt1 ){ printf( "array with cho axis missing energy_range\n" ); return -1; } iaxis = iaxisP++; if( !(iaxis==4 && !xmlStrcmp(txt1,(const xmlChar*)"elast") || iaxis==5 && !xmlStrcmp(txt1,(const xmlChar*)"inela")) ){ printf( "unexpected energy_range in chopper array\n" ); return -1; } xmlFree( txt1 ); } else { printf( "unexpected array axis\n" ); return -1; } xmlFree( axis ); txt = xmlNodeListGetString( doc, sub->xmlChildrenNode, 1 ); if( mystd::str2vec( (const char*)txt, &(rawdata[iaxis]), 0, false) ){ printf( "str2vec( array text ) failed\n" ); } xmlFree( txt ); } sub = sub->next; } xmlFreeDoc( doc ); return 0; } void NRSSM::ReadScan( int flag ) // flag values (to be OR'ed): // 1 save also open // 2 save also chop histo // 4 save spectra also separately for both directions // 8 do not save regular spectrum { string file_f, name; file_f = wask("Read SPHERES data from xml file"); RssmRawFile R; int ret = R.ReadRaw( file_f ); if( ret==1 ) fprintf( stderr, "Data file not parsed successfully.\n" ); if( ret ) return; double tstep = R.daq_time_step; vector<double> *raw = R.rawdata; int ndet = R.angles.size(); // *** set file headers *** COld olf[8]; int iolf; for( iolf=0; iolf<8; ++iolf ){ olf[iolf].lDoc.push_back( "acquire data from "+file_f ); olf[iolf].xco = iolf<4 ||iolf>5 ? CCoord( "E", "ueV" ) : CCoord( "phase", "deg" ); olf[iolf].yco = CCoord( "cts", "sec-1" ); olf[iolf].ZCo.push_back( CCoord( "det", "") ); } mystd::fname_divide( file_f, 0, &name, 0 ); olf[0].name = name+"left"; olf[1].name = name+"right"; olf[2].name = name+"open_left"; olf[3].name = name+"open_right"; olf[4].name = name+"chop_elast"; olf[5].name = name+"chop_inela"; olf[6].name = name; olf[7].name = name+"open"; olf[0].lDoc.push_back( "refl, left halfspace" ); olf[1].lDoc.push_back( "refl, right halfspace" ); olf[2].lDoc.push_back( "open, left halfspace" ); olf[3].lDoc.push_back( "open, right halfspace" ); olf[4].lDoc.push_back( "elastic region" ); olf[5].lDoc.push_back( "inelastic region" ); olf[6].lDoc.push_back( "refl, average over both halfspaces" ); olf[7].lDoc.push_back( "open, average over both halfspaces" ); CScan S; for( int j=0; j<ndet; ++j ){ S.Clear(); S.z.resize( 1 ); S.z[0] = R.angles[j]; for( iolf=0; iolf<8; ++iolf ) olf[iolf].VS.push_back(S); } if( R.maj_outform<=2 ){ double x, tmeas, count; // transfer data from raw arrays: for( iolf=0; iolf<6; ++iolf ){ for( int iraw=0; iraw<(raw+iolf)->size(); iraw+=(ndet+2) ){ x = raw[iolf][iraw]; tmeas = raw[iolf][iraw+ndet+1]; if( tmeas<1 ) continue; for ( int j=0; j<ndet; ++j ){ count = raw[iolf][iraw+1+j]; olf[iolf].VS[j].push_back( x, count/tmeas/tstep ); } } } // sum over halfspaces: for( int ichop=0; ichop<2; ++ichop ){ int iolf0 = ichop*2; int iolf1 = ichop*2+1; int nline = (raw+iolf0)->size(); if( (raw+iolf1)->size()!=nline ){ printf( "inconsistent raw array sizes\n" ); return; } for( int iraw=0; iraw<nline; iraw+=(ndet+2) ){ x = raw[iolf0][iraw]; tmeas = raw[iolf0][iraw+ndet+1]+raw[iolf1][iraw+ndet+1]; if( tmeas<1 ) continue; for ( int j=0; j<ndet; ++j ){ count = raw[iolf0][iraw+1+j] + raw[iolf1][iraw+1+j]; olf[6+ichop].VS[j].push_back( x, count/tmeas/tstep ); } } } } else { // as of 2008-03-03 double x, tmeas, count; // transfer data from raw arrays: for( iolf=0; iolf<6; ++iolf ){ for( int iraw=0; iraw<(raw+iolf)->size(); iraw+=(1+ndet*2) ){ x = raw[iolf][iraw]; for ( int j=0; j<ndet; ++j ){ tmeas = raw[iolf][iraw+1+ndet+j]; if( tmeas<1 ) continue; count = raw[iolf][iraw+1+j]; olf[iolf].VS[j].push_back( x, count/tmeas/tstep ); } } } // sum over halfspaces: for( int ichop=0; ichop<2; ++ichop ){ int iolf0 = ichop*2; int iolf1 = ichop*2+1; int nline = (raw+iolf0)->size(); if( (raw+iolf1)->size()!=nline ){ printf( "inconsistent raw array sizes\n" ); return; } for( int iraw=0; iraw<nline; iraw+=(1+ndet*2) ){ x = raw[iolf0][iraw]; for ( int j=0; j<ndet; ++j ){ tmeas = raw[iolf0][iraw+1+ndet+j] + raw[iolf1][iraw+1+ndet+j]; if( tmeas<1 ) continue; count = raw[iolf0][iraw+1+j] + raw[iolf1][iraw+1+j]; olf[6+ichop].VS[j].push_back( x, count/tmeas/tstep ); } } } } NOlm::SelNew(); if( flag & 2 ){ NOlm::OloAdd(&olf[4]); NOlm::OloAdd(&olf[5]); } if( flag & 2 && flag & 4 ){ NOlm::OloAdd(&olf[2]); NOlm::OloAdd(&olf[3]); } if( flag & 4 ){ NOlm::OloAdd(&olf[0]); NOlm::OloAdd(&olf[1]); } if( flag & 1 ){ NOlm::OloAdd(&olf[7]); } if( ! (flag & 8 ) ){ NOlm::OloAdd(&olf[6]); } } void NRSSM::ReadSeries( int flag ) // flag values (to be OR'ed): // 1 save also open { char tstrg[30]; string fser, name; time_t t; int ret, isub; vector<RssmRawFile> RR; // Read consolidated files: fser = wask("Read SPHERES data from series"); for( isub=0; ; ++isub ){ RR.push_back( RssmRawFile() ); ret = RR.back().ReadRaw( fser+"c"+strg(isub) ); if( ret==1 ){ printf( "ignore the above warning\n" ); RR.pop_back(); break; } if( ret ) return; } int nsub = RR.size(); if( nsub==0 ) return; else if( nsub==1 ){ printf( "series contains just one scan -> use a simpler method\n" ); return; } printf( "successfully read %d files\n", nsub ); // Correct time: double mean_time = ( RR[nsub-1].measured_until - RR[0].measured_until ) / nsub; printf( "mean measuring time %g seconds per file\n", mean_time ); t = (time_t) (RR[0].measured_until-mean_time); strftime( tstrg, 30, "%F %b %H:%M:%S", localtime( &t ) ); printf( "measurement times relative to start time %s\n", tstrg ); for( isub=0; isub<nsub; ++isub ) RR[isub].measured_at = RR[isub].measured_until - RR[0].measured_until + (int) (mean_time/2); // Get parameters, check consistency: int ndet = RR[0].angles.size(); double tstep = RR[0].daq_time_step; bool incremental_in = RR[0].incremental; int nE = RR[0].rawdata[0].size()/(ndet+2); for( isub=1; isub<nsub; ++isub ){ if( RR[isub].angles.size()!=ndet || RR[isub].daq_time_step!=tstep || RR[isub].incremental!=incremental_in || RR[0].rawdata[0].size()/(ndet+2)!=nE ){ printf( "SEVERE essential parameters are inconsistent\n" ); return; } } // Set file headers: COld olf[2]; int iolf, j; for( iolf=0; iolf<2; ++iolf ){ olf[iolf].lDoc.push_back( "acquire data from series"+fser ); olf[iolf].xco = CCoord( "E", "ueV" ); olf[iolf].yco = CCoord( "cts", "sec-1" ); olf[iolf].ZCo.push_back( CCoord( "T0", "K") ); olf[iolf].ZCo.push_back( CCoord( "T1", "K") ); olf[iolf].ZCo.push_back( CCoord( "det", "") ); } mystd::fname_divide( fser, 0, &name, 0 ); olf[0].name = name; olf[1].name = name+"open"; olf[0].lDoc.push_back( "refl, average over both halfspaces" ); olf[1].lDoc.push_back( "open, average over both halfspaces" ); for( isub=0; isub<nsub; ++isub ){ // ? = (double)RR[isub].measured_at/3600; for( j=0; j<ndet; ++j ){ CScan S; S.z.resize( 3 ); S.z[0] = RR[isub].temp0; S.z[1] = RR[isub].temp1; S.z[2] = RR[isub].angles[j]; for( iolf=0; iolf<2; ++iolf ) olf[iolf].VS.push_back( S ); } } if( RR[0].maj_outform>=3 ){ printf( "series / format080303 not yet implemented\n" ); return; } // Reverse incrementation? if( incremental_in ){ printf( "reversing incrementation\n" ); for( isub=nsub-1; isub>=1; --isub ){ for( int iarr=0; iarr<4; ++iarr ){ for( int iE=0; iE<nE; ++iE ){ for( j=1; j<ndet+2; ++j ){ RR[isub].rawdata[iarr][iE*(ndet+2)+j] -= RR[isub-1].rawdata[iarr][iE*(ndet+2)+j]; } } } } } // Transfer data from raw arrays, sum over halfspaces: vector<double> *raw; double x, tmeas, count; int iraw; for( isub=0; isub<nsub; ++isub ){ raw = RR[isub].rawdata; for( int ichop=0; ichop<2; ++ichop ){ int iolf0 = ichop*2; int iolf1 = ichop*2+1; if( (raw+iolf1)->size()/(ndet+2)!=nE ){ printf( "inconsistent raw array sizes\n" ); return; } for( int iE=0; iE<nE; ++iE ){ iraw = iE*(ndet+2); x = raw[iolf0][iraw]; tmeas = raw[iolf0][iraw+ndet+1]+raw[iolf1][iraw+ndet+1]; if( tmeas<1 ) continue; for( j=0; j<ndet; ++j ){ count = raw[iolf0][iraw+1+j] + raw[iolf1][iraw+1+j]; olf[ichop].VS[isub*ndet+j].push_back( x, count/tmeas/tstep ); } } } } NOlm::SelNew(); if( flag & 1 ){ NOlm::OloAdd(&olf[1]); } if( 1 ){ NOlm::OloAdd(&olf[0]); } }