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: Molecule.C,v $ 00013 * $Author: johns $ $Locker: $ $State: Exp $ 00014 * $Revision: 1.92 $ $Date: 2019年01月17日 21:21:00 $ 00015 * 00016 *************************************************************************** 00017 * DESCRIPTION: 00018 * 00019 * Main Molecule objects, which contains all the capabilities necessary to 00020 * store, draw, and manipulate a molecule. This adds to the functions of 00021 * DrawMolecule and BaseMolecule by adding routines to read and write various 00022 * coordinate files. 00023 * 00024 * Note: Other capabilities, such as writing structure files, mutations, etc. 00025 * should go into this level. 00026 * 00027 ***************************************************************************/ 00028 00029 #include "Molecule.h" 00030 #include "Inform.h" 00031 #include "DisplayDevice.h" 00032 #include "TextEvent.h" 00033 #include "VMDApp.h" 00034 #include "CommandQueue.h" 00035 #include "CoorData.h" 00036 00038 00039 Molecule::Molecule(const char *src, VMDApp *vmdapp, Displayable *d) 00040 : DrawMolecule(vmdapp, d), coorIOFiles(8) { 00041 00042 char *strPath = NULL, *strName = NULL; 00043 breakup_filename(src, &strPath, &strName); 00044 if (!strName) strName = stringdup("unknown"); 00045 00046 // set the molecule name 00047 moleculename = stringdup(strName); 00048 delete [] strPath; 00049 delete [] strName; 00050 } 00051 00053 Molecule::~Molecule(void) { 00054 int i; 00055 00056 // Disconnect this molecule from IMD, if it's active 00057 app->imd_disconnect(id()); 00058 00059 while(coorIOFiles.num() > 0) { 00060 delete coorIOFiles[0]; 00061 coorIOFiles.remove(0); 00062 } 00063 00064 if (moleculename) 00065 delete [] moleculename; 00066 00067 for (i=0; i<fileList.num(); i++) { 00068 delete [] fileList[i]; 00069 } 00070 for (i=0; i<fileSpecList.num(); i++) { 00071 delete [] fileSpecList[i]; 00072 } 00073 for (i=0; i<typeList.num(); i++) { 00074 delete [] typeList[i]; 00075 } 00076 for (i=0; i<dbList.num(); i++) { 00077 delete [] dbList[i]; 00078 } 00079 for (i=0; i<accessionList.num(); i++) { 00080 delete [] accessionList[i]; 00081 } 00082 for (i=0; i<remarksList.num(); i++) { 00083 delete [] remarksList[i]; 00084 } 00085 } 00086 00088 00089 int Molecule::rename(const char *newname) { 00090 delete [] moleculename; 00091 moleculename = stringdup(newname); 00092 return 1; 00093 } 00094 00095 void Molecule::add_coor_file(CoorData *data) { 00096 coorIOFiles.append(data); 00097 } 00098 00099 void Molecule::close_coor_file(CoorData *data) { 00100 // remove file from list 00101 msgInfo << "Finished with coordinate file " << data->name << "." << sendmsg; 00102 00103 // Must be appended, not run, because callbacks could delete the molecule! 00104 app->commandQueue->append( 00105 new TrajectoryReadEvent(id(), data->name) 00106 ); 00107 00108 delete data; 00109 } 00110 00111 // cancel load/save of coordinate files 00112 // return number canceled 00113 int Molecule::cancel() { 00114 int retval = 0; 00115 while(coorIOFiles.num() > 0) { 00116 msgInfo << "Canceling load/save of file: " << coorIOFiles[0]->name 00117 << sendmsg; 00118 delete coorIOFiles[0]; 00119 coorIOFiles.remove(0); 00120 retval++; 00121 } 00122 return retval; 00123 } 00124 00125 int Molecule::get_new_frames() { 00126 int newframes = 0; 00127 00128 // add a new frame if there are frames available in the I/O queue 00129 if (next_frame()) 00130 newframes = 1; 00131 00132 // If an IMD simulation is in progress, store the forces in the current 00133 // timestep and send them to the simulation. Otherwise, just toss them. 00134 if (app->imd_connected(id())) { 00135 // Add persistent forces to regular forces 00136 force_indices.appendlist(&persistent_force_indices[0], persistent_force_indices.num()); 00137 force_vectors.appendlist(&persistent_force_vectors[0], persistent_force_vectors.num()); 00138 00139 // Clear old forces out of the timestep 00140 Timestep *ts = current(); 00141 if (ts && ts->force) { 00142 memset(ts->force, 0, 3L*nAtoms*sizeof(float)); 00143 } 00144 00145 // Check for atoms forced last time that didn't show up this time. 00146 // XXX order N^2 in number of applied forces; could be easily improved. 00147 // But N now is usually 1 or 2. 00148 ResizeArray<int> zero_force_indices; 00149 ResizeArray<float> zero_forces; 00150 00151 int forcecnt = force_indices.num(); // save in local var for speed 00152 00153 int ii; 00154 for(ii=0; ii<last_force_indices.num(); ii++) { 00155 int j; 00156 int index_missing=1; 00157 for (j=0; j<forcecnt; j++) { 00158 if (force_indices[j]==last_force_indices[ii]) { 00159 index_missing=0; 00160 break; 00161 } 00162 } 00163 if (index_missing) { 00164 // this one didn't show up this time 00165 zero_force_indices.append(last_force_indices[ii]); 00166 zero_forces.append3(0, 0, 0); 00167 } 00168 } 00169 00170 if (zero_force_indices.num()) { 00171 // There some atoms forced last time that didn't show up this time. 00172 app->imd_sendforces(zero_force_indices.num(), &(zero_force_indices[0]), 00173 &(zero_forces[0])); 00174 } 00175 00176 // now clear the last forces so we don't send them again 00177 last_force_indices.clear(); 00178 00179 // Set/send forces if we got any 00180 if (forcecnt) { 00181 if (ts) { 00182 if (!ts->force) { 00183 ts->force = new float[3L*nAtoms]; 00184 memset(ts->force, 0, 3L*nAtoms*sizeof(float)); 00185 } 00186 for (int i=0; i<forcecnt; i++) { 00187 int ind = force_indices[i]; 00188 ts->force[3L*ind ] += force_vectors[3L*i ]; 00189 ts->force[3L*ind+1] += force_vectors[3L*i+1]; 00190 ts->force[3L*ind+2] += force_vectors[3L*i+2]; 00191 } 00192 } 00193 // XXX If we send multiple forces for the same atom, NAMD will keep only 00194 // the last force. We therefore have to sum multiple contributions to the 00195 // same atom before sending. Annoying. 00196 ResizeArray<float> summed_forces; 00197 int i; 00198 for (i=0; i<forcecnt; i++) { 00199 int ind = force_indices[i]; 00200 summed_forces.append3(&ts->force[3L*ind]); 00201 } 00202 app->imd_sendforces(forcecnt, &(force_indices[0]), &(summed_forces[0])); 00203 00204 // save the force indices before clearing them 00205 last_force_indices.appendlist(&force_indices[0], force_indices.num()); 00206 00207 // now clear the force indices 00208 force_indices.clear(); 00209 force_vectors.clear(); 00210 } 00211 } 00212 00213 // Inform the top level class that background processing 00214 // is going on to prevent the CPU throttling code from activating 00215 if (newframes > 0) 00216 app->background_processing_set(); 00217 00218 return newframes; 00219 } 00220 00221 int Molecule::next_frame() { 00222 CoorData::CoorDataState state = CoorData::DONE; 00223 00224 while (coorIOFiles.num() > 0) { 00225 // R/W'ing file, do frames until DONE is returned (then close) 00226 state = coorIOFiles[0]->next(this); 00227 00228 if (state == CoorData::DONE) { 00229 close_coor_file(coorIOFiles[0]); 00230 coorIOFiles.remove(0); 00231 } else { 00232 break; // we got a frame, return to caller; 00233 } 00234 } 00235 00236 return (state == CoorData::NOTDONE); 00237 } 00238 00239 // prepare for drawing ... can do one or more of the following: 00240 // - open a new file and start reading 00241 // - continue reading an already open file 00242 // - finish reading a file and close it 00243 // - always add a new frame if there are frames available 00244 // when done, this then 'prepares' the parent class 00245 void Molecule::prepare() { 00246 get_new_frames(); // add a new frame if there are frames available 00247 DrawMolecule::prepare(); // do prepare for parent class 00248 } 00249 00250 void Molecule::addForce(int theatom, const float *f) { 00251 force_indices.append(theatom); 00252 force_vectors.append3(&f[0]); 00253 } 00254 00255 void Molecule::addPersistentForce(int theatom, const float *f) { 00256 // reset the force on this atom if any are stored 00257 // remove it completely if <f> is (0,0,0) 00258 00259 float mag2 = f[0]*f[0] + f[1]*f[1] + f[2]*f[2]; 00260 int ind = persistent_force_indices.find(theatom); 00261 if (ind < 0) { 00262 if (mag2 > 0) { 00263 // only set if non-zero 00264 reset_disp_list(); 00265 persistent_force_indices.append(theatom); 00266 persistent_force_vectors.append3(&f[0]); 00267 } 00268 } else { 00269 if (mag2 > 0) { 00270 reset_disp_list(); 00271 for (int i=0; i<3; i++) persistent_force_vectors[3L*ind+i] = f[i]; 00272 } else { 00273 // remove the persistent force (a zero will be sent automatically!) 00274 persistent_force_indices.remove(ind); 00275 00276 // remove same index three times since this is a ResizeArray 00277 // and it will shift elements down as they are removed... 00278 persistent_force_vectors.remove(3L*ind); 00279 persistent_force_vectors.remove(3L*ind); 00280 persistent_force_vectors.remove(3L*ind); 00281 } 00282 } 00283 } 00284