static void addTngMoleculeFromTopology(tng_trajectory_t tng, const char *moleculeName, const t_atoms *atoms, gmx_int64_t numMolecules, tng_molecule_t *tngMol) { if (tng_molecule_add(tng, moleculeName, tngMol) != TNG_SUCCESS) { gmx_file("Cannot add molecule to TNG molecular system."); } /* FIXME: The TNG atoms should contain mass and atomB info (for free * energy calculations), i.e. in when it's available in TNG (2.0). */ for (int atomIt = 0; atomIt < atoms->nr; atomIt++) { const t_atom *at = &atoms->atom[atomIt]; /* FIXME: Currently the TNG API can only add atoms belonging to a * residue and chain. Wait for TNG 2.0*/ if (atoms->nres > 0) { const t_resinfo *resInfo = &atoms->resinfo[at->resind]; char chainName[2] = {resInfo->chainid, 0}; tng_chain_t tngChain = NULL; tng_residue_t tngRes = NULL; tng_atom_t tngAtom = NULL; if (tng_molecule_chain_find (tng, *tngMol, chainName, (gmx_int64_t)-1, &tngChain) != TNG_SUCCESS) { tng_molecule_chain_add (tng, *tngMol, chainName, &tngChain); } /* FIXME: When TNG supports both residue index and residue * number the latter should be used. Wait for TNG 2.0*/ if (tng_chain_residue_find(tng, tngChain, *resInfo->name, at->resind + 1, &tngRes) != TNG_SUCCESS) { tng_chain_residue_add(tng, tngChain, *resInfo->name, &tngRes); } tng_residue_atom_add(tng, tngRes, *(atoms->atomname[atomIt]), *(atoms->atomtype[atomIt]), &tngAtom); } } tng_molecule_cnt_set(tng, *tngMol, numMolecules); }
/* Create a TNG molecule representing the selection groups * to write */ static void add_selection_groups(tng_trajectory_t tng, const gmx_mtop_t *mtop) { const gmx_moltype_t *molType; const t_atoms *atoms; const t_atom *at; const t_resinfo *resInfo; const t_ilist *ilist; int nAtoms = 0, i = 0, j, molIt, atomIt, nameIndex; int atom_offset = 0; tng_molecule_t mol, iterMol; tng_chain_t chain; tng_residue_t res; tng_atom_t atom; tng_bond_t tngBond; gmx_int64_t nMols; char *groupName; /* The name of the TNG molecule containing the selection group is the * same as the name of the selection group. */ nameIndex = *mtop->groups.grps[egcCompressedX].nm_ind; groupName = *mtop->groups.grpname[nameIndex]; tng_molecule_alloc(tng, &mol); tng_molecule_name_set(tng, mol, groupName); tng_molecule_chain_add(tng, mol, "", &chain); for (molIt = 0; molIt < mtop->nmoltype; molIt++) { molType = &mtop->moltype[mtop->molblock[molIt].type]; atoms = &molType->atoms; for (j = 0; j < mtop->molblock[molIt].nmol; j++) { bool bAtomsAdded = FALSE; for (atomIt = 0; atomIt < atoms->nr; atomIt++, i++) { char *res_name; int res_id; if (ggrpnr(&mtop->groups, egcCompressedX, i) != 0) { continue; } at = &atoms->atom[atomIt]; if (atoms->nres > 0) { resInfo = &atoms->resinfo[at->resind]; /* FIXME: When TNG supports both residue index and residue * number the latter should be used. */ res_name = *resInfo->name; res_id = at->resind + 1; } else { res_name = (char *)""; res_id = 0; } if (tng_chain_residue_find(tng, chain, res_name, res_id, &res) != TNG_SUCCESS) { /* Since there is ONE chain for selection groups do not keep the * original residue IDs - otherwise there might be conflicts. */ tng_chain_residue_add(tng, chain, res_name, &res); } tng_residue_atom_w_id_add(tng, res, *(atoms->atomname[atomIt]), *(atoms->atomtype[atomIt]), atom_offset + atomIt, &atom); nAtoms++; bAtomsAdded = TRUE; } /* Add bonds. */ if (bAtomsAdded) { for (int k = 0; k < F_NRE; k++) { if (IS_CHEMBOND(k)) { ilist = &molType->ilist[k]; if (ilist) { int l = 1; while (l < ilist->nr) { int atom1, atom2; atom1 = ilist->iatoms[l] + atom_offset; atom2 = ilist->iatoms[l+1] + atom_offset; if (ggrpnr(&mtop->groups, egcCompressedX, atom1) == 0 && ggrpnr(&mtop->groups, egcCompressedX, atom2) == 0) { tng_molecule_bond_add(tng, mol, ilist->iatoms[l], ilist->iatoms[l+1], &tngBond); } l += 3; } } } } /* Settle is described using three atoms */ ilist = &molType->ilist[F_SETTLE]; if (ilist) { int l = 1; while (l < ilist->nr) { int atom1, atom2, atom3; atom1 = ilist->iatoms[l] + atom_offset; atom2 = ilist->iatoms[l+1] + atom_offset; atom3 = ilist->iatoms[l+2] + atom_offset; if (ggrpnr(&mtop->groups, egcCompressedX, atom1) == 0) { if (ggrpnr(&mtop->groups, egcCompressedX, atom2) == 0) { tng_molecule_bond_add(tng, mol, atom1, atom2, &tngBond); } if (ggrpnr(&mtop->groups, egcCompressedX, atom3) == 0) { tng_molecule_bond_add(tng, mol, atom1, atom3, &tngBond); } } l += 4; } } } atom_offset += atoms->nr; } } if (nAtoms != i) { tng_molecule_existing_add(tng, &mol); 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 { tng_molecule_free(tng, &mol); } }
int main () /******************************************************************************/ /* Purpose: MAIN is the main program for MD_OPENMP. Discussion: MD implements a simple molecular dynamics simulation. The program uses Open MP directives to allow parallel computation. The velocity Verlet time integration scheme is used. The particles interact with a central pair potential. Output of the program is saved in the TNG format, which is why this code is included in the TNG API release. The high-level API of the TNG API is used where appropriate. Licensing: This code is distributed under the GNU LGPL license. Modified: 8 Jan 2013 Author: Original FORTRAN77 version by Bill Magro. C version by John Burkardt. TNG trajectory output by Magnus Lundborg. Parameters: None */ { float *acc; float *box; float *box_shape; float dt = 0.0002; float e0; float *force; int i; float kinetic; float mass = 1.0; int nd = 3; int np = 50; float *pos; float potential; int proc_num; int seed = 123456789; int step; int step_num = 50000; int step_print; int step_print_index; int step_print_num; int step_save; float *vel; float wtime; tng_trajectory_t traj; tng_molecule_t molecule; tng_chain_t chain; tng_residue_t residue; tng_atom_t atom; timestamp ( ); proc_num = omp_get_num_procs ( ); acc = ( float * ) malloc ( nd * np * sizeof ( float ) ); box = ( float * ) malloc ( nd * sizeof ( float ) ); box_shape = (float *) malloc (9 * sizeof (float)); force = ( float * ) malloc ( nd * np * sizeof ( float ) ); pos = ( float * ) malloc ( nd * np * sizeof ( float ) ); vel = ( float * ) malloc ( nd * np * sizeof ( float ) ); printf ( "\n" ); printf ( "MD_OPENMP\n" ); printf ( " C/OpenMP version\n" ); printf ( "\n" ); printf ( " A molecular dynamics program.\n" ); printf ( "\n" ); printf ( " NP, the number of particles in the simulation is %d\n", np ); printf ( " STEP_NUM, the number of time steps, is %d\n", step_num ); printf ( " DT, the size of each time step, is %f\n", dt ); printf ( "\n" ); printf ( " Number of processors available = %d\n", proc_num ); printf ( " Number of threads = %d\n", omp_get_max_threads ( ) ); printf("\n"); printf(" Initializing trajectory storage.\n"); /* Initialize the TNG trajectory */ tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_md_out.tng", 'w', &traj); /* Set molecules data */ /* N.B. This is still not done using utility functions. The low-level API * is used. */ printf(" Creating molecules in trajectory.\n"); tng_molecule_add(traj, "water", &molecule); tng_molecule_chain_add(traj, molecule, "W", &chain); tng_chain_residue_add(traj, chain, "WAT", &residue); if(tng_residue_atom_add(traj, residue, "O", "O", &atom) == TNG_CRITICAL) { tng_util_trajectory_close(&traj); printf(" Cannot create molecules.\n"); exit(1); } tng_molecule_cnt_set(traj, molecule, np); /* Set the dimensions of the box. */ for(i = 0; i < 9; i++) { box_shape[i] = 0.0; } for ( i = 0; i < nd; i++ ) { box[i] = 10.0; /* box_shape stores 9 values according to the TNG specs */ box_shape[i*nd + i] = box[i]; } printf ( "\n" ); printf ( " Initializing positions, velocities, and accelerations.\n" ); /* Set initial positions, velocities, and accelerations. */ initialize ( np, nd, box, &seed, pos, vel, acc ); /* Compute the forces and energies. */ printf ( "\n" ); printf ( " Computing initial forces and energies.\n" ); compute ( np, nd, pos, vel, mass, force, &potential, &kinetic ); e0 = potential + kinetic; /* Saving frequency */ step_save = 400; step_print = 0; step_print_index = 0; step_print_num = 10; /* This is the main time stepping loop: Compute forces and energies, Update positions, velocities, accelerations. */ printf(" Every %d steps box shape, particle positions, velocities and forces are\n", step_save); printf(" saved to a TNG trajectory file.\n"); printf ( "\n" ); printf ( " At certain step intervals, we report the potential and kinetic energies.\n" ); printf ( " The sum of these energies should be a constant.\n" ); printf ( " As an accuracy check, we also print the relative error\n" ); printf ( " in the total energy.\n" ); printf ( "\n" ); printf ( " Step Potential Kinetic (P+K-E0)/E0\n" ); printf ( " Energy P Energy K Relative Energy Error\n" ); printf ( "\n" ); step = 0; printf ( " %8d %14f %14f %14e\n", step, potential, kinetic, ( potential + kinetic - e0 ) / e0 ); step_print_index++; step_print = ( step_print_index * step_num ) / step_print_num; /* Set the output frequency of box shape, positions, velocities and forces */ if(tng_util_box_shape_write_frequency_set(traj, step_save) != TNG_SUCCESS) { printf("Error setting writing frequency data. %s: %d\n", __FILE__, __LINE__); exit(1); } if(tng_util_pos_write_frequency_set(traj, step_save) != TNG_SUCCESS) { printf("Error setting writing frequency data. %s: %d\n", __FILE__, __LINE__); exit(1); } if(tng_util_vel_write_frequency_set(traj, step_save) != TNG_SUCCESS) { printf("Error setting writing frequency data. %s: %d\n", __FILE__, __LINE__); exit(1); } if(tng_util_force_write_frequency_set(traj, step_save) != TNG_SUCCESS) { printf("Error setting writing frequency data. %s: %d\n", __FILE__, __LINE__); exit(1); } /* Write the first frame of box shape, positions, velocities and forces */ if(tng_util_box_shape_write(traj, 0, box_shape) != TNG_SUCCESS) { printf("Error writing box shape. %s: %d\n", __FILE__, __LINE__); exit(1); } if(tng_util_pos_write(traj, 0, pos) != TNG_SUCCESS) { printf("Error adding data. %s: %d\n", __FILE__, __LINE__); exit(1); } if(tng_util_vel_write(traj, 0, vel) != TNG_SUCCESS) { printf("Error adding data. %s: %d\n", __FILE__, __LINE__); exit(1); } if(tng_util_force_write(traj, 0, force) != TNG_SUCCESS) { printf("Error adding data. %s: %d\n", __FILE__, __LINE__); exit(1); } wtime = omp_get_wtime ( ); for ( step = 1; step < step_num; step++ ) { compute ( np, nd, pos, vel, mass, force, &potential, &kinetic ); if ( step == step_print ) { printf ( " %8d %14f %14f %14e\n", step, potential, kinetic, ( potential + kinetic - e0 ) / e0 ); step_print_index++; step_print = ( step_print_index * step_num ) / step_print_num; } if(step % step_save == 0) { /* Write box shape, positions, velocities and forces */ if(tng_util_box_shape_write(traj, step, box_shape) != TNG_SUCCESS) { printf("Error writing box shape. %s: %d\n", __FILE__, __LINE__); exit(1); } if(tng_util_pos_write(traj, step, pos) != TNG_SUCCESS) { printf("Error adding data. %s: %d\n", __FILE__, __LINE__); break; } if(tng_util_vel_write(traj, step, vel) != TNG_SUCCESS) { printf("Error adding data. %s: %d\n", __FILE__, __LINE__); break; } if(tng_util_force_write(traj, step, force) != TNG_SUCCESS) { printf("Error adding data. %s: %d\n", __FILE__, __LINE__); break; } } update ( np, nd, pos, vel, force, acc, mass, dt ); } wtime = omp_get_wtime ( ) - wtime; printf ( "\n" ); printf ( " Elapsed time for main computation:\n" ); printf ( " %f seconds.\n", wtime ); free ( acc ); free ( box ); free ( box_shape ); free ( force ); free ( pos ); free ( vel ); /* Close the TNG output. */ tng_util_trajectory_close(&traj); printf ( "\n" ); printf ( "MD_OPENMP\n" ); printf ( " Normal end of execution.\n" ); printf ( "\n" ); timestamp ( ); return 0; }
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 }