///////////////////////////////////////////////// // // SUDS2SEGY 1.0 // // CREATED BY MARK GOLDMAN // // USGS, MENLO PARK // // MARCH, 2000 // // C++ PROGRAM // // MAY NEED TO MODIFY CONSTANTS IF INPUT FILE FORMAT CHANGES // ///////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #include #include // MAIN PROGRAM main(int argc, char** argv) { // DECLARE CONSTANTS const int NUMBER_HEADER_KEYWORDS = 3; // READ IN THESE HEADER VALUES FROM SUDS2ASC FILES const int HEADER_TIME_INDEX = 0; const int HEADER_NSAMP_INDEX = 1; const int HEADER_SAMPRATE_INDEX = 2; // HEADER KEYWORDS ARRAY // HEADER KEYWORDS FROM SUDS2ASC FILES const char* H[NUMBER_HEADER_KEYWORDS] = { "initial sample time", "number of samples", "samples per second", }; const int NUMBER_COMPONENTS = 3; // THREE COMPONENTS: N, E, V const char* HEADER_LAST_KEYWORD = "rate correction"; // KEYWORD SIGNIFIES END OF HEADER // INFORMATION, NEXT LINE STARTS DATA const int TABLE_FILENAME_WORD = 1; // READ IN THESE HEADER VALUES FROM TABLE FILE const int TABLE_STATION_WORD = 2; const int TABLE_OFFSET_WORD = 3; // USER-GIVEN INPUT DIRECTORY VARIABLES char inputDirectory[100]; // INPUT DIRECTORY DIR* dir; struct dirent* dirEntry; char* inputFilename; // INPUT FILENAME FROM INPUT DIRECTORY char prefixFilename[100]; // INPUT FILENAME UP TO FIRST "." char fullFilename[100]; // INPUT FULL FILENAME ( DIRECTORY/FILENAME ) // USER-GIVEN FILENAME VARIABLES char tableFilename[100]; char reportFilename[100]; char diagFilename[100]; char segyFilename[100]; // USER-GIVEN DATA SAMPLE VARIABLES char uStartTime[100]; // USER-GIVEN TIME STRING int uHour; // CALCULATED FROM TIME STRING int uMinute; // CALCULATED FROM TIME STRING float uSecond; // CALCULATED FROM TIME STRING float uTime; // TIME IN SECONDS, CALCULATED FROM TIME STRING int uNsamp; // NUMBER OF SAMPLES PER TRACE IN OUTPUT SEGY FILE // TRACE HEADER VARIABLES char tFilename[100]; // INPUT FILENAME FROM TABLE FILE char tStationName[100];// FULL STATION NAME FROM TABLE FILE int tOffset; // OFFSET FROM TABLE FILE, IN METERS int hSampRate; // SAMPLE RATE FROM INPUT FILE HEADER char hStartTime[100]; // TIME STRING FROM INPUT FILE HEADER int hHour; // CALCULATED FROM TIME STRING int hMinute; // CALCULATED FROM TIME STRING float hSecond; // CALCULATED FROM TIME STRING float hTime; // TIME IN SECONDS, CALCULATED FROM TIME STRING int hNsamp; // NUMBER OF SAMPLES PER TRACE IN INPUT SUDS2ASC FILE // TRACE COUNTING VARIABLES int ffid; int chan; int trace; // SAMPLE COUNTING VARIABLES int samplesRead; // TOTAL NUMBER SAMPLES READ FROM INPUT SUDS2ASC FILE, // INCLUDING TRUNCATED DATA SAMPLES int samplesUsed; // NUMBER DATA SAMPLES ACTUALLY USED FROM INPUT FILE // (IE. OUTPUT TO TRACE IN SEGY FILE) int samplesWritten; // TOTAL NUMBER SAMPLES OUTPUT TO TRACE IN SEGY FILE // INCLUDING PADDED DUMMY SAMPLES int padStart; // NUMBER DUMMY SAMPLES TO PAD AT START OF TRACE IN OUPTUT SEGY FILE int padEnd; // NUMBER DUMMY SAMPLES TO PAD AT END OF TRACE IN OUTPUT SEGY FILE int truncStart; // NUMBER DATA SAMPLES TO TRUNCATE FROM START OF TRACE IN SUDS2ASC FILE int truncEnd; // NUMBER DATA SAMPLES TO TRUNCATE FROM END OF TRACE IN SUDS2ASC FILE int maxAmp[NUMBER_COMPONENTS]; // MAXIMUM AMPLITUDE PER COMPONENT int maxSamp[NUMBER_COMPONENTS]; // SAMPLE NUMBER WHERE MAXIMUM AMPLITUDE OCCURS // STREAM VARIABLES ifstream in; ifstream tin; ofstream sout; ofstream rout; ofstream dout; // MISC VARIABLES char input[500]; char input2[500]; char word[200]; int dataFlag; int index; // BINARY VALUE VARIABLES int value; short svalue; char dummy[3600]; // DECLARE SUBROUTINES void getWord(char* word, const char* input, const int n); int parseTime(const char* startTime, int& hour, int& minute, float& second, float& time); char* createTime(char* startTime, const int& hour, const int& minute, const float& second); char* formatTime(const char* startTime, char* output); char* addTime(const float sample, const int samprate, const char* input, char* output); // CHECK ARGUMENTS if (argc != 8) { cout << endl; cout << argv[0] << " reads in input SUDS2ASC files from an input directory," << endl; cout << "adds in station and offset information from a table file," << endl; cout << "converts the input files to a single SEGY file," << endl; cout << "and creates a report file and a diagnostics file" << endl; cout << endl; cout << "NOTE: only SUDS2ASC files should exist in the input directory" << endl; cout << endl; cout << "format: " << argv[0] << " inputDirectory tableFilename SEGYfilename "; cout << "reportFilename diagFilename startTime SamplesPerTrace" << endl; cout << endl; cout << "example: " << argv[0] << " Input table output report diag "; cout << "17:47:12.60 20000" << endl; cout << endl; exit(1); } // INITIALIZE DUMMY VARIABLE for (int i = 0; i < 3600; i++) dummy[i] = '\0'; // COPY ARGUMENTS TO VARIABLES strcpy(inputDirectory, argv[1]); strcpy(tableFilename, argv[2]); strcpy(segyFilename, argv[3]); strcpy(reportFilename, argv[4]); strcpy(diagFilename, argv[5]); strcpy(uStartTime, argv[6]); uNsamp = atoi( argv[7]); // CHECK NUMBER OF SAMPLES if (uNsamp < 1) { cout << "ERROR: SamplesPerTrace argument too small" << endl; exit(1); } if (uNsamp >= 32000) { cout << "ERROR: SamplesPerTrace argument cannot be >= 32000" << endl; exit(1); } // PARSE STARTING TIME if ( parseTime(uStartTime, uHour, uMinute, uSecond, uTime) == 1) { cout << "ERROR: could not parse startTime argument: " << uStartTime << endl; cout << " argument must have form:" << endl; cout << " hour:minute:seconds, where seconds can be floating point" << endl; exit(1); } // OPEN THE INPUT TABLE FILE tin.open(tableFilename); if ( !tin ) { cout << endl << "ERROR: cannot open table file " << tableFilename << endl; exit(1); } // OPEN THE OUTPUT SEGY FILE sout.open(segyFilename); if ( !sout ) { cout << endl << "ERROR: cannot create SEGY file " << segyFilename << endl; exit(1); } // OPEN THE OUTPUT REPORT FILE // AND WRITE INITAL LINES rout.open(reportFilename); if ( !rout ) { cout << endl << "ERROR: cannot create report file " << reportFilename << endl; exit(1); } rout << " Event Start Time: " << uStartTime << " All Traces In SEGY File Contain " << uNsamp << " samples" << endl << endl; rout << setw(10) << "filename" << setw(6) << "FFID" << setw(10) << "offset" << setw(8) << "max 1" << setw(8) << "max 2" << setw(8) << "max 3" << setw(14) << "time 1" << setw(14) << "time 2" << setw(14) << "time 3" << endl; // OPEN THE OUTPUT DIAGNOSTICS FILE // AND WRITE INITIAL LINES dout.open(diagFilename); if ( !dout ) { cout << endl << "ERROR: cannot create diagnostic file " << diagFilename << endl; exit(1); } dout << " Event Start Time: " << uStartTime << " All Traces In SEGY File Contain " << uNsamp << " samples" << endl << endl; // OPEN THE INPUT DIRECTORY if ( ( dir = opendir(inputDirectory) ) == NULL ) { cout << "cannot open directory: " << inputDirectory << endl; exit(1); } // INITIALIZE PROGRAM VARIABLES ffid = 1000; trace = 0; istrstream istr(input, 500); // FOR EACH FILE IN THE DIRECTORY while ( ( dirEntry = readdir(dir) ) != NULL ) { // GET FILENAME inputFilename = dirEntry->d_name; // MAKE SURE FILENAME DOES NOT START WITH "." if (inputFilename[0] == '.') continue; // GET FILENAME PREFIX char* pointer = strstr(inputFilename, "."); if (pointer != 0) { strncpy(prefixFilename, inputFilename, (pointer - inputFilename) ); prefixFilename[pointer - inputFilename] = '\0'; } else { strcpy(prefixFilename, inputFilename); } // OPEN INPUT FILE strcpy(fullFilename, inputDirectory); strcat(fullFilename, "/"); strcat(fullFilename, inputFilename); in.open(fullFilename); if ( !in ) { cout << endl << "ERROR: cannot open input file " << fullFilename << endl; exit(1); } // INITIALIZE FILE VARIABLES ffid++; trace++; chan = 0; padStart = 0; padEnd = 0; truncStart = 0; truncEnd = 0; // FOR EACH COMPONENT IN THE FILE for (int icomp = 0; icomp < NUMBER_COMPONENTS; icomp++) { // INITIALIZE COMPONENT VARIABLES chan++; samplesRead = 0; samplesWritten = 0; samplesUsed = 0; dataFlag = 0; index = 0; maxAmp[icomp] = 0; // CREATE LOOP TO READ IN LINES FROM FILE while (1) { // GET NEXT LINE FROM FILE in.getline(input, 500); // MAKE SURE NOT AT END OF FILE if ( !in ) { cout << "unexpected end of input file " << fullFilename << endl; exit(1); } // IF READING IN HEADER LINES if (dataFlag == 0) { // IF AT LAST HEADER LINE BEFORE DATA BEGINS if ( strstr(input, HEADER_LAST_KEYWORD) != 0 ) { // MAKE SURE ALL HEADER VALUES WERE READ IN if (index < NUMBER_HEADER_KEYWORDS) { cout << "ERROR: unable to read in headers for file " << fullFilename << endl; exit(1); } // IF AT FIRST COMPONENT if (icomp == 0) { // READ IN ADDITIONAL INFORMATION FROM TABLE FILE int readFlag = 0; while ( tin.getline(input2, 500) ) { getWord(tFilename, input2, TABLE_FILENAME_WORD); if ( strncasecmp( tFilename, prefixFilename, strlen(prefixFilename) ) == 0 ) { getWord(word, input2, TABLE_STATION_WORD); strcpy(tStationName, word); getWord(word, input2, TABLE_OFFSET_WORD); tOffset = (int)(atof(word) * 1000.0); if (tOffset < 1) { cout << "ERROR: offset value in table file is less than 1" << endl; exit(1); } readFlag = 1; break; } } if (readFlag == 0) { cout << "ERROR: could not find file " << inputFilename << " in table file " << tableFilename << endl; exit(1); } tin.clear(); tin.seekg(0); // GIVE MESSAGE cout << "input file " << setw(20) << fullFilename << " has " << setw(6) << hNsamp << " samples, starting at time " << hStartTime << endl; // END OF "IF AT FIRST COMPONENT" } // IF VERY FIRST TRACE, THEN WRITE 3600-BYTE FILE HEADER if (ffid == 1001 && chan == 1) { sout.write( dummy, 3212 ); svalue = NUMBER_COMPONENTS; sout.write( (char*)&svalue, 2); svalue = 0; sout.write( (char*)&svalue, 2); svalue = 1000000/hSampRate; sout.write( (char*)&svalue, 2); svalue = 1000000/hSampRate; sout.write( (char*)&svalue, 2); svalue = uNsamp; sout.write( (char*)&svalue, 2); svalue = uNsamp; sout.write( (char*)&svalue, 2); svalue = 2; sout.write( (char*)&svalue, 2); sout.write( dummy, 374 ); } // WRITE 240-BYTE TRACE HEADER value = trace; sout.write( (char*)&value, 4); value = trace; sout.write( (char*)&value, 4); value = ffid; sout.write( (char*)&value, 4); value = chan; sout.write( (char*)&value, 4); sout.write( dummy, 12); svalue = 1; sout.write( (char*)&svalue, 2); sout.write( dummy, 6); value = tOffset; sout.write( (char*)&value, 4); sout.write( dummy, 28); svalue = 1; sout.write( (char*)&svalue, 2); svalue = 1; sout.write( (char*)&svalue, 2); sout.write( dummy, 16); sout.write( dummy, 26); svalue = uNsamp; sout.write( (char*)&svalue, 2); svalue = 1000000/hSampRate; sout.write( (char*)&svalue, 2); sout.write( dummy, 42); svalue = uHour; sout.write( (char*)&svalue, 2); svalue = uMinute; sout.write( (char*)&svalue, 2); svalue =(int)uSecond; sout.write( (char*)&svalue, 2); svalue = 2; sout.write( (char*)&svalue, 2); svalue = 0; sout.write( (char*)&svalue, 2); sout.write( dummy, 70); // IF FIRST COMPONENT THEN SET SAMPLE VARIABLES // LOOK FOR SPECIAL CASES: // NUMBER PADDED SAMPLES AT START >= NUMBER OUTPUT SAMPLES // NUMBER TRUNCATED SAMPLES AT START >= NUMBER INPUT SAMPLES if (icomp == 0) { double timeDiff = uTime - hTime; if (timeDiff > 0.0) { truncStart = (int)( (1.0 * timeDiff) * (float)hSampRate + 0.5); if (truncStart > hNsamp) truncStart = hNsamp; } else if (timeDiff < 0.0) { padStart = (int)( (-1.0 * timeDiff) * (float)hSampRate + 0.5); if (padStart > uNsamp) padStart = uNsamp; } truncEnd = hNsamp - uNsamp + padStart - truncStart; if (truncEnd < 0) truncEnd = 0; if (truncEnd > hNsamp) truncEnd = hNsamp; if (padStart == uNsamp) truncEnd = hNsamp; padEnd = uNsamp - hNsamp - padStart + truncStart; if (padEnd < 0) padEnd = 0; if (padEnd > uNsamp) padEnd = uNsamp; if (truncStart == hNsamp) padEnd = uNsamp; if (padStart == uNsamp) cout << "WARNING: for file " << fullFilename << ", first sample occurs too far " << "beyond user-supplied start time to be valid" << endl; if (truncStart == hNsamp) cout << "WARNING: for file " << fullFilename << ", last sample occurs before user-supplied start time" << endl; } // WRITE DUMMY SAMPLES IF NEEDED value = 0; for (int i = 0; i < padStart; i++) { sout.write( (char*)&value, 4); samplesWritten++; } // SET DATA FLAG TO ONE AND READ IN NEXT LINE FROM FILE dataFlag = 1; continue; // END OF "IF AT LAST HEADER LINE BEFORE DATA BEGINS" } // IF AT CURRENT KEYWORD HEADER LINE if ( strstr(input, H[index]) != 0 ) { // FOR STARTING_TIME HEADER // IF NOT FIRST COMPONENT THEN // MAKE SURE HEADER VALUE MATCHES PREVIOUS VALUE if (index == 0) { getWord(word, input, 2); if (icomp == 0) { strcpy(hStartTime, word); parseTime(hStartTime, hHour, hMinute, hSecond, hTime); } else { if ( strcmp(hStartTime, word) != 0 ) { cout << "file " << fullFilename << " has varying start_time header values" << " among components" << endl; exit(1); } } } // FOR NUMBER_OF_SAMPLES HEADER // IF NOT FIRST COMPONENT THEN // MAKE SURE HEADER VALUE MATCHES PREVIOUS VALUE if (index == 1) { getWord(word, input, 1); if ( atoi(word) == 0 ) { cout << "ERROR: could not read number_of_samples value from file " << fullFilename << endl; exit(1); } if (icomp == 0) { hNsamp = atoi(word); } else { if ( hNsamp != atoi(word) ) { cout << "file " << fullFilename << " has varying number_of_samples header values" << " among components" << endl; exit(1); } } } // FOR SAMPLE_RATE HEADER // IF NOT VERY FIRST TRACE THEN // MAKE SURE HEADER VALUE MATCHES PREVIOUS VALUE if (index == 2) { getWord(word, input, 1); int testSampRate = atoi(word); if ( testSampRate == 0 ) { cout << "ERROR: could not read sample_rate value from file " << fullFilename << endl; exit(1); } if (ffid == 1001 && chan == 1) { hSampRate = testSampRate; } else { if ( testSampRate != hSampRate ) { cout << "file " << fullFilename << " has a different sample_rate header value" << " from other files" << endl; exit(1); } } } // INCREMENT INDEX index++; // END OF "IF AT CURRENT KEYWORD HEADER LINE" } // END OF "IF READING IN HEADER LINES" } // ELSE IF READING IN DATA LINES else { // CHECK IF AT END OF DATA if (input[0] == 13 || input[0] == '\0') break; // PARSE DATA LINE while ( (istr >> value).good() ) { // READ DATA SAMPLE VALUE samplesRead++; // CHECK IF TRUNCATING SAMPLE if ( ( samplesRead <= truncStart ) || ( samplesRead > (hNsamp - truncEnd) ) ) continue; // WRITE DATA SAMPLE VALUE sout.write( (char*)&value, 4); samplesWritten++; samplesUsed++; // CHECK IF MAXIMUM AMPLITUDE if ( abs(value) > maxAmp[icomp] ) { maxAmp[icomp] = abs(value); maxSamp[icomp] = samplesRead; } } istr.clear(); istr.seekg(0); // END OF "IF READING IN DATA LINES" } // END OF WHILE LOOP TO READ IN LINES FROM FILE } // WRITE DUMMY SAMPLES IF NEEDED value = 0; for (int i = 0; i < padEnd; i++) { sout.write( (char*)&value, 4); samplesWritten++; } // CHECK THAT PROPER NUMBER OF SAMPLES READ/WRITTEN if (samplesRead != hNsamp) { cout << "ERROR: only read " << samplesRead << " out of " << hNsamp << " samples from file " << fullFilename << endl; // exit(1); } if (samplesWritten != uNsamp) { cout << "ERROR: only wrote " << samplesWritten << " out of " << uNsamp << " needed samples for file " << fullFilename << endl; // exit(1); } if (samplesUsed != (hNsamp - truncStart - truncEnd) ) { cout << "ERROR: only used " << samplesUsed << " out of " << (hNsamp - truncStart - truncEnd) << " valid data samples (ie. non-truncated samples) " << " for file " << fullFilename << endl; // exit(1); } // END OF "FOR EACH COMPONENT IN FILE" } // WRITE LINE TO REPORT FILE rout << setw(10) << prefixFilename << setw(6) << ffid << setw(10) << tOffset << setw(8) << maxAmp[0] << setw(8) << maxAmp[1] << setw(8) << maxAmp[2] << setw(14) << addTime( maxSamp[0], hSampRate, hStartTime, input2 ) << setw(14) << addTime( maxSamp[1], hSampRate, hStartTime, input2 ) << setw(14) << addTime( maxSamp[2], hSampRate, hStartTime, input2 ) << endl; // WRITE LINE TO DIAGNOSTICS FILE dout << prefixFilename << ", "; dout << formatTime(hStartTime, input) << ", "; if (truncStart > 0) dout << "skipped " << setw(6) << truncStart << " samples, "; if (padStart > 0) dout << " padded " << setw(6) << padStart << " samples, "; dout << "wrote " << setw(6) << samplesUsed << " samples"; if (truncEnd > 0) dout << ", skipped " << setw(6) << truncEnd << " samples"; if (padEnd > 0) dout << ", padded " << setw(6) << padEnd << " samples"; dout << endl; // CLOSE INPUT FILE in.close(); // END OF "FOR EACH FILE IN THE DIRECTORY" } // CLEANUP tin.close(); sout.close(); rout.close(); closedir(dir); // END OF MAIN PROGRAM } // SUBROUTINE TO GET Nth WORD FROM STRING void getWord(char* word, const char* input, const int n) { int j = 0; int count = 0; int flag = 1; strcpy(word,""); for (int i = 0; i < strlen(input); i++) { if ( !isspace(input[i]) ) { if (flag == 1) count++; flag = 0; if (count == n) word[j++] = input[i]; } else if ( isspace(input[i]) && flag == 0 ) { flag = 1; if (count >= n) break; } } word[j] = '\0'; } // SUBROUTINE TO PARSE START_TIME INTO HOUR, MINUTE, SECOND int parseTime(const char* startTime, int& hour, int& minute, float& second, float& time) { istrstream istr(startTime, strlen(startTime) + 1); char d; istr >> hour >> d >> minute >> d >> second; time = (float)(hour * 3600 + minute * 60) + second; if (! istr.good() ) return 1; else return 0; } // SUBROUTINE TO CREATE START_TIME FROM HOUR, MINUTE, SECOND char* createTime(char* startTime, const int& hour, const int& minute, const float& second) { ostrstream ostr(startTime, 100); ostr << setw(2) << setfill('0') << hour << ":" << setw(2) << setfill('0') << minute << ":"; ostr.setf(ios::fixed, ios::floatfield); ostr << setw(5) << setfill('0') << setprecision(2) << second; ostr << ends; return startTime; } // SUBROUTINE TO FORMAT TIME char* formatTime(const char* startTime, char* output) { int hour; int minute; float second; float time; parseTime(startTime, hour, minute, second, time); createTime(output, hour, minute, second); return output; } // SUBROUTINE TO ADD SECONDS TO CURRENT TIME char* addTime(const float sample, const int sampRate, const char* input, char* output) { int hour; int minute; float second; float time; parseTime(input, hour, minute, second, time); second += sample / sampRate; minute += (int)second / 60; hour += minute / 60; hour -= 24 * (hour / 24); minute -= 60 * (minute / 60); second -= (float)( 60 * (int)(second / 60) ); createTime(output, hour, minute, second); return output; }