void print_firstlast_selection(wkf_timerhandle timer, int n, int *on) { int sel, rc; wkf_timer_start(timer); rc = find_first_selection_aligned(n, on, &sel); wkf_timer_stop(timer); printf("first selection: %d time: %f\n", sel, wkf_timer_time(timer)); wkf_timer_start(timer); rc = find_last_selection_aligned(n, on, &sel); wkf_timer_stop(timer); printf("last selection: %d time: %f\n", sel, wkf_timer_time(timer)); }
/// return true if it's time to print a status update message int wkf_msg_timer_timeout(wkfmsgtimer *mt) { double elapsed = wkf_timer_timenow(mt->timer); if (elapsed > mt->updatetime) { // reset the clock and return true that our timer expired wkf_timer_start(mt->timer); return 1; } else if (elapsed < 0) { // time went backwards, best reset our clock! wkf_timer_start(mt->timer); } return 0; }
void print_analyze_selection(wkf_timerhandle timer, int n, int *on) { int first, last, selected; wkf_timer_start(timer); analyze_selection_aligned(n, on, &first, &last, &selected); wkf_timer_stop(timer); printf("selection stats: first %d last %d sel %d time: %f\n", first, last, selected, wkf_timer_time(timer)); }
/// initialize status message timer wkfmsgtimer * wkf_msg_timer_create(double updatetime) { wkfmsgtimer *mt; mt = (wkfmsgtimer *) malloc(sizeof(wkfmsgtimer)); if (mt != NULL) { mt->timer = wkf_timer_create(); mt->updatetime = updatetime; wkf_timer_start(mt->timer); } return mt; }
int main() { int i; float minfv[3], maxfv[3]; float minf, maxf; int isz = 100000000; int sz = 3 * isz; int *on = (int *) malloc(isz * sizeof(int)); float *fv = (float *) malloc(sz * sizeof(float)); for (i=0; i<sz; i++) fv[i] = (float) i; wkf_timerhandle timer = wkf_timer_create(); int j; for (j=0; j<1; j++) { memset(on, 0, isz*sizeof(int)); wkf_timer_start(timer); minmax_1fv_aligned(fv, sz, &minf, &maxf); wkf_timer_stop(timer); printf("minmax_1fv_aligned: %f\n", wkf_timer_time(timer)); // printf("min: %f max: %f\n", minf, maxf); wkf_timer_start(timer); minmax_3fv_aligned(fv, sz/3, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_3fv_aligned: %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } // set exactly one selected atom to measure perf of the // fast first/last selection traversal loops on[isz/2 + 7] = 1; print_firstlast_selection(timer, isz, on); print_analyze_selection(timer, isz, on); #if 1 wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 0%%): %f\n", wkf_timer_time(timer)); for (i=0; i<(isz-7); i+=8) { on[i+7] = 1; } print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 12%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } for (i=0; i<(isz-7); i+=8) { on[i+6] = 1; } print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 25%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } for (i=0; i<(isz-7); i+=8) { on[i+4] = 1; on[i+5] = 1; on[i+6] = 1; on[i+7] = 1; } print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 50%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } for (i=0; i<isz; i++) on[i] = 1; print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned(100%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } #endif msmparms mp; setupmsm(mp); wkf_timer_start(timer); testmsm(mp); wkf_timer_stop(timer); printf("MSM testmsm(): %f\n", wkf_timer_time(timer)); finishmsm(mp); printf("\n"); } wkf_timer_destroy(timer); printf("checking sum: %g\n", minf+maxf); return 0; }
int QuickSurf::calc_surf(AtomSel *atomSel, DrawMolecule *mol, const float *atompos, const float *atomradii, int quality, float radscale, float gridspacing, float isoval, const int *colidx, const float *cmap, VMDDisplayList *cmdList) { wkf_timer_start(timer); int colorperatom = (colidx != NULL && cmap != NULL); int usebeads=0; // clean up any existing CPU arrays before going any further... if (voltexmap != NULL) free(voltexmap); voltexmap = NULL; ResizeArray<float> beadpos(64 + (3 * atomSel->selected) / 20); ResizeArray<float> beadradii(64 + (3 * atomSel->selected) / 20); ResizeArray<float> beadcolors(64 + (3 * atomSel->selected) / 20); if (getenv("VMDQUICKSURFBEADS")) { usebeads=1; #if !defined(ARCH_BLUEWATERS) printf("QuickSurf using residue beads representation...\n"); #endif } int numbeads = 0; if (usebeads) { int i, resid, numres; // draw a bead for each residue numres = mol->residueList.num(); for (resid=0; resid<numres; resid++) { float com[3] = {0.0, 0.0, 0.0}; const ResizeArray<int> &atoms = mol->residueList[resid]->atoms; int numatoms = atoms.num(); int oncount = 0; // find COM for residue for (i=0; i<numatoms; i++) { int idx = atoms[i]; if (atomSel->on[idx]) { oncount++; vec_add(com, com, atompos + 3*idx); } } if (oncount < 1) continue; // exit if there weren't any atoms vec_scale(com, 1.0f / (float) oncount, com); // find radius of bounding sphere and save last atom index for color int atomcolorindex=0; // initialize, to please compilers float boundradsq = 0.0f; for (i=0; i<numatoms; i++) { int idx = atoms[i]; if (atomSel->on[idx]) { float tmpdist[3]; atomcolorindex = idx; vec_sub(tmpdist, com, atompos + 3*idx); float distsq = dot_prod(tmpdist, tmpdist); if (distsq > boundradsq) { boundradsq = distsq; } } } beadpos.append(com[0]); beadpos.append(com[1]); beadpos.append(com[2]); beadradii.append(sqrtf(boundradsq) + 1.0f); if (colorperatom) { const float *cp = &cmap[colidx[atomcolorindex] * 3]; beadcolors.append(cp[0]); beadcolors.append(cp[1]); beadcolors.append(cp[2]); } // XXX still need to add pick points... } numbeads = beadpos.num() / 3; } // initialize class variables isovalue=isoval; // If no volumetric texture will be computed we will use the cmap // parameter to pass in the solid color to be applied to all vertices vec_copy(solidcolor, cmap); // compute min/max atom radius, build list of selected atom radii, // and compute bounding box for the selected atoms float minx, miny, minz, maxx, maxy, maxz; float minrad, maxrad; int i; if (usebeads) { minx = maxx = beadpos[0]; miny = maxy = beadpos[1]; minz = maxz = beadpos[2]; minrad = maxrad = beadradii[0]; for (i=0; i<numbeads; i++) { int ind = i * 3; float tmpx = beadpos[ind ]; float tmpy = beadpos[ind+1]; float tmpz = beadpos[ind+2]; minx = (tmpx < minx) ? tmpx : minx; maxx = (tmpx > maxx) ? tmpx : maxx; miny = (tmpy < miny) ? tmpy : miny; maxy = (tmpy > maxy) ? tmpy : maxy; minz = (tmpz < minz) ? tmpz : minz; maxz = (tmpz > maxz) ? tmpz : maxz; // we always have to compute the rmin/rmax for beads // since these radii are defined on-the-fly float r = beadradii[i]; minrad = (r < minrad) ? r : minrad; maxrad = (r > maxrad) ? r : maxrad; } } else { minx = maxx = atompos[atomSel->firstsel*3 ]; miny = maxy = atompos[atomSel->firstsel*3+1]; minz = maxz = atompos[atomSel->firstsel*3+2]; // Query min/max atom radii for the entire molecule mol->get_radii_minmax(minrad, maxrad); // We only compute rmin/rmax for the actual group of selected atoms if // (rmax/rmin > 2.5) for the whole molecule, otherwise it's a small // enough range that we don't care since it won't hurt our performance. if (minrad <= 0.001 || maxrad/minrad > 2.5) { minrad = maxrad = atomradii[atomSel->firstsel]; for (i=atomSel->firstsel; i<=atomSel->lastsel; i++) { if (atomSel->on[i]) { int ind = i * 3; float tmpx = atompos[ind ]; float tmpy = atompos[ind+1]; float tmpz = atompos[ind+2]; minx = (tmpx < minx) ? tmpx : minx; maxx = (tmpx > maxx) ? tmpx : maxx; miny = (tmpy < miny) ? tmpy : miny; maxy = (tmpy > maxy) ? tmpy : maxy; minz = (tmpz < minz) ? tmpz : minz; maxz = (tmpz > maxz) ? tmpz : maxz; float r = atomradii[i]; minrad = (r < minrad) ? r : minrad; maxrad = (r > maxrad) ? r : maxrad; } } } else { for (i=atomSel->firstsel; i<=atomSel->lastsel; i++) { if (atomSel->on[i]) { int ind = i * 3; float tmpx = atompos[ind ]; float tmpy = atompos[ind+1]; float tmpz = atompos[ind+2]; minx = (tmpx < minx) ? tmpx : minx; maxx = (tmpx > maxx) ? tmpx : maxx; miny = (tmpy < miny) ? tmpy : miny; maxy = (tmpy > maxy) ? tmpy : maxy; minz = (tmpz < minz) ? tmpz : minz; maxz = (tmpz > maxz) ? tmpz : maxz; } } } } float mincoord[3], maxcoord[3]; mincoord[0] = minx; mincoord[1] = miny; mincoord[2] = minz; maxcoord[0] = maxx; maxcoord[1] = maxy; maxcoord[2] = maxz; // crude estimate of the grid padding we require to prevent the // resulting isosurface from being clipped float gridpadding = radscale * maxrad * 1.70f; float padrad = gridpadding; padrad = 0.65f * sqrtf(4.0f/3.0f*((float) VMD_PI)*padrad*padrad*padrad); gridpadding = MAX(gridpadding, padrad); // Handle coarse-grained structures and whole-cell models // XXX The switch at 4.0A from an assumed all-atom scale structure to // CG or cell models is a simple heuristic at a somewhat arbitrary // threshold value. // For all-atom models the units shown in the GUI are in Angstroms // and are absolute, but for CG or cell models the units in the GUI // are relative to the atom with the minimum radius. // This code doesn't do anything to handle structures with a minrad // of zero, where perhaps only one particle has an unset radius. if (minrad > 4.0f) { gridspacing *= minrad; } #if !defined(ARCH_BLUEWATERS) printf("QuickSurf: R*%.1f, I=%.1f, H=%.1f Pad: %.1f minR: %.1f maxR: %.1f)\n", radscale, isovalue, gridspacing, gridpadding, minrad, maxrad); #endif mincoord[0] -= gridpadding; mincoord[1] -= gridpadding; mincoord[2] -= gridpadding; maxcoord[0] += gridpadding; maxcoord[1] += gridpadding; maxcoord[2] += gridpadding; // compute the real grid dimensions from the selected atoms xaxis[0] = maxcoord[0]-mincoord[0]; yaxis[1] = maxcoord[1]-mincoord[1]; zaxis[2] = maxcoord[2]-mincoord[2]; numvoxels[0] = (int) ceil(xaxis[0] / gridspacing); numvoxels[1] = (int) ceil(yaxis[1] / gridspacing); numvoxels[2] = (int) ceil(zaxis[2] / gridspacing); // recalc the grid dimensions from rounded/padded voxel counts xaxis[0] = (numvoxels[0]-1) * gridspacing; yaxis[1] = (numvoxels[1]-1) * gridspacing; zaxis[2] = (numvoxels[2]-1) * gridspacing; maxcoord[0] = mincoord[0] + xaxis[0]; maxcoord[1] = mincoord[1] + yaxis[1]; maxcoord[2] = mincoord[2] + zaxis[2]; #if !defined(ARCH_BLUEWATERS) printf(" GridSZ: (%4d %4d %4d) BBox: (%.1f %.1f %.1f)->(%.1f %.1f %.1f)\n", numvoxels[0], numvoxels[1], numvoxels[2], mincoord[0], mincoord[1], mincoord[2], maxcoord[0], maxcoord[1], maxcoord[2]); #endif vec_copy(origin, mincoord); // build compacted lists of bead coordinates, radii, and colors float *xyzr = NULL; float *colors = NULL; if (usebeads) { int ind =0; int ind4=0; xyzr = (float *) malloc(numbeads * sizeof(float) * 4); if (colorperatom) { colors = (float *) malloc(numbeads * sizeof(float) * 4); // build compacted lists of bead coordinates, radii, and colors for (i=0; i<numbeads; i++) { const float *fp = &beadpos[0] + ind; xyzr[ind4 ] = fp[0]-origin[0]; xyzr[ind4 + 1] = fp[1]-origin[1]; xyzr[ind4 + 2] = fp[2]-origin[2]; xyzr[ind4 + 3] = beadradii[i]; const float *cp = &beadcolors[0] + ind; colors[ind4 ] = cp[0]; colors[ind4 + 1] = cp[1]; colors[ind4 + 2] = cp[2]; colors[ind4 + 3] = 1.0f; ind4 += 4; ind += 3; } } else { // build compacted lists of bead coordinates and radii only for (i=0; i<numbeads; i++) { const float *fp = &beadpos[0] + ind; xyzr[ind4 ] = fp[0]-origin[0]; xyzr[ind4 + 1] = fp[1]-origin[1]; xyzr[ind4 + 2] = fp[2]-origin[2]; xyzr[ind4 + 3] = beadradii[i]; ind4 += 4; ind += 3; } } } else { int ind = atomSel->firstsel * 3; int ind4=0; xyzr = (float *) malloc(atomSel->selected * sizeof(float) * 4); if (colorperatom) { colors = (float *) malloc(atomSel->selected * sizeof(float) * 4); // build compacted lists of atom coordinates, radii, and colors for (i=atomSel->firstsel; i <= atomSel->lastsel; i++) { if (atomSel->on[i]) { const float *fp = atompos + ind; xyzr[ind4 ] = fp[0]-origin[0]; xyzr[ind4 + 1] = fp[1]-origin[1]; xyzr[ind4 + 2] = fp[2]-origin[2]; xyzr[ind4 + 3] = atomradii[i]; const float *cp = &cmap[colidx[i] * 3]; colors[ind4 ] = cp[0]; colors[ind4 + 1] = cp[1]; colors[ind4 + 2] = cp[2]; colors[ind4 + 3] = 1.0f; ind4 += 4; } ind += 3; } } else { // build compacted lists of atom coordinates and radii only for (i=atomSel->firstsel; i <= atomSel->lastsel; i++) { if (atomSel->on[i]) { const float *fp = atompos + ind; xyzr[ind4 ] = fp[0]-origin[0]; xyzr[ind4 + 1] = fp[1]-origin[1]; xyzr[ind4 + 2] = fp[2]-origin[2]; xyzr[ind4 + 3] = atomradii[i]; ind4 += 4; } ind += 3; } } } // set gaussian window size based on user-specified quality parameter float gausslim = 2.0f; switch (quality) { case 3: gausslim = 4.0f; break; // max quality case 2: gausslim = 3.0f; break; // high quality case 1: gausslim = 2.5f; break; // medium quality case 0: default: gausslim = 2.0f; // low quality break; } pretime = wkf_timer_timenow(timer); #if defined(VMDCUDA) if (!getenv("VMDNOCUDA")) { // compute both density map and floating point color texture map int pcount = (usebeads) ? numbeads : atomSel->selected; int rc = cudaqs->calc_surf(pcount, &xyzr[0], (colorperatom) ? &colors[0] : &cmap[0], colorperatom, origin, numvoxels, maxrad, radscale, gridspacing, isovalue, gausslim, cmdList); if (rc == 0) { free(xyzr); if (colors) free(colors); voltime = wkf_timer_timenow(timer); return 0; } } #endif #if !defined(ARCH_BLUEWATERS) printf(" Computing density map grid on CPUs "); #endif long volsz = numvoxels[0] * numvoxels[1] * numvoxels[2]; volmap = new float[volsz]; if (colidx != NULL && cmap != NULL) { voltexmap = (float*) calloc(1, 3 * sizeof(float) * numvoxels[0] * numvoxels[1] * numvoxels[2]); } fflush(stdout); memset(volmap, 0, sizeof(float) * volsz); if ((volsz * atomSel->selected) > 20000000) { vmd_gaussdensity_threaded(atomSel->selected, &xyzr[0], (voltexmap!=NULL) ? &colors[0] : NULL, volmap, voltexmap, numvoxels, radscale, gridspacing, isovalue, gausslim); } else { vmd_gaussdensity_opt(atomSel->selected, &xyzr[0], (voltexmap!=NULL) ? &colors[0] : NULL, volmap, voltexmap, numvoxels, radscale, gridspacing, isovalue, gausslim); } free(xyzr); if (colors) free(colors); voltime = wkf_timer_timenow(timer); // draw the surface draw_trimesh(cmdList); #if !defined(ARCH_BLUEWATERS) printf(" Done.\n"); #endif return 0; }
void DrawMolItem::draw_orbital(int density, int wavefnctype, int wavefncspin, int wavefncexcitation, int orbid, float isovalue, int drawbox, int style, float gridspacing, int stepsize, int thickness) { if (!mol->numframes() || gridspacing <= 0.0f) return; // only recalculate the orbital grid if necessary int regenorbital=0; if (density != orbgridisdensity || wavefnctype != waveftype || wavefncspin != wavefspin || wavefncexcitation != wavefexcitation || orbid != gridorbid || gridspacing != orbgridspacing || orbvol == NULL || needRegenerate & MOL_REGEN || needRegenerate & SEL_REGEN) { regenorbital=1; } double motime=0, voltime=0, gradtime=0; wkf_timerhandle timer = wkf_timer_create(); wkf_timer_start(timer); if (regenorbital) { // XXX this needs to be fixed so that things like the // draw multiple frames feature will work correctly for Orbitals int frame = mol->frame(); // draw currently active frame const Timestep *ts = mol->get_frame(frame); if (!ts->qm_timestep || !mol->qm_data || !mol->qm_data->num_basis || orbid < 1) { wkf_timer_destroy(timer); return; } // Find the timestep independent wavefunction ID tag // by comparing type, spin, and excitation with the // signatures of existing wavefunctions. int waveid = mol->qm_data->find_wavef_id_from_gui_specs( wavefnctype, wavefncspin, wavefncexcitation); // Translate the wavefunction ID into the index the // wavefunction has in this timestep int iwave = ts->qm_timestep->get_wavef_index(waveid); if (iwave<0 || !ts->qm_timestep->get_wavecoeffs(iwave) || !ts->qm_timestep->get_num_orbitals(iwave) || orbid > ts->qm_timestep->get_num_orbitals(iwave)) { wkf_timer_destroy(timer); return; } // Get the orbital index for this timestep from the orbital ID. int orbindex = ts->qm_timestep->get_orbital_index_from_id(iwave, orbid); // Build an Orbital object and prepare to calculate a grid Orbital *orbital = mol->qm_data->create_orbital(iwave, orbindex, ts->pos, ts->qm_timestep); // Set the bounding box of the atom coordinates as the grid dimensions orbital->set_grid_to_bbox(ts->pos, 3.0, gridspacing); // XXX needs more testing, can get stuck for certain orbitals #if 0 // XXX for GPU, we need to only optimize to a stepsize of 4 or more, as // otherwise doing this actually slows us down rather than speeding up // orbital.find_optimal_grid(0.01, 4, 8); // // optimize: minstep 2, maxstep 8, threshold 0.01 orbital->find_optimal_grid(0.01, 2, 8); #endif // Calculate the molecular orbital orbital->calculate_mo(mol, density); motime = wkf_timer_timenow(timer); // query orbital grid origin, dimensions, and axes const int *numvoxels = orbital->get_numvoxels(); const float *origin = orbital->get_origin(); float xaxis[3], yaxis[3], zaxis[3]; orbital->get_grid_axes(xaxis, yaxis, zaxis); // build a VolumetricData object for rendering char dataname[64]; sprintf(dataname, "molecular orbital %i", orbid); // update attributes of cached orbital grid orbgridisdensity = density; waveftype = wavefnctype; wavefspin = wavefncspin; wavefexcitation = wavefncexcitation; gridorbid = orbid; orbgridspacing = gridspacing; delete orbvol; orbvol = new VolumetricData(dataname, origin, xaxis, yaxis, zaxis, numvoxels[0], numvoxels[1], numvoxels[2], orbital->get_grid_data()); delete orbital; voltime = wkf_timer_timenow(timer); orbvol->compute_volume_gradient(); // calc gradients: smooth vertex normals gradtime = wkf_timer_timenow(timer); } // regen the orbital grid... // draw the newly created VolumetricData object sprintf(commentBuffer, "MoleculeID: %d ReprID: %d Beginning Orbital", mol->id(), repNumber); cmdCommentX.putdata(commentBuffer, cmdList); if (drawbox > 0) { // don't texture the box if color by volume is active if (atomColor->method() == AtomColor::VOLUME) { append(DVOLTEXOFF); } // wireframe only? or solid? if (style > 0 || drawbox == 2) { draw_volume_box_lines(orbvol); } else { draw_volume_box_solid(orbvol); } if (atomColor->method() == AtomColor::VOLUME) { append(DVOLTEXON); } } if ((drawbox == 2) || (drawbox == 0)) { switch (style) { case 3: // shaded points isosurface looping over X-axis, 1 point per voxel draw_volume_isosurface_lit_points(orbvol, isovalue, stepsize, thickness); break; case 2: // points isosurface looping over X-axis, max of 1 point per voxel draw_volume_isosurface_points(orbvol, isovalue, stepsize, thickness); break; case 1: // lines implementation, max of 18 line per voxel (3-per triangle) draw_volume_isosurface_lines(orbvol, isovalue, stepsize, thickness); break; case 0: default: // trimesh polygonalized surface, max of 6 triangles per voxel draw_volume_isosurface_trimesh(orbvol, isovalue, stepsize); break; } } if (regenorbital) { double surftime = wkf_timer_timenow(timer); if (surftime > 5) { char strmsg[1024]; sprintf(strmsg, "Total MO rep time: %.3f [MO: %.3f vol: %.3f grad: %.3f surf: %.2f]", surftime, motime, voltime - motime, gradtime - motime, surftime - gradtime); msgInfo << strmsg << sendmsg; } } wkf_timer_destroy(timer); }
CoorPluginData::CoorPluginData(const char *nm, Molecule *m, MolFilePlugin *p, int input, int first, int stride, int last, const int *sel) : CoorData(nm), is_input(input), begFrame(first), frameSkip(stride), endFrame(last) { /// selection is NULL by default, indicating all atoms are to be written selection = NULL; /// set plugin NULL to indicate trouble if we early exit plugin = NULL; /// initialize timer handle tm=NULL; /// initialize data size variables kbytesperframe=0; totalframes=0; // make sure frame data is correct if(begFrame < 0) begFrame = 0; if(endFrame < begFrame) endFrame = (-1); if(frameSkip <= 0) frameSkip = 1; recentFrame = -1; // make sure frame data is valid if(!m || (!is_input && ( m->numframes() < begFrame || endFrame >= m->numframes() ) ) ) { msgErr << "Illegal frames requested for coordinate file I/O" << sendmsg; return; } if (is_input) { // Checks for and reject attempts to use selections when reading // coordinates. The most useful thing to do would be to allow coordinate // files to contain whatever number of atoms you want, and then use the // selection to filter those atoms. However, one could go a number of ways // with this. Should the selection be reparsed using the structure and/or // coordinate data in the new file in order to determine which atoms to // read, or should one simply use the already-computed atom indices? I can // think of situations where both of those behaviors would be desirable. if (sel) { msgErr << "Internal error: cannot read selection of coordinates" << sendmsg; return; } // make sure that the number of atoms in the coordinate file is either valid // or unknown. if (p->natoms() != m->nAtoms) { if (p->natoms() == -1) { p->set_natoms(m->nAtoms); } else { msgErr << "Incorrect number of atoms (" << p->natoms() << ") in" << sendmsg; msgErr << "coordinate file " << nm << sendmsg; return; } } } // make plugin and selection information valid plugin = p; if (sel) { selection = new int[m->nAtoms]; memcpy(selection, sel, m->nAtoms * sizeof(int)); } tm=wkf_timer_create(); wkf_timer_start(tm); // If this is output, write the structure now. if (!is_input && plugin->can_write_structure()) { if (plugin->write_structure(m, selection) == MOLFILE_SUCCESS) { totalframes++; } else { plugin = NULL; } } if (is_input) { kbytesperframe = (p->natoms() * 12) / 1024; } else { kbytesperframe = (m->nAtoms * 12) / 1024; } }