00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * RCS INFORMATION: 00011 * 00012 * $RCSfile: CoorPluginData.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.34 $ $Date: 2020年06月11日 08:17:38 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * Interface code that manages loading and saving of coordinate data via 00019 * plugin interfaces. Uses MolFilePlugin to do the file loading. 00020 ***************************************************************************/ 00021 00022 #include <stdio.h> 00023 #include <stdlib.h> 00024 #include <string.h> 00025 00026 #include "CoorPluginData.h" 00027 #include "MolFilePlugin.h" 00028 #include "Inform.h" 00029 #include "Molecule.h" 00030 #include "WKFUtils.h" 00031 00032 CoorPluginData::CoorPluginData(const char *nm, Molecule *m, MolFilePlugin *p, 00033 int input, int first, int stride, int last, const int *sel) 00034 : CoorData(nm), is_input(input), begFrame(first), frameSkip(stride), 00035 endFrame(last) { 00036 00038 selection = NULL; 00039 00041 plugin = NULL; 00042 00044 tm=NULL; 00045 00046 // ensure ts_page_alignment flag is cleared by default 00047 ts_page_align_sz=0; 00048 00050 kbytesperframe=0; 00051 totalframes=0; 00052 00053 // make sure frame data is correct 00054 if(begFrame < 0) 00055 begFrame = 0; 00056 if(endFrame < begFrame) 00057 endFrame = (-1); 00058 if(frameSkip <= 0) 00059 frameSkip = 1; 00060 recentFrame = -1; 00061 00062 // make sure frame data is valid 00063 if(!m || (!is_input && 00064 ( m->numframes() < begFrame || endFrame >= m->numframes() ) 00065 ) ) { 00066 msgErr << "Illegal frames requested for coordinate file I/O" << sendmsg; 00067 return; 00068 } 00069 if (is_input) { 00070 // Checks for and reject attempts to use selections when reading 00071 // coordinates. The most useful thing to do would be to allow coordinate 00072 // files to contain whatever number of atoms you want, and then use the 00073 // selection to filter those atoms. However, one could go a number of ways 00074 // with this. Should the selection be reparsed using the structure and/or 00075 // coordinate data in the new file in order to determine which atoms to 00076 // read, or should one simply use the already-computed atom indices? I can 00077 // think of situations where both of those behaviors would be desirable. 00078 if (sel) { 00079 msgErr << "Internal error: cannot read selection of coordinates" 00080 << sendmsg; 00081 return; 00082 } 00083 // make sure that the number of atoms in the coordinate file is either valid 00084 // or unknown. 00085 if (p->natoms() != m->nAtoms) { 00086 if (p->natoms() == -1) { 00087 p->set_natoms(m->nAtoms); 00088 } else { 00089 msgErr << "Incorrect number of atoms (" << p->natoms() << ") in" 00090 << sendmsg; 00091 msgErr << "coordinate file " << nm << sendmsg; 00092 msgErr << "Mismatch between existing molecule or structure file atom count and coordinate or trajectory file atom count." << sendmsg; 00093 return; 00094 } 00095 } 00096 } 00097 00098 // make plugin and selection information valid 00099 plugin = p; 00100 if (sel) { 00101 selection = new int[m->nAtoms]; 00102 memcpy(selection, sel, m->nAtoms * sizeof(int)); 00103 } 00104 00105 tm=wkf_timer_create(); 00106 wkf_timer_start(tm); 00107 00108 // If this is output, write the structure now. 00109 if (!is_input && plugin->can_write_structure()) { 00110 if (plugin->write_structure(m, selection) == MOLFILE_SUCCESS) { 00111 totalframes++; 00112 } else { 00113 plugin = NULL; 00114 } 00115 } 00116 00117 if (is_input) { 00118 kbytesperframe = (long(p->natoms()) * 12L) / 1024L; 00119 } else { 00120 kbytesperframe = (long(m->nAtoms) * 12L) / 1024L; 00121 } 00122 00123 // Check if VMD has to use page-aligned memory allocations for 00124 // timestep data, to allow for fast kernel-bypass unbuffered I/O APIs 00125 if (plugin->can_read_pagealigned_timesteps()) { 00126 #if vmdplugin_ABIVERSION > 17 00127 ts_page_align_sz = plugin->read_timestep_pagealign_size(); 00128 #else 00129 #if 1 00130 ts_page_align_sz = 1; // assume non-blocked I/O 00131 #else 00132 // Enable VMD to cope with hard-coded revs of jsplugin if we want 00133 ts_page_align_sz = MOLFILE_DIRECTIO_MAX_BLOCK_SIZE; 00134 #endif 00135 #endif 00136 } else { 00137 ts_page_align_sz = 1; // set page alignment flag to indicate normal I/O 00138 } 00139 } 00140 00141 CoorPluginData::~CoorPluginData() { 00142 delete plugin; 00143 plugin = NULL; 00144 00145 if (tm) { 00146 wkf_timer_destroy(tm); 00147 tm=NULL; 00148 } 00149 00150 delete [] selection; 00151 } 00152 00153 CoorData::CoorDataState CoorPluginData::next(Molecule *m) { 00154 if (!plugin) 00155 return DONE; 00156 00157 if (is_input) { 00158 if (recentFrame < 0) { 00159 recentFrame = 0; 00160 while (recentFrame < begFrame) { 00161 plugin->skip(m); 00162 recentFrame++; 00163 } 00164 } else { 00165 for (int i=1; i<frameSkip; i++) 00166 plugin->skip(m); 00167 recentFrame += frameSkip; 00168 } 00169 if (endFrame < 0 || recentFrame <= endFrame) { 00170 Timestep *ts = plugin->next(m, ts_page_align_sz); 00171 if (ts) { 00172 m->append_frame(ts); 00173 totalframes++; 00174 return NOTDONE; 00175 } 00176 } 00177 } else if (m->numframes() > 0) { // output 00178 if (recentFrame < 0) 00179 recentFrame = begFrame; 00180 else 00181 recentFrame += frameSkip; 00182 00183 // get next frame, and write to file 00184 if ((endFrame < 0 || recentFrame <= endFrame) 00185 && m->numframes() > recentFrame) { 00186 Timestep *ts = m->get_frame(recentFrame); 00187 if (ts) { 00188 if (!plugin->write_timestep(ts, selection)) { 00189 totalframes++; 00190 return NOTDONE; 00191 } else { 00192 msgErr << "write_timestep returned nonzero" << sendmsg; 00193 } 00194 } 00195 } 00196 } 00197 00198 if (tm != NULL && totalframes > 0) { 00199 double iotime = wkf_timer_timenow(tm); 00200 // emit I/O stats if requested, or it took more than 3 seconds 00201 if ((getenv("VMDTSTIMER") != NULL) || (iotime > 3.0)) { 00202 float framerate = (float) (((double) totalframes) / iotime); 00203 char tmbuf[1024], frameratebuf[1024]; 00204 sprintf(tmbuf, "%.1f", iotime); 00205 if (framerate > 10) 00206 sprintf(frameratebuf, "%.1f", framerate); 00207 else 00208 sprintf(frameratebuf, "%.2f", framerate); 00209 msgInfo << "Coordinate I/O rate " 00210 << frameratebuf << " frames/sec, " 00211 << (int) ((totalframes / iotime) * (kbytesperframe / 1024.0)) 00212 << " MB/sec, " 00213 << tmbuf << " sec" << sendmsg; 00214 } 00215 } 00216 00217 // we're done; close file and stop reading/writing 00218 delete plugin; 00219 plugin = NULL; 00220 return DONE; 00221 } 00222