[gmx-developers] How to get the number of frames contained by an .xtc trajectory file??
Mirco Wahab
mirco.wahab at chemie.tu-freiberg.de
Wed Jun 6 00:49:28 CEST 2012
Hi Tsjerk,
> If you have a small C program for calculating the number of
> frames, please do post it. It might be interesting for others.
I tried a crude, but self-contained tool some time ago that never
really worked, but after your nice posting (python script) on this
topic I was able to make it work reliably. Maybe it's of use for something.
Regards and thanks for your hints,
M.
==> xtcplay.cxx
-------------- next part --------------
/*
[2012-06-06]
== Version 0.01
= XTCPLAY - play around w/Gromacs xtc trajectory files
= self-contained, no xtc lib - works on LITTLE ENDIAN machines (Intel, AMD)
= xtc_brute_force_scan() -> prints file offsets of every frame in the xtc
= xtc_dump_last_frame() -> displays various xtc info and writes last frame
= written after reading a usenet posting from Tsjerk Wassenaar
= C++ with minimal error handling, just for demonstration
= tested with MSVC11/Win64 and gcc 4.3.4/x64 ( g++ xtcplay.cxx -o xtcplay)
= please send error info or improvements to mirco.wahab at chemie.tu-freiberg.de
*/
// if Intel, AMD etc., see
// http://en.wikipedia.org/wiki/Endianness#Endianness_and_operating_systems_on_architectures
#define _LSB_FIRST_ 1
// otherwise:
// #define _MSB_FIRST_ 1
#include <stdint.h>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int xtc_brute_force_scan(const string& fname);
int xtc_dump_last_frame(const string& fname);
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
int main(int argc, char* argv[])
{
string fname(argv[1]);
// int status = xtc_brute_force_scan(fname);
int status = xtc_dump_last_frame(fname);
return status;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
uint32_t u4_from_buffer(char b[])
{
#if defined(_LSB_FIRST_)
return uint8_t(b[3]) << 0 | uint8_t(b[2]) << 8
| uint8_t(b[1]) << 16 | uint8_t(b[0]) << 24 ;
#else
return * (uint32_t*) b; // is this correct? I don't have a MSB first machine
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
int64_t find_xtc_frame_tag(char *block, int64_t len1, char *tag)
{
char *p=block, *q=block+len1, *t=tag;
while(p < q) { // unrolled for speed
if( *(p+0) == *(t+0) && *(p+1) == *(t+1) && *(p+2) == *(t+2)
&& *(p+3) == *(t+3) && *(p+4) == *(t+4) && *(p+5) == *(t+5)
&& *(p+6) == *(t+6) && *(p+7) == *(t+7) )
return p-block;
++p;
}
return -1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
int xtc_brute_force_scan(const string& fn)
{
// read the whole xtc to memory - can your box handle this?
ifstream fd;
fd.open(fn.c_str(), ios::binary);
if(!fd.is_open()) {
perror(fn.c_str());
exit(1);
}
fd.seekg(0, ios_base::end);
streamsize flen = fd.tellg();
fd.seekg(0, ios_base::beg);
cout << "FILE SIZE = " << flen/(1024*1024) << " MB\nFRAME\tOFSETT" << endl;
char *buf = new char[size_t(flen)];
if(buf == NULL) {
cerr << "out of memory" << endl;
exit(1);
}
fd.read(buf, flen);
streamsize rdlen = fd.gcount();
if(rdlen) {
streamsize cnt=0, pos=0, offs=0;
while( (pos=find_xtc_frame_tag(buf+offs, rdlen-offs, buf)) != -1 ) {
cnt++;
cout << dec << cnt << "\t" << (pos+offs) << "/" << flen
<< "\t(0x" << hex << (pos+offs) << ")" << endl;
offs += pos+92;
}
cout << "TOTAL = " << dec << cnt << " FRAMES" << endl;
}
else {
cerr << "short read" << endl;
exit(1);
}
delete [] buf;
fd.close();
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
int xtc_dump_last_frame(const string& fn)
{
ifstream fd;
fd.open(fn.c_str(), ios::binary);
if(!fd.is_open()) {
perror(fn.c_str());
exit(1);
}
char header[92];
fd.read(header, 92);
uint32_t magic = u4_from_buffer(header); // 1995
uint32_t natom = u4_from_buffer(header+4); // natoms
uint32_t frmsz = 92 + u4_from_buffer(header+88); // framesize
cout << "FILE=" << fn.c_str() << ", MAGIC=" << magic
<< ", NATOMS=" << natom << ", FRAMESIZE=" << frmsz << " BYTES, " ;
streamsize offs = frmsz + (frmsz/4); // guess last frame position
fd.seekg(-offs, ios_base::end); // move read pointer up there
streamsize fpos = fd.tellg();
streamsize nframes = fpos/frmsz+1;
cout << "NFRAMES=" << nframes << endl;
char *rdbuf = new char [size_t(offs+1)]; // prepare load of last frame
fd.read(rdbuf, offs+1); // read last block from file
streamsize rdlen = fd.gcount();
fd.close();
// find frame start
int64_t pos = find_xtc_frame_tag(rdbuf, rdlen, header);
if(pos == -1) {
cerr << "error: no frame header found for last frame" << endl;
return 1;
}
cout << "write last frame of " << nframes << " (" << (rdlen-pos)
<< " bytes)" << endl;
string fname = "lastframe_" + fn;
ofstream fh(fname.c_str(), ios::binary);
fh.write(rdbuf+pos, rdlen-pos);
fh.close();
delete [] rdbuf;
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
More information about the gromacs.org_gmx-developers
mailing list