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; }
static int write_tng_timestep(void *v, const molfile_timestep_t *ts) { float box_shape[9]; tngdata *tng = (tngdata *)v; double time; /* If there are fewer particles in the TNG mol system (write_tng_structure * has not already been performed) compensate by creating implicit particles, * which will not have full atom information. */ tng_implicit_num_particles_set(tng->tng_traj, tng->natoms); if(!ts) { return MOLFILE_ERROR; } time = ts->physical_time * PICO; convert_vmd_box_shape_to_tng(ts, box_shape); if(tng->step == 1 && ts->physical_time != 0) { tng->time_per_frame = time; tng_time_per_frame_set(tng->tng_traj, tng->time_per_frame); } if(tng->time_per_frame < 0) { // fprintf(stderr, "tngplugin) Writing frame without time stamp\n"); tng_util_box_shape_write(tng->tng_traj, tng->step, box_shape); tng_util_pos_write(tng->tng_traj, tng->step, ts->coords); } else { // fprintf(stderr, "tngplugin) Writing frame with time stamp\n"); tng_util_box_shape_with_time_write(tng->tng_traj, tng->step, time, box_shape); tng_util_pos_with_time_write(tng->tng_traj, tng->step, time, ts->coords); } if(tng->step == 0) { tng_util_pos_write_interval_set(tng->tng_traj, 1); tng_util_box_shape_write_interval_set(tng->tng_traj, 1); } if(ts->velocities) { fprintf(stderr, "tngplugin) Writing TNG velocities\n"); if(tng->time_per_frame < 0) { tng_util_vel_write(tng->tng_traj, tng->step, ts->velocities); } else { tng_util_vel_with_time_write(tng->tng_traj, tng->step, time, ts->velocities); } if(tng->step == 0) { tng_util_vel_write_interval_set(tng->tng_traj, 1); } } tng->step++; return MOLFILE_SUCCESS; }