static void *open_tng_read(const char *filename, const char*, int *natoms) { tngdata *tng; tng_function_status stat; int64_t n, exp; tng = new tngdata; stat = tng_util_trajectory_open(filename, 'r', &tng->tng_traj); if(stat != TNG_SUCCESS) { fprintf(stderr, "tngplugin) Cannot open file '%s'\n", filename); return NULL; } tng_num_particles_get(tng->tng_traj, &n); *natoms = (int)n; tng->natoms = (int)n; tng->step = 0; tng_num_frames_get(tng->tng_traj, &n); tng->n_frames = n; tng->has_velocities = 0; tng_distance_unit_exponential_get(tng->tng_traj, &exp); tng->coord_exponential = (int) exp; return tng; }
void gmx_fwrite_tng(tng_trajectory_t tng, const gmx_bool bUseLossyCompression, int step, real elapsedPicoSeconds, real lambda, const rvec *box, int nAtoms, const rvec *x, const rvec *v, const rvec *f) { #ifdef GMX_USE_TNG typedef tng_function_status (*write_data_func_pointer)(tng_trajectory_t, const gmx_int64_t, const double, const real*, const gmx_int64_t, const gmx_int64_t, const char*, const char, const char); #ifdef GMX_DOUBLE static write_data_func_pointer write_data = tng_util_generic_with_time_double_write; #else static write_data_func_pointer write_data = tng_util_generic_with_time_write; #endif double elapsedSeconds = elapsedPicoSeconds * PICO; gmx_int64_t nParticles; char compression; if (!tng) { /* This function might get called when the type of the compressed trajectory is actually XTC. So we exit and move on. */ return; } tng_num_particles_get(tng, &nParticles); if (nAtoms != (int)nParticles) { tng_implicit_num_particles_set(tng, nAtoms); } if (bUseLossyCompression) { compression = TNG_TNG_COMPRESSION; } else { compression = TNG_GZIP_COMPRESSION; } /* The writing is done using write_data, which writes float or double * depending on the GROMACS compilation. */ if (x) { GMX_ASSERT(box, "Need a non-NULL box if positions are written"); if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real *>(x), 3, TNG_TRAJ_POSITIONS, "POSITIONS", TNG_PARTICLE_BLOCK_DATA, compression) != TNG_SUCCESS) { gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?"); } /* TNG-MF1 compression only compresses positions and velocities. Use lossless * compression for box shape regardless of output mode */ if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real *>(box), 9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION) != TNG_SUCCESS) { gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?"); } } if (v) { if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real *>(v), 3, TNG_TRAJ_VELOCITIES, "VELOCITIES", TNG_PARTICLE_BLOCK_DATA, compression) != TNG_SUCCESS) { gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?"); } } if (f) { /* TNG-MF1 compression only compresses positions and velocities. Use lossless * compression for forces regardless of output mode */ if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real *>(f), 3, TNG_TRAJ_FORCES, "FORCES", TNG_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION) != TNG_SUCCESS) { gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?"); } } /* TNG-MF1 compression only compresses positions and velocities. Use lossless * compression for lambdas regardless of output mode */ if (write_data(tng, step, elapsedSeconds, reinterpret_cast<const real *>(&lambda), 1, TNG_GMX_LAMBDA, "LAMBDAS", TNG_NON_PARTICLE_BLOCK_DATA, TNG_GZIP_COMPRESSION) != TNG_SUCCESS) { gmx_file("Cannot write TNG trajectory frame; maybe you are out of disk space?"); } #else GMX_UNUSED_VALUE(tng); GMX_UNUSED_VALUE(bUseLossyCompression); GMX_UNUSED_VALUE(step); GMX_UNUSED_VALUE(elapsedPicoSeconds); GMX_UNUSED_VALUE(lambda); GMX_UNUSED_VALUE(box); GMX_UNUSED_VALUE(nAtoms); GMX_UNUSED_VALUE(x); GMX_UNUSED_VALUE(v); GMX_UNUSED_VALUE(f); #endif }
static int read_tng_timestep(void *v, int natoms, molfile_timestep_t *ts) { /* The pointers that will be allocated by the TNG must be NULL before allocation. */ void *values = 0; char datatype; float box_shape[9], vmd_box[6]; float fact = 1; int64_t frame, n, temp, temp2; double temp_time; tng_function_status stat; tngdata *tng = (tngdata *)v; if(!ts) { return MOLFILE_ERROR; } // fprintf(stderr, "Reading framestep from TNG\n"); stat = tng_util_particle_data_next_frame_read(tng->tng_traj, TNG_TRAJ_POSITIONS, &values, &datatype, &frame, &temp_time); ts->physical_time = temp_time / PICO; if(stat != TNG_SUCCESS) { if(values) { free(values); } return MOLFILE_ERROR; } // fprintf(stderr, "tngplugin) Timestep %d (%f), frame %d (%d), %d atoms\n", // tng->step, ts->physical_time, (int)frame, (int)tng->n_frames, natoms); /* TODO: Here it would be possible to add reading of the energy and pressure * measurements supported in VMD if they are present in the TNG file */ tng_num_particles_get(tng->tng_traj, &n); if(n != natoms) { fprintf(stderr, "tngplugin) Timestep in file contains wrong number of atoms\n"); fprintf(stderr, "tngplugin) Found %d, expected %d\n", (int)n, natoms); return MOLFILE_ERROR; } if(tng->coord_exponential != -10) { fact = pow(10.0, tng->coord_exponential + 10); } convert_to_float(values, ts->coords, fact, natoms, 3, datatype); if(ts->velocities) { // fprintf(stderr, "tngplugin) Reading velocities\n"); stat = tng_particle_data_vector_interval_get(tng->tng_traj, TNG_TRAJ_VELOCITIES, frame, frame, TNG_USE_HASH, &values, &n, &temp, &temp2, &datatype); if(stat == TNG_CRITICAL) { if(values) { free(values); } return MOLFILE_ERROR; } if(stat == TNG_SUCCESS) { convert_to_float(values, ts->velocities, fact, natoms, 3, datatype); } } stat = tng_data_vector_interval_get(tng->tng_traj, TNG_TRAJ_BOX_SHAPE, frame, frame, TNG_USE_HASH, &values, &temp, &temp2, &datatype); if(stat == TNG_CRITICAL) { if(values) { free(values); } return MOLFILE_ERROR; } if(stat == TNG_SUCCESS) { convert_to_float(values, box_shape, fact, 1, 9, datatype); convert_tng_box_shape_to_vmd(box_shape, vmd_box); if(ts) { ts->A = vmd_box[0]; ts->B = vmd_box[1]; ts->C = vmd_box[2]; ts->alpha = vmd_box[3]; ts->beta = vmd_box[4]; ts->gamma = vmd_box[5]; } } ++tng->step; if(values) { free(values); } return MOLFILE_SUCCESS; }
gmx_bool gmx_get_tng_data_next_frame_of_block_type(tng_trajectory_t input, gmx_int64_t blockId, real **values, gmx_int64_t *frameNumber, double *frameTime, gmx_int64_t *nValuesPerFrame, gmx_int64_t *nAtoms, real *prec, char *name, int maxLen, gmx_bool *bOK) { #if GMX_USE_TNG tng_function_status stat; char datatype = -1; gmx_int64_t codecId; int blockDependency; void *data = 0; double localPrec; stat = tng_data_block_name_get(input, blockId, name, maxLen); if (stat != TNG_SUCCESS) { gmx_file("Cannot read next frame of TNG file"); } stat = tng_data_block_dependency_get(input, blockId, &blockDependency); if (stat != TNG_SUCCESS) { gmx_file("Cannot read next frame of TNG file"); } if (blockDependency & TNG_PARTICLE_DEPENDENT) { tng_num_particles_get(input, nAtoms); stat = tng_util_particle_data_next_frame_read(input, blockId, &data, &datatype, frameNumber, frameTime); } else { *nAtoms = 1; /* There are not actually any atoms, but it is used for allocating memory */ stat = tng_util_non_particle_data_next_frame_read(input, blockId, &data, &datatype, frameNumber, frameTime); } if (stat == TNG_CRITICAL) { gmx_file("Cannot read next frame of TNG file"); } if (stat == TNG_FAILURE) { *bOK = TRUE; return FALSE; } stat = tng_data_block_num_values_per_frame_get(input, blockId, nValuesPerFrame); if (stat != TNG_SUCCESS) { gmx_file("Cannot read next frame of TNG file"); } snew(*values, sizeof(real) * *nValuesPerFrame * *nAtoms); convert_array_to_real_array(data, *values, getDistanceScaleFactor(input), *nAtoms, *nValuesPerFrame, datatype); tng_util_frame_current_compression_get(input, blockId, &codecId, &localPrec); /* This must be updated if/when more lossy compression methods are added */ if (codecId != TNG_TNG_COMPRESSION) { *prec = -1.0; } else { *prec = localPrec; } *bOK = TRUE; return TRUE; #else GMX_UNUSED_VALUE(input); GMX_UNUSED_VALUE(blockId); GMX_UNUSED_VALUE(values); GMX_UNUSED_VALUE(frameNumber); GMX_UNUSED_VALUE(frameTime); GMX_UNUSED_VALUE(nValuesPerFrame); GMX_UNUSED_VALUE(nAtoms); GMX_UNUSED_VALUE(prec); GMX_UNUSED_VALUE(name); GMX_UNUSED_VALUE(maxLen); GMX_UNUSED_VALUE(bOK); return FALSE; #endif }
/* TODO: If/when TNG acquires the ability to copy data blocks without * uncompressing them, then this implemenation should be reconsidered. * Ideally, gmx trjconv -f a.tng -o b.tng -b 10 -e 20 would be fast * and lose no information. */ gmx_bool gmx_read_next_tng_frame(tng_trajectory_t input, t_trxframe *fr, gmx_int64_t *requestedIds, int numRequestedIds) { #if GMX_USE_TNG gmx_bool bOK = TRUE; tng_function_status stat; gmx_int64_t numberOfAtoms = -1, frameNumber = -1; gmx_int64_t nBlocks, blockId, *blockIds = NULL, codecId; char datatype = -1; void *values = NULL; double frameTime = -1.0; int size, blockDependency; double prec; const int defaultNumIds = 5; static gmx_int64_t fallbackRequestedIds[defaultNumIds] = { TNG_TRAJ_BOX_SHAPE, TNG_TRAJ_POSITIONS, TNG_TRAJ_VELOCITIES, TNG_TRAJ_FORCES, TNG_GMX_LAMBDA }; fr->bStep = FALSE; fr->bTime = FALSE; fr->bLambda = FALSE; fr->bAtoms = FALSE; fr->bPrec = FALSE; fr->bX = FALSE; fr->bV = FALSE; fr->bF = FALSE; fr->bBox = FALSE; /* If no specific IDs were requested read all block types that can * currently be interpreted */ if (!requestedIds || numRequestedIds == 0) { numRequestedIds = defaultNumIds; requestedIds = fallbackRequestedIds; } stat = tng_num_particles_get(input, &numberOfAtoms); if (stat != TNG_SUCCESS) { gmx_file("Cannot determine number of atoms from TNG file."); } fr->natoms = numberOfAtoms; if (!gmx_get_tng_data_block_types_of_next_frame(input, fr->step, numRequestedIds, requestedIds, &frameNumber, &nBlocks, &blockIds)) { return FALSE; } if (nBlocks == 0) { return FALSE; } for (gmx_int64_t i = 0; i < nBlocks; i++) { blockId = blockIds[i]; tng_data_block_dependency_get(input, blockId, &blockDependency); if (blockDependency & TNG_PARTICLE_DEPENDENT) { stat = tng_util_particle_data_next_frame_read(input, blockId, &values, &datatype, &frameNumber, &frameTime); } else { stat = tng_util_non_particle_data_next_frame_read(input, blockId, &values, &datatype, &frameNumber, &frameTime); } if (stat == TNG_CRITICAL) { gmx_file("Cannot read positions from TNG file."); return FALSE; } else if (stat == TNG_FAILURE) { continue; } switch (blockId) { case TNG_TRAJ_BOX_SHAPE: switch (datatype) { case TNG_INT_DATA: size = sizeof(gmx_int64_t); break; case TNG_FLOAT_DATA: size = sizeof(float); break; case TNG_DOUBLE_DATA: size = sizeof(double); break; default: gmx_incons("Illegal datatype of box shape values!"); } for (int i = 0; i < DIM; i++) { convert_array_to_real_array(reinterpret_cast<char *>(values) + size * i * DIM, reinterpret_cast<real *>(fr->box[i]), getDistanceScaleFactor(input), 1, DIM, datatype); } fr->bBox = TRUE; break; case TNG_TRAJ_POSITIONS: srenew(fr->x, fr->natoms); convert_array_to_real_array(values, reinterpret_cast<real *>(fr->x), getDistanceScaleFactor(input), fr->natoms, DIM, datatype); fr->bX = TRUE; tng_util_frame_current_compression_get(input, blockId, &codecId, &prec); /* This must be updated if/when more lossy compression methods are added */ if (codecId == TNG_TNG_COMPRESSION) { fr->prec = prec; fr->bPrec = TRUE; } break; case TNG_TRAJ_VELOCITIES: srenew(fr->v, fr->natoms); convert_array_to_real_array(values, (real *) fr->v, getDistanceScaleFactor(input), fr->natoms, DIM, datatype); fr->bV = TRUE; tng_util_frame_current_compression_get(input, blockId, &codecId, &prec); /* This must be updated if/when more lossy compression methods are added */ if (codecId == TNG_TNG_COMPRESSION) { fr->prec = prec; fr->bPrec = TRUE; } break; case TNG_TRAJ_FORCES: srenew(fr->f, fr->natoms); convert_array_to_real_array(values, reinterpret_cast<real *>(fr->f), getDistanceScaleFactor(input), fr->natoms, DIM, datatype); fr->bF = TRUE; break; case TNG_GMX_LAMBDA: switch (datatype) { case TNG_FLOAT_DATA: fr->lambda = *(reinterpret_cast<float *>(values)); break; case TNG_DOUBLE_DATA: fr->lambda = *(reinterpret_cast<double *>(values)); break; default: gmx_incons("Illegal datatype lambda value!"); } fr->bLambda = TRUE; break; default: gmx_warning("Illegal block type! Currently GROMACS tools can only handle certain data types. Skipping block."); } /* values does not have to be freed before reading next frame. It will * be reallocated if it is not NULL. */ } fr->step = static_cast<int>(frameNumber); fr->bStep = TRUE; // Convert the time to ps fr->time = frameTime / PICO; fr->bTime = TRUE; /* values must be freed before leaving this function */ sfree(values); return bOK; #else GMX_UNUSED_VALUE(input); GMX_UNUSED_VALUE(fr); GMX_UNUSED_VALUE(requestedIds); GMX_UNUSED_VALUE(numRequestedIds); return FALSE; #endif }
void gmx_tng_setup_atom_subgroup(tng_trajectory_t tng, const int nind, const int *ind, const char *name) { #if GMX_USE_TNG gmx_int64_t nAtoms, cnt, nMols; tng_molecule_t mol, iterMol; tng_chain_t chain; tng_residue_t res; tng_atom_t atom; tng_function_status stat; tng_num_particles_get(tng, &nAtoms); if (nAtoms == nind) { return; } stat = tng_molecule_find(tng, name, -1, &mol); if (stat == TNG_SUCCESS) { tng_molecule_num_atoms_get(tng, mol, &nAtoms); tng_molecule_cnt_get(tng, mol, &cnt); if (nAtoms == nind) { stat = TNG_SUCCESS; } else { stat = TNG_FAILURE; } } if (stat == TNG_FAILURE) { /* The indexed atoms are added to one separate molecule. */ tng_molecule_alloc(tng, &mol); tng_molecule_name_set(tng, mol, name); tng_molecule_chain_add(tng, mol, "", &chain); for (int i = 0; i < nind; i++) { char temp_name[256], temp_type[256]; /* Try to retrieve the residue name of the atom */ stat = tng_residue_name_of_particle_nr_get(tng, ind[i], temp_name, 256); if (stat != TNG_SUCCESS) { temp_name[0] = '\0'; } /* Check if the molecule of the selection already contains this residue */ if (tng_chain_residue_find(tng, chain, temp_name, -1, &res) != TNG_SUCCESS) { tng_chain_residue_add(tng, chain, temp_name, &res); } /* Try to find the original name and type of the atom */ stat = tng_atom_name_of_particle_nr_get(tng, ind[i], temp_name, 256); if (stat != TNG_SUCCESS) { temp_name[0] = '\0'; } stat = tng_atom_type_of_particle_nr_get(tng, ind[i], temp_type, 256); if (stat != TNG_SUCCESS) { temp_type[0] = '\0'; } tng_residue_atom_w_id_add(tng, res, temp_name, temp_type, ind[i], &atom); } tng_molecule_existing_add(tng, &mol); } /* Set the count of the molecule containing the selected atoms to 1 and all * other molecules to 0 */ tng_molecule_cnt_set(tng, mol, 1); tng_num_molecule_types_get(tng, &nMols); for (gmx_int64_t k = 0; k < nMols; k++) { tng_molecule_of_index_get(tng, k, &iterMol); if (iterMol == mol) { continue; } tng_molecule_cnt_set(tng, iterMol, 0); } #else GMX_UNUSED_VALUE(tng); GMX_UNUSED_VALUE(nind); GMX_UNUSED_VALUE(ind); GMX_UNUSED_VALUE(name); #endif }