/*---------------------------------------------------------------------- SerialReax - Reax Force Field Simulator Copyright (2010) Purdue University Hasan Metin Aktulga, haktulga@cs.purdue.edu Joseph Fogarty, jcfogart@mail.usf.edu Sagar Pandit, pandit@usf.edu Ananth Y Grama, ayg@cs.purdue.edu This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details: <http://www.gnu.org/licenses/>. ----------------------------------------------------------------------*/ #include "spuremd.h" #include "allocate.h" #include "analyze.h" #include "box.h" #include "control.h" #include "ffield.h" #include "forces.h" #include "init_md.h" #include "io_tools.h" #include "neighbors.h" #include "geo_tools.h" #include "reset_tools.h" #include "restart.h" #include "system_props.h" #include "tool_box.h" #include "vector.h" #include <ctype.h> /* Handles additional entire geometry calculations after * perturbing atom positions during a simulation step */ static void Post_Evolve( reax_system * const system, control_params * const control, simulation_data * const data, static_storage * const workspace, reax_list ** const lists, output_controls * const out_control ) { int i; rvec diff, cross; /* remove rotational and translational velocity of the center of mass */ if ( control->ensemble != NVE && control->remove_CoM_vel > 0 && data->step % control->remove_CoM_vel == 0 ) { /* compute velocity of the center of mass */ Compute_Center_of_Mass( system, data ); for ( i = 0; i < system->N; i++ ) { /* remove translational */ rvec_ScaledAdd( system->atoms[i].v, -1.0, data->vcm ); /* remove rotational */ rvec_ScaledSum( diff, 1.0, system->atoms[i].x, -1.0, data->xcm ); rvec_Cross( cross, data->avcm, diff ); rvec_ScaledAdd( system->atoms[i].v, -1.0, cross ); } } if ( control->ensemble == NVE ) { Compute_Kinetic_Energy( system, data ); } Compute_Total_Energy( data ); if ( control->compute_pressure == TRUE && control->ensemble != sNPT && control->ensemble != iNPT && control->ensemble != aNPT ) { Compute_Pressure_Isotropic( system, control, data, out_control ); } } /* Parse input files * * geo_file: file containing geometry info of the structure to simulate * ffield_file: file containing force field parameters * control_file: file containing simulation parameters */ static void Read_Input_Files( const char * const geo_file, const char * const ffield_file, const char * const control_file, reax_system * const system, control_params * const control, simulation_data * const data, static_storage * const workspace, output_controls * const out_control, int reset ) { if ( ffield_file != NULL ) { Read_Force_Field( ffield_file, system, &system->reax_param ); } if ( reset == FALSE || control_file != NULL ) { Set_Control_Defaults( system, control, out_control ); } if ( control_file != NULL ) { Read_Control_File( control_file, system, control, out_control ); } if ( reset == FALSE || control_file != NULL ) { Set_Control_Derived_Values( system, control ); } if ( geo_file != NULL ) { if ( control->geo_format == CUSTOM ) { Read_Geo( geo_file, system, control, data, workspace ); } else if ( control->geo_format == PDB ) { Read_PDB( geo_file, system, control, data, workspace ); } else if ( control->geo_format == BGF ) { Read_BGF( geo_file, system, control, data, workspace ); } else if ( control->geo_format == ASCII_RESTART ) { Read_ASCII_Restart( geo_file, system, control, data, workspace ); control->restart = TRUE; } else if ( control->geo_format == BINARY_RESTART ) { Read_Binary_Restart( geo_file, system, control, data, workspace ); control->restart = TRUE; } else { fprintf( stderr, "[ERROR] unknown geo file format. terminating!\n" ); exit( INVALID_GEO ); } } #if defined(DEBUG_FOCUS) Print_Box( &system->box, stderr ); #endif } static void Allocate_Top_Level_Structs( spuremd_handle ** handle ) { int i; /* top-level allocation */ *handle = smalloc( sizeof(spuremd_handle), __FILE__, __LINE__ ); /* second-level allocations */ (*handle)->system = smalloc( sizeof(reax_system), __FILE__, __LINE__ ); (*handle)->control = smalloc( sizeof(control_params), __FILE__, __LINE__ ); (*handle)->data = smalloc( sizeof(simulation_data), __FILE__, __LINE__ ); (*handle)->workspace = smalloc( sizeof(static_storage), __FILE__, __LINE__ ); (*handle)->lists = smalloc( sizeof(reax_list *) * LIST_N, __FILE__, __LINE__ ); for ( i = 0; i < LIST_N; ++i ) { (*handle)->lists[i] = smalloc( sizeof(reax_list), __FILE__, __LINE__ ); } (*handle)->out_control = smalloc( sizeof(output_controls), __FILE__, __LINE__ ); } static void Initialize_Top_Level_Structs( spuremd_handle * handle ) { int i; /* top-level initializations */ handle->output_enabled = TRUE; handle->realloc = TRUE; handle->callback = NULL; handle->data->sim_id = 0; /* second-level initializations */ handle->system->prealloc_allocated = FALSE; handle->system->allocated = FALSE; handle->system->ffield_params_allocated = FALSE; handle->system->g.allocated = FALSE; handle->workspace->allocated = FALSE; handle->workspace->H.allocated = FALSE; handle->workspace->H_full.allocated = FALSE; handle->workspace->H_sp.allocated = FALSE; handle->workspace->H_p.allocated = FALSE; handle->workspace->H_spar_patt.allocated = FALSE; handle->workspace->H_spar_patt_full.allocated = FALSE; handle->workspace->H_app_inv.allocated = FALSE; handle->workspace->L.allocated = FALSE; handle->workspace->U.allocated = FALSE; for ( i = 0; i < LIST_N; ++i ) { handle->lists[i]->allocated = FALSE; } handle->out_control->allocated = FALSE; } /* Allocate top-level data structures and parse input files * for the first simulation * * geo_file: file containing geometry info of the structure to simulate * ffield_file: file containing force field parameters * control_file: file containing simulation parameters */ void * setup( const char * const geo_file, const char * const ffield_file, const char * const control_file ) { spuremd_handle *spmd_handle; Allocate_Top_Level_Structs( &spmd_handle ); Initialize_Top_Level_Structs( spmd_handle ); spmd_handle->system->N_max = 0; spmd_handle->system->max_num_molec_charge_constraints = 0; spmd_handle->system->num_molec_charge_constraints = 0; spmd_handle->system->max_num_custom_charge_constraints = 0; spmd_handle->system->num_custom_charge_constraints = 0; Read_Input_Files( geo_file, ffield_file, control_file, spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->out_control, FALSE ); spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N ); return (void *) spmd_handle; } /* Allocate top-level data structures and parse input files * for the first simulation * * num_atoms: num. atoms in this simulation * types: integer representation of atom element (type) * NOTE: must match the 0-based index from section 2 in the ReaxFF parameter file * sim_box_info: simulation box information, where the entries are * - box length per dimension (3 entries) * - angles per dimension (3 entries) * pos: coordinates of atom positions (consecutively arranged), in Angstroms * ffield_file: file containing force field parameters * control_file: file containing simulation parameters */ void * setup2( int num_atoms, const int * const atom_type, const double * const pos, const double * const sim_box_info, const char * const ffield_file, const char * const control_file ) { int i; // char atom_name[9]; rvec x; spuremd_handle *spmd_handle; Allocate_Top_Level_Structs( &spmd_handle ); Initialize_Top_Level_Structs( spmd_handle ); spmd_handle->system->max_num_molec_charge_constraints = 0; spmd_handle->system->num_molec_charge_constraints = 0; spmd_handle->system->max_num_custom_charge_constraints = 0; spmd_handle->system->num_custom_charge_constraints = 0; /* override default */ spmd_handle->output_enabled = FALSE; Read_Input_Files( NULL, ffield_file, control_file, spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->out_control, FALSE ); spmd_handle->system->N = num_atoms; /* note: assign here to avoid compiler warning * of uninitialized usage in PreAllocate_Space */ spmd_handle->system->N_max = 0; spmd_handle->system->max_num_molec_charge_constraints = 0; spmd_handle->system->num_molec_charge_constraints = 0; spmd_handle->system->max_num_custom_charge_constraints = 0; spmd_handle->system->num_custom_charge_constraints = 0; PreAllocate_Space( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, (int) CEIL( SAFE_ZONE * spmd_handle->system->N ) ); Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2], sim_box_info[3], sim_box_info[4], sim_box_info[5], &spmd_handle->system->box ); for ( i = 0; i < spmd_handle->system->N; ++i ) { assert( atom_type[i] >= 0 && atom_type[i] < spmd_handle->system->reax_param.num_atom_types ); x[0] = pos[3 * i]; x[1] = pos[3 * i + 1]; x[2] = pos[3 * i + 2]; Fit_to_Periodic_Box( &spmd_handle->system->box, x ); spmd_handle->workspace->orig_id[i] = i + 1; spmd_handle->system->atoms[i].type = atom_type[i]; strncpy( spmd_handle->system->atoms[i].name, spmd_handle->system->reax_param.sbp[atom_type[i]].name, sizeof(spmd_handle->system->atoms[i].name) - 1 ); spmd_handle->system->atoms[i].name[sizeof(spmd_handle->system->atoms[i].name) - 1] = '\0'; rvec_Copy( spmd_handle->system->atoms[i].x, x ); rvec_MakeZero( spmd_handle->system->atoms[i].v ); rvec_MakeZero( spmd_handle->system->atoms[i].f ); spmd_handle->system->atoms[i].q = 0.0; /* check for dummy atom */ if ( strncmp( spmd_handle->system->atoms[i].name, "X\0", 2 ) == 0 ) { spmd_handle->system->atoms[i].is_dummy = TRUE; } else { spmd_handle->system->atoms[i].is_dummy = FALSE; } } spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N ); return (void *) spmd_handle; } /* Setup callback function to be run after each simulation step * * handle: pointer to wrapper struct with top-level data structures * callback: function pointer to attach for callback * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int setup_callback( const void * const handle, const callback_function callback ) { int ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL && callback != NULL ) { spmd_handle = (spuremd_handle*) handle; spmd_handle->callback = callback; ret = SPUREMD_SUCCESS; } return ret; } /* Run the simulation according to the prescribed parameters * * handle: pointer to wrapper struct with top-level data structures * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int simulate( const void * const handle ) { int steps, ret, ret_forces, retries; evolve_function Evolve; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; Initialize( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control, &Evolve, spmd_handle->output_enabled, spmd_handle->realloc ); /* compute f_0 */ //if( control.restart == FALSE ) { Reset( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists ); ret_forces = Compute_Forces( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control, spmd_handle->realloc ); if ( ret_forces != SUCCESS ) { Estimate_Storages( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, spmd_handle->lists, spmd_handle->workspace->realloc.cm, spmd_handle->workspace->realloc.bonds || spmd_handle->workspace->realloc.hbonds ); Reallocate_Part2( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists ); ret_forces = Compute_Forces( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control, spmd_handle->realloc ); if ( ret_forces != SUCCESS ) { fprintf( stderr, "[ERROR] Unrecoverable memory allocation issue (Compute_Forces). Terminating...\n" ); exit( INVALID_GEO ); } } Compute_Kinetic_Energy( spmd_handle->system, spmd_handle->data ); if ( spmd_handle->control->compute_pressure == TRUE && spmd_handle->control->ensemble != sNPT && spmd_handle->control->ensemble != iNPT && spmd_handle->control->ensemble != aNPT ) { Compute_Pressure_Isotropic( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->out_control ); } Compute_Total_Energy( spmd_handle->data ); if ( spmd_handle->output_enabled == TRUE ) { Output_Results( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control ); } Check_Energy( spmd_handle->data ); if ( spmd_handle->output_enabled == TRUE ) { if ( spmd_handle->out_control->write_steps > 0 && spmd_handle->data->step % spmd_handle->out_control->write_steps == 0 ) { Write_PDB( spmd_handle->system, spmd_handle->lists[BONDS], spmd_handle->data, spmd_handle->control, spmd_handle->workspace, spmd_handle->out_control ); } } if ( spmd_handle->callback != NULL ) { spmd_handle->callback( spmd_handle->system->N, spmd_handle->system->atoms, spmd_handle->data ); } //} ++spmd_handle->data->step; retries = 0; while ( spmd_handle->data->step <= spmd_handle->control->nsteps && retries < MAX_RETRIES ) { ret = SUCCESS; if ( spmd_handle->control->T_mode != 0 ) { Temperature_Control( spmd_handle->control, spmd_handle->data, spmd_handle->out_control ); } ret = Evolve( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control ); if ( ret == SUCCESS ) { Post_Evolve( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control ); } if ( ret == SUCCESS ) { if ( spmd_handle->output_enabled == TRUE ) { Output_Results( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control ); } Check_Energy( spmd_handle->data ); if ( spmd_handle->output_enabled == TRUE ) { steps = spmd_handle->data->step - spmd_handle->data->prev_steps; Analysis( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control ); if ( spmd_handle->out_control->restart_freq > 0 && steps % spmd_handle->out_control->restart_freq == 0 ) { Write_Restart( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->out_control ); } if ( spmd_handle->out_control->write_steps > 0 && steps % spmd_handle->out_control->write_steps == 0 ) { Write_PDB( spmd_handle->system, spmd_handle->lists[BONDS], spmd_handle->data, spmd_handle->control, spmd_handle->workspace, spmd_handle->out_control ); } } if ( spmd_handle->callback != NULL ) { spmd_handle->callback( spmd_handle->system->N, spmd_handle->system->atoms, spmd_handle->data ); } ++spmd_handle->data->step; retries = 0; } else { ++retries; #if defined(DEBUG_FOCUS) fprintf( stderr, "[INFO] p%d: retrying step %d...\n", system->my_rank, data->step ); #endif } } spmd_handle->data->timing.end = Get_Time( ); spmd_handle->data->timing.elapsed = Get_Timing_Info( spmd_handle->data->timing.start ); if ( spmd_handle->output_enabled == TRUE && spmd_handle->out_control->log_update_freq > 0 ) { fprintf( spmd_handle->out_control->log, "total: %.2f secs\n", spmd_handle->data->timing.elapsed ); } spmd_handle->realloc = FALSE; ret = SPUREMD_SUCCESS; } return ret; } /* Deallocate all data structures post-simulation * * handle: pointer to wrapper struct with top-level data structures * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int cleanup( const void * const handle ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; Finalize( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control, spmd_handle->output_enabled, FALSE ); sfree( spmd_handle->out_control, __FILE__, __LINE__ ); for ( i = 0; i < LIST_N; ++i ) { sfree( spmd_handle->lists[i], __FILE__, __LINE__ ); } sfree( spmd_handle->lists, __FILE__, __LINE__ ); sfree( spmd_handle->workspace, __FILE__, __LINE__ ); sfree( spmd_handle->data, __FILE__, __LINE__ ); sfree( spmd_handle->control, __FILE__, __LINE__ ); sfree( spmd_handle->system, __FILE__, __LINE__ ); sfree( spmd_handle, __FILE__, __LINE__ ); ret = SPUREMD_SUCCESS; } return ret; } /* Reset for the next simulation by parsing input files and triggering * reallocation if more space is needed * * handle: pointer to wrapper struct with top-level data structures * geo_file: file containing geometry info of the structure to simulate * ffield_file: file containing force field parameters * control_file: file containing simulation parameters * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int reset( const void * const handle, const char * const geo_file, const char * const ffield_file, const char * const control_file ) { int ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; /* close files used in previous simulation */ if ( spmd_handle->output_enabled == TRUE ) { Finalize_Out_Controls( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, spmd_handle->out_control ); } spmd_handle->realloc = FALSE; spmd_handle->data->sim_id++; Read_Input_Files( geo_file, ffield_file, control_file, spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->out_control, TRUE ); if ( spmd_handle->system->N > spmd_handle->system->N_max ) { /* deallocate everything which needs more space * (i.e., structures whose space is a function of the number of atoms), * except for data structures allocated while parsing input files */ Finalize( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control, spmd_handle->output_enabled, TRUE ); spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N ); spmd_handle->realloc = TRUE; } ret = SPUREMD_SUCCESS; } return ret; } /* Allocate top-level data structures and parse input files * for the first simulation * * handle: pointer to wrapper struct with top-level data structures * num_atoms: num. atoms in this simulation * types: integer representation of atom element (type) * NOTE: must match the 0-based index from section 2 in the ReaxFF parameter file * sim_box_info: simulation box information, where the entries are * - box length per dimension (3 entries) * - angles per dimension (3 entries) * pos: coordinates of atom positions (consecutively arranged), in Angstroms * ffield_file: file containing force field parameters * control_file: file containing simulation parameters */ int reset2( const void * const handle, int num_atoms, const int * const atom_type, const double * const pos, const double * const sim_box_info, const char * const ffield_file, const char * const control_file ) { int i, ret; rvec x; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; /* close files used in previous simulation */ if ( spmd_handle->output_enabled == TRUE ) { Finalize_Out_Controls( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, spmd_handle->out_control ); } spmd_handle->realloc = FALSE; spmd_handle->data->sim_id++; Read_Input_Files( NULL, ffield_file, control_file, spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->out_control, TRUE ); spmd_handle->system->N = num_atoms; if ( spmd_handle->system->prealloc_allocated == FALSE || spmd_handle->system->N > spmd_handle->system->N_max ) { PreAllocate_Space( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, (int) CEIL( SAFE_ZONE * spmd_handle->system->N ) ); } Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2], sim_box_info[3], sim_box_info[4], sim_box_info[5], &spmd_handle->system->box ); for ( i = 0; i < spmd_handle->system->N; ++i ) { assert( atom_type[i] >= 0 && atom_type[i] < spmd_handle->system->reax_param.num_atom_types ); x[0] = pos[3 * i]; x[1] = pos[3 * i + 1]; x[2] = pos[3 * i + 2]; Fit_to_Periodic_Box( &spmd_handle->system->box, x ); spmd_handle->workspace->orig_id[i] = i + 1; spmd_handle->system->atoms[i].type = atom_type[i]; strncpy( spmd_handle->system->atoms[i].name, spmd_handle->system->reax_param.sbp[atom_type[i]].name, sizeof(spmd_handle->system->atoms[i].name) - 1 ); spmd_handle->system->atoms[i].name[sizeof(spmd_handle->system->atoms[i].name) - 1] = '\0'; rvec_Copy( spmd_handle->system->atoms[i].x, x ); rvec_MakeZero( spmd_handle->system->atoms[i].v ); rvec_MakeZero( spmd_handle->system->atoms[i].f ); spmd_handle->system->atoms[i].q = 0.0; /* check for dummy atom */ if ( strncmp( spmd_handle->system->atoms[i].name, "X\0", 2 ) == 0 ) { spmd_handle->system->atoms[i].is_dummy = TRUE; } else { spmd_handle->system->atoms[i].is_dummy = FALSE; } } if ( spmd_handle->system->N > spmd_handle->system->N_max ) { /* deallocate everything which needs more space * (i.e., structures whose space is a function of the number of atoms), * except for data structures allocated while parsing input files */ Finalize( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control, spmd_handle->output_enabled, TRUE ); spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N ); spmd_handle->realloc = TRUE; } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom positions * * handle: pointer to wrapper struct with top-level data structures * pos: coordinates of atom positions, in Angstroms (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_positions( const void * const handle, double * const pos ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; for ( i = 0; i < spmd_handle->system->N; ++i ) { pos[3 * i] = spmd_handle->system->atoms[i].x[0]; pos[3 * i + 1] = spmd_handle->system->atoms[i].x[1]; pos[3 * i + 2] = spmd_handle->system->atoms[i].x[2]; } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom velocities * * handle: pointer to wrapper struct with top-level data structures * vel: coordinates of atom velocities, in Angstroms / ps (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_velocities( const void * const handle, double * const vel ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; for ( i = 0; i < spmd_handle->system->N; ++i ) { vel[3 * i] = spmd_handle->system->atoms[i].v[0]; vel[3 * i + 1] = spmd_handle->system->atoms[i].v[1]; vel[3 * i + 2] = spmd_handle->system->atoms[i].v[2]; } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom forces * * handle: pointer to wrapper struct with top-level data structures * f: coordinates of atom forces, in Angstroms * Daltons / ps^2 (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_forces( const void * const handle, double * const f ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; for ( i = 0; i < spmd_handle->system->N; ++i ) { f[3 * i] = spmd_handle->system->atoms[i].f[0]; f[3 * i + 1] = spmd_handle->system->atoms[i].f[1]; f[3 * i + 2] = spmd_handle->system->atoms[i].f[2]; } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom charges * * handle: pointer to wrapper struct with top-level data structures * q: atom charges, in Coulombs (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_charges( const void * const handle, double * const q ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; for ( i = 0; i < spmd_handle->system->N; ++i ) { q[i] = spmd_handle->system->atoms[i].q; } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for system energies * * handle: pointer to wrapper struct with top-level data structures * e_pot: system potential energy, in kcal / mol (reference from caller) * e_kin: system kinetic energy, in kcal / mol (reference from caller) * e_tot: system total energy, in kcal / mol (reference from caller) * t_scalar: temperature scalar, in K (reference from caller) * vol: volume of the simulation box, in Angstroms^3 (reference from caller) * pres: average pressure, in K (reference from caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_system_info( const void * const handle, double * const e_pot, double * const e_kin, double * const e_tot, double * const temp, double * const vol, double * const pres ) { int ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; if ( e_pot != NULL ) { *e_pot = spmd_handle->data->E_Pot; } if ( e_kin != NULL ) { *e_kin = spmd_handle->data->E_Kin; } if ( e_tot != NULL ) { *e_tot = spmd_handle->data->E_Tot; } if ( temp != NULL ) { *temp = spmd_handle->data->therm.T; } if ( vol != NULL ) { *vol = spmd_handle->system->box.volume; } if ( pres != NULL ) { *pres = (spmd_handle->control->P[0] + spmd_handle->control->P[1] + spmd_handle->control->P[2]) / 3.0; } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for total energy * * handle: pointer to wrapper struct with top-level data structures * e_tot: system total energy, in kcal / mol (reference from caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_total_energy( const void * const handle, double * const e_tot ) { int ret; ret = get_system_info( handle, e_tot, NULL, NULL, NULL, NULL, NULL ); if ( ret == SUCCESS ) { ret = SPUREMD_SUCCESS; } return ret; } /* Setter for writing output to files * * handle: pointer to wrapper struct with top-level data structures * enabled: TRUE enables writing output to files, FALSE otherwise * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int set_output_enabled( const void * const handle, const int enabled ) { int ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; spmd_handle->output_enabled = enabled; ret = SPUREMD_SUCCESS; } return ret; } /* Setter for simulation parameter values as defined in the input control file * * handle: pointer to wrapper struct with top-level data structures * control_keyword: keyword from the control file to set the value for * control_value: value to set * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int set_control_parameter( const void * const handle, const char * const keyword, const char ** const values ) { int ret, ret_; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; ret_ = Set_Control_Parameter( keyword, values, spmd_handle->control, spmd_handle->out_control ); if ( ret_ == SUCCESS ) { ret = SPUREMD_SUCCESS; } } return ret; } #if defined(QMMM) /* Allocate top-level data structures and parse input files * for the first simulation * * qm_num_atoms: num. atoms in the QM region * qm_symbols: element types for QM atoms * qm_pos: coordinates of QM atom positions (consecutively arranged), in Angstroms * mm_num_atoms: num. atoms in the MM region * mm_symbols: element types for MM atoms * mm_pos_q: coordinates and charges of MM atom positions (consecutively arranged), in Angstroms / Coulombs * sim_box_info: simulation box information, where the entries are * - box length per dimension (3 entries) * - angles per dimension (3 entries) * num_charge_constraint_contig: num. of contiguous charge constraints for charge model * charge_constraint_contig_start: starting atom num. (1-based) of atom group for a charge constraint * charge_constraint_contig_end: ending atom num. (1-based) of atom group for a charge constraint * charge_constraint_contig_value: charge constraint value for atom group * num_charge_constraint_custom: num. of custom charge constraints for charge model * charge_constraint_custom_count: counts for each custom charge constraint * charge_constraint_custom_atom_index: atom indices (1-based) for custom charge constraints * charge_constraint_custom_coeff: coefficients for custom charge constraints * charge_constraint_custom_rhs: right-hand side (RHS) constants for custom charge constraints * ffield_file: file containing force field parameters * control_file: file containing simulation parameters */ void * setup_qmmm( int qm_num_atoms, const char * const qm_symbols, const double * const qm_pos, int mm_num_atoms, const char * const mm_symbols, const double * const mm_pos_q, const double * const sim_box_info, int num_charge_constraint_contig, const int * const charge_constraint_contig_start, const int * const charge_constraint_contig_end, const double * const charge_constraint_contig_value, int num_charge_constraint_custom, const int * const charge_constraint_custom_count, const int * const charge_constraint_custom_atom_index, const double * const charge_constraint_custom_coeff, const double * const charge_constraint_custom_rhs, const char * const ffield_file, const char * const control_file ) { int i; char element[3]; rvec x; spuremd_handle *spmd_handle; Allocate_Top_Level_Structs( &spmd_handle ); Initialize_Top_Level_Structs( spmd_handle ); /* override default */ spmd_handle->output_enabled = FALSE; Read_Input_Files( NULL, ffield_file, control_file, spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->out_control, FALSE ); spmd_handle->system->max_num_molec_charge_constraints = num_charge_constraint_contig; spmd_handle->system->num_molec_charge_constraints = num_charge_constraint_contig; if ( spmd_handle->system->num_molec_charge_constraints > 0 ) { spmd_handle->system->molec_charge_constraints = smalloc( sizeof(real) * spmd_handle->system->num_molec_charge_constraints, __FILE__, __LINE__ ); spmd_handle->system->molec_charge_constraint_ranges = smalloc( sizeof(int) * 2 * spmd_handle->system->num_molec_charge_constraints, __FILE__, __LINE__ ); for ( i = 0; i < spmd_handle->system->num_molec_charge_constraints; ++i ) { spmd_handle->system->molec_charge_constraint_ranges[2 * i] = charge_constraint_contig_start[i]; spmd_handle->system->molec_charge_constraint_ranges[2 * i + 1] = charge_constraint_contig_end[i]; spmd_handle->system->molec_charge_constraints[i] = charge_constraint_contig_value[i]; } } spmd_handle->system->max_num_custom_charge_constraints = num_charge_constraint_custom; spmd_handle->system->num_custom_charge_constraints = num_charge_constraint_custom; spmd_handle->system->num_custom_charge_constraint_entries = 0; if ( spmd_handle->system->num_custom_charge_constraints > 0 ) { spmd_handle->system->custom_charge_constraint_count = smalloc( sizeof(int) * spmd_handle->system->num_custom_charge_constraints, __FILE__, __LINE__ ); spmd_handle->system->custom_charge_constraint_start = smalloc( sizeof(int) * (spmd_handle->system->num_custom_charge_constraints + 1), __FILE__, __LINE__ ); spmd_handle->system->custom_charge_constraint_rhs = smalloc( sizeof(real) * spmd_handle->system->num_custom_charge_constraints, __FILE__, __LINE__ ); for ( i = 0; i < spmd_handle->system->num_custom_charge_constraints; ++i ) { spmd_handle->system->custom_charge_constraint_count[i] = charge_constraint_custom_count[i]; spmd_handle->system->custom_charge_constraint_start[i] = (i == 0 ? 0 : spmd_handle->system->custom_charge_constraint_start[i - 1] + charge_constraint_custom_count[i - 1]); spmd_handle->system->num_custom_charge_constraint_entries += charge_constraint_custom_count[i]; spmd_handle->system->custom_charge_constraint_rhs[i] = charge_constraint_custom_rhs[i]; } spmd_handle->system->custom_charge_constraint_start[spmd_handle->system->num_custom_charge_constraints] = spmd_handle->system->custom_charge_constraint_start[spmd_handle->system->num_custom_charge_constraints - 1] + charge_constraint_custom_count[spmd_handle->system->num_custom_charge_constraints - 1]; } spmd_handle->system->max_num_custom_charge_constraint_entries = spmd_handle->system->num_custom_charge_constraint_entries; if ( spmd_handle->system->num_custom_charge_constraint_entries > 0 ) { spmd_handle->system->custom_charge_constraint_atom_index = smalloc( sizeof(int) * spmd_handle->system->num_custom_charge_constraint_entries, __FILE__, __LINE__ ); spmd_handle->system->custom_charge_constraint_coeff = smalloc( sizeof(real) * spmd_handle->system->num_custom_charge_constraint_entries, __FILE__, __LINE__ ); for ( i = 0; i < spmd_handle->system->num_custom_charge_constraint_entries; ++i ) { spmd_handle->system->custom_charge_constraint_atom_index[i] = charge_constraint_custom_atom_index[i]; spmd_handle->system->custom_charge_constraint_coeff[i] = charge_constraint_custom_coeff[i]; } } spmd_handle->system->N_qm = qm_num_atoms; spmd_handle->system->N_mm = mm_num_atoms; spmd_handle->system->N = spmd_handle->system->N_qm + spmd_handle->system->N_mm; /* note: assign here to avoid compiler warning * of uninitialized usage in PreAllocate_Space */ spmd_handle->system->N_max = 0; PreAllocate_Space( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, (int) CEIL( SAFE_ZONE * spmd_handle->system->N ) ); Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2], sim_box_info[3], sim_box_info[4], sim_box_info[5], &spmd_handle->system->box ); element[2] = '\0'; for ( i = 0; i < spmd_handle->system->N_qm; ++i ) { x[0] = qm_pos[3 * i]; x[1] = qm_pos[3 * i + 1]; x[2] = qm_pos[3 * i + 2]; Fit_to_Periodic_Box( &spmd_handle->system->box, x ); spmd_handle->workspace->orig_id[i] = i + 1; element[0] = toupper( qm_symbols[2 * i] ); element[1] = toupper( qm_symbols[2 * i + 1] ); Trim_Spaces( element, sizeof(element) ); spmd_handle->system->atoms[i].type = Get_Atom_Type( &spmd_handle->system->reax_param, element, sizeof(element) ); strncpy( spmd_handle->system->atoms[i].name, element, sizeof(spmd_handle->system->atoms[i].name) - 1 ); spmd_handle->system->atoms[i].name[sizeof(spmd_handle->system->atoms[i].name) - 1] = '\0'; rvec_Copy( spmd_handle->system->atoms[i].x, x ); rvec_MakeZero( spmd_handle->system->atoms[i].v ); rvec_MakeZero( spmd_handle->system->atoms[i].f ); spmd_handle->system->atoms[i].q = 0.0; spmd_handle->system->atoms[i].q_init = 0.0; spmd_handle->system->atoms[i].qmmm_mask = TRUE; /* check for dummy atom */ if ( strncmp( element, "X\0", 2 ) == 0 ) { spmd_handle->system->atoms[i].is_dummy = TRUE; } else { spmd_handle->system->atoms[i].is_dummy = FALSE; } } for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i ) { x[0] = mm_pos_q[4 * (i - spmd_handle->system->N_qm)]; x[1] = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 1]; x[2] = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 2]; Fit_to_Periodic_Box( &spmd_handle->system->box, x ); spmd_handle->workspace->orig_id[i] = i + 1; element[0] = toupper( mm_symbols[2 * (i - spmd_handle->system->N_qm)] ); element[1] = toupper( mm_symbols[2 * (i - spmd_handle->system->N_qm) + 1] ); Trim_Spaces( element, sizeof(element) ); spmd_handle->system->atoms[i].type = Get_Atom_Type( &spmd_handle->system->reax_param, element, sizeof(element) ); strncpy( spmd_handle->system->atoms[i].name, element, sizeof(spmd_handle->system->atoms[i].name) - 1 ); spmd_handle->system->atoms[i].name[sizeof(spmd_handle->system->atoms[i].name) - 1] = '\0'; rvec_Copy( spmd_handle->system->atoms[i].x, x ); rvec_MakeZero( spmd_handle->system->atoms[i].v ); rvec_MakeZero( spmd_handle->system->atoms[i].f ); spmd_handle->system->atoms[i].q = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 3]; spmd_handle->system->atoms[i].q_init = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 3]; spmd_handle->system->atoms[i].qmmm_mask = FALSE; /* check for dummy atom */ if ( strncmp( element, "X\0", 2 ) == 0 ) { spmd_handle->system->atoms[i].is_dummy = TRUE; } else { spmd_handle->system->atoms[i].is_dummy = FALSE; } } spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N ); return (void *) spmd_handle; } /* Reset for the next simulation by parsing input files and triggering * reallocation if more space is needed * * handle: pointer to wrapper struct with top-level data structures * qm_num_atoms: num. atoms in the QM region * qm_symbols: element types for QM atoms * qm_pos: coordinates of QM atom positions (consecutively arranged), in Angstroms * mm_num_atoms: num. atoms in the MM region * mm_symbols: element types for MM atoms * mm_pos_q: coordinates and charges of MM atom positions (consecutively arranged), in Angstroms / Coulombs * sim_box_info: simulation box information, where the entries are * - box length per dimension (3 entries) * - angles per dimension (3 entries) * num_charge_constraint_contig: num. of contiguous charge constraints for charge model * charge_constraint_contig_start: starting atom num. (1-based) of atom group for a charge constraint * charge_constraint_contig_end: ending atom num. (1-based) of atom group for a charge constraint * charge_constraint_contig_value: charge constraint value for atom group * num_charge_constraint_custom: num. of custom charge constraints for charge model * charge_constraint_custom_count: counts for each custom charge constraint * charge_constraint_custom_atom_index: atom indices (1-based) for custom charge constraints * charge_constraint_custom_coeff: coefficients for custom charge constraints * charge_constraint_custom_rhs: right-hand side (RHS) constants for custom charge constraints * ffield_file: file containing force field parameters * control_file: file containing simulation parameters * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int reset_qmmm( const void * const handle, int qm_num_atoms, const char * const qm_symbols, const double * const qm_pos, int mm_num_atoms, const char * const mm_symbols, const double * const mm_pos_q, const double * const sim_box_info, int num_charge_constraint_contig, const int * const charge_constraint_contig_start, const int * const charge_constraint_contig_end, const double * const charge_constraint_contig_value, int num_charge_constraint_custom, const int * const charge_constraint_custom_count, const int * const charge_constraint_custom_atom_index, const double * const charge_constraint_custom_coeff, const double * const charge_constraint_custom_rhs, const char * const ffield_file, const char * const control_file ) { int i, ret; char element[3]; rvec x; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; /* close files used in previous simulation */ if ( spmd_handle->output_enabled == TRUE ) { Finalize_Out_Controls( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, spmd_handle->out_control ); } spmd_handle->realloc = FALSE; spmd_handle->data->sim_id++; Read_Input_Files( NULL, ffield_file, control_file, spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->out_control, TRUE ); spmd_handle->system->num_molec_charge_constraints = num_charge_constraint_contig; if ( spmd_handle->system->num_molec_charge_constraints > spmd_handle->system->max_num_molec_charge_constraints ) { if ( spmd_handle->system->max_num_molec_charge_constraints > 0 ) { sfree( spmd_handle->system->molec_charge_constraints, __FILE__, __LINE__ ); sfree( spmd_handle->system->molec_charge_constraint_ranges, __FILE__, __LINE__ ); } spmd_handle->system->molec_charge_constraints = smalloc( sizeof(real) * spmd_handle->system->num_molec_charge_constraints, __FILE__, __LINE__ ); spmd_handle->system->molec_charge_constraint_ranges = smalloc( sizeof(int) * 2 * spmd_handle->system->num_molec_charge_constraints, __FILE__, __LINE__ ); spmd_handle->system->max_num_molec_charge_constraints = spmd_handle->system->num_molec_charge_constraints; } if ( spmd_handle->system->num_molec_charge_constraints > 0 ) { for ( i = 0; i < spmd_handle->system->num_molec_charge_constraints; ++i ) { spmd_handle->system->molec_charge_constraint_ranges[2 * i] = charge_constraint_contig_start[i]; spmd_handle->system->molec_charge_constraint_ranges[2 * i + 1] = charge_constraint_contig_end[i]; spmd_handle->system->molec_charge_constraints[i] = charge_constraint_contig_value[i]; } } spmd_handle->system->num_custom_charge_constraints = num_charge_constraint_custom; if ( spmd_handle->system->num_custom_charge_constraints > spmd_handle->system->max_num_custom_charge_constraints ) { if ( spmd_handle->system->max_num_custom_charge_constraints > 0 ) { sfree( spmd_handle->system->custom_charge_constraint_count, __FILE__, __LINE__ ); sfree( spmd_handle->system->custom_charge_constraint_start, __FILE__, __LINE__ ); sfree( spmd_handle->system->custom_charge_constraint_rhs, __FILE__, __LINE__ ); } spmd_handle->system->custom_charge_constraint_count = smalloc( sizeof(int) * spmd_handle->system->num_custom_charge_constraints, __FILE__, __LINE__ ); spmd_handle->system->custom_charge_constraint_start = smalloc( sizeof(int) * (spmd_handle->system->num_custom_charge_constraints + 1), __FILE__, __LINE__ ); spmd_handle->system->custom_charge_constraint_rhs = smalloc( sizeof(real) * spmd_handle->system->num_custom_charge_constraints, __FILE__, __LINE__ ); spmd_handle->system->max_num_custom_charge_constraints = spmd_handle->system->num_custom_charge_constraints; } spmd_handle->system->num_custom_charge_constraint_entries = 0; if ( spmd_handle->system->num_custom_charge_constraints > 0 ) { for ( i = 0; i < spmd_handle->system->num_custom_charge_constraints; ++i ) { spmd_handle->system->custom_charge_constraint_count[i] = charge_constraint_custom_count[i]; spmd_handle->system->custom_charge_constraint_start[i] = (i == 0 ? 0 : spmd_handle->system->custom_charge_constraint_start[i - 1] + charge_constraint_custom_count[i - 1]); spmd_handle->system->num_custom_charge_constraint_entries += charge_constraint_custom_count[i]; spmd_handle->system->custom_charge_constraint_rhs[i] = charge_constraint_custom_rhs[i]; } spmd_handle->system->custom_charge_constraint_start[spmd_handle->system->num_custom_charge_constraints] = spmd_handle->system->custom_charge_constraint_start[spmd_handle->system->num_custom_charge_constraints - 1] + charge_constraint_custom_count[spmd_handle->system->num_custom_charge_constraints - 1]; } if ( spmd_handle->system->num_custom_charge_constraint_entries > spmd_handle->system->max_num_custom_charge_constraint_entries ) { if ( spmd_handle->system->max_num_custom_charge_constraint_entries > 0 ) { sfree( spmd_handle->system->custom_charge_constraint_atom_index, __FILE__, __LINE__ ); sfree( spmd_handle->system->custom_charge_constraint_coeff, __FILE__, __LINE__ ); } spmd_handle->system->custom_charge_constraint_atom_index = smalloc( sizeof(int) * spmd_handle->system->num_custom_charge_constraint_entries, __FILE__, __LINE__ ); spmd_handle->system->custom_charge_constraint_coeff = smalloc( sizeof(real) * spmd_handle->system->num_custom_charge_constraint_entries, __FILE__, __LINE__ ); spmd_handle->system->max_num_custom_charge_constraint_entries = spmd_handle->system->num_custom_charge_constraint_entries; } if ( spmd_handle->system->num_custom_charge_constraint_entries > 0 ) { for ( i = 0; i < spmd_handle->system->num_custom_charge_constraint_entries; ++i ) { spmd_handle->system->custom_charge_constraint_atom_index[i] = charge_constraint_custom_atom_index[i]; spmd_handle->system->custom_charge_constraint_coeff[i] = charge_constraint_custom_coeff[i]; } } spmd_handle->system->N_qm = qm_num_atoms; spmd_handle->system->N_mm = mm_num_atoms; spmd_handle->system->N = spmd_handle->system->N_qm + spmd_handle->system->N_mm; if ( spmd_handle->system->prealloc_allocated == FALSE || spmd_handle->system->N > spmd_handle->system->N_max ) { PreAllocate_Space( spmd_handle->system, spmd_handle->control, spmd_handle->workspace, (int) CEIL( SAFE_ZONE * spmd_handle->system->N ) ); } Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2], sim_box_info[3], sim_box_info[4], sim_box_info[5], &spmd_handle->system->box ); element[2] = '\0'; for ( i = 0; i < spmd_handle->system->N_qm; ++i ) { x[0] = qm_pos[3 * i]; x[1] = qm_pos[3 * i + 1]; x[2] = qm_pos[3 * i + 2]; Fit_to_Periodic_Box( &spmd_handle->system->box, x ); spmd_handle->workspace->orig_id[i] = i + 1; element[0] = toupper( qm_symbols[2 * i] ); element[1] = toupper( qm_symbols[2 * i + 1] ); Trim_Spaces( element, sizeof(element) ); spmd_handle->system->atoms[i].type = Get_Atom_Type( &spmd_handle->system->reax_param, element, sizeof(element) ); strncpy( spmd_handle->system->atoms[i].name, element, sizeof(spmd_handle->system->atoms[i].name) - 1 ); spmd_handle->system->atoms[i].name[sizeof(spmd_handle->system->atoms[i].name) - 1] = '\0'; rvec_Copy( spmd_handle->system->atoms[i].x, x ); rvec_MakeZero( spmd_handle->system->atoms[i].v ); rvec_MakeZero( spmd_handle->system->atoms[i].f ); spmd_handle->system->atoms[i].q = 0.0; spmd_handle->system->atoms[i].q_init = 0.0; spmd_handle->system->atoms[i].qmmm_mask = TRUE; /* check for dummy atom */ if ( strncmp( element, "X\0", 2 ) == 0 ) { spmd_handle->system->atoms[i].is_dummy = TRUE; } else { spmd_handle->system->atoms[i].is_dummy = FALSE; } } for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i ) { x[0] = mm_pos_q[4 * (i - spmd_handle->system->N_qm)]; x[1] = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 1]; x[2] = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 2]; Fit_to_Periodic_Box( &spmd_handle->system->box, x ); spmd_handle->workspace->orig_id[i] = i + 1; element[0] = toupper( mm_symbols[2 * (i - spmd_handle->system->N_qm)] ); element[1] = toupper( mm_symbols[2 * (i - spmd_handle->system->N_qm) + 1] ); Trim_Spaces( element, sizeof(element) ); spmd_handle->system->atoms[i].type = Get_Atom_Type( &spmd_handle->system->reax_param, element, sizeof(element) ); strncpy( spmd_handle->system->atoms[i].name, element, sizeof(spmd_handle->system->atoms[i].name) - 1 ); spmd_handle->system->atoms[i].name[sizeof(spmd_handle->system->atoms[i].name) - 1] = '\0'; rvec_Copy( spmd_handle->system->atoms[i].x, x ); rvec_MakeZero( spmd_handle->system->atoms[i].v ); rvec_MakeZero( spmd_handle->system->atoms[i].f ); spmd_handle->system->atoms[i].q = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 3]; spmd_handle->system->atoms[i].q_init = mm_pos_q[4 * (i - spmd_handle->system->N_qm) + 3]; spmd_handle->system->atoms[i].qmmm_mask = FALSE; /* check for dummy atom */ if ( strncmp( element, "X\0", 2 ) == 0 ) { spmd_handle->system->atoms[i].is_dummy = TRUE; } else { spmd_handle->system->atoms[i].is_dummy = FALSE; } } if ( spmd_handle->system->N > spmd_handle->system->N_max ) { /* deallocate everything which needs more space * (i.e., structures whose space is a function of the number of atoms), * except for data structures allocated while parsing input files */ Finalize( spmd_handle->system, spmd_handle->control, spmd_handle->data, spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control, spmd_handle->output_enabled, TRUE ); spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N ); spmd_handle->realloc = TRUE; } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom positions in QMMM mode * * handle: pointer to wrapper struct with top-level data structures * qm_pos: coordinates of QM atom positions (consecutively arranged), in Angstroms (allocated by caller) * mm_pos: coordinates of MM atom positions (consecutively arranged), in Angstroms (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_positions_qmmm( const void * const handle, double * const qm_pos, double * const mm_pos ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; if ( qm_pos != NULL ) { for ( i = 0; i < spmd_handle->system->N_qm; ++i ) { qm_pos[3 * i] = spmd_handle->system->atoms[i].x[0]; qm_pos[3 * i + 1] = spmd_handle->system->atoms[i].x[1]; qm_pos[3 * i + 2] = spmd_handle->system->atoms[i].x[2]; } } if ( mm_pos != NULL ) { for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i ) { mm_pos[3 * (i - spmd_handle->system->N_qm)] = spmd_handle->system->atoms[i].x[0]; mm_pos[3 * (i - spmd_handle->system->N_qm) + 1] = spmd_handle->system->atoms[i].x[1]; mm_pos[3 * (i - spmd_handle->system->N_qm) + 2] = spmd_handle->system->atoms[i].x[2]; } } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom velocities in QMMM mode * * handle: pointer to wrapper struct with top-level data structures * qm_vel: coordinates of QM atom velocities (consecutively arranged), in Angstroms / ps (allocated by caller) * mm_vel: coordinates of MM atom velocities (consecutively arranged), in Angstroms / ps (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_velocities_qmmm( const void * const handle, double * const qm_vel, double * const mm_vel ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; if ( qm_vel != NULL ) { for ( i = 0; i < spmd_handle->system->N_qm; ++i ) { qm_vel[3 * i] = spmd_handle->system->atoms[i].v[0]; qm_vel[3 * i + 1] = spmd_handle->system->atoms[i].v[1]; qm_vel[3 * i + 2] = spmd_handle->system->atoms[i].v[2]; } } if ( mm_vel != NULL ) { for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i ) { mm_vel[3 * (i - spmd_handle->system->N_qm)] = spmd_handle->system->atoms[i].v[0]; mm_vel[3 * (i - spmd_handle->system->N_qm) + 1] = spmd_handle->system->atoms[i].v[1]; mm_vel[3 * (i - spmd_handle->system->N_qm) + 2] = spmd_handle->system->atoms[i].v[2]; } } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom forces in QMMM mode * * handle: pointer to wrapper struct with top-level data structures * qm_f: coordinates of QM atom forces (consecutively arranged), in Angstroms * Daltons / ps^2 (allocated by caller) * mm_f: coordinates of MM atom forces (consecutively arranged), in Angstroms * Daltons / ps^2 (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_forces_qmmm( const void * const handle, double * const qm_f, double * const mm_f ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; if ( qm_f != NULL ) { for ( i = 0; i < spmd_handle->system->N_qm; ++i ) { qm_f[3 * i] = spmd_handle->system->atoms[i].f[0]; qm_f[3 * i + 1] = spmd_handle->system->atoms[i].f[1]; qm_f[3 * i + 2] = spmd_handle->system->atoms[i].f[2]; } } if ( mm_f != NULL ) { for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i ) { mm_f[3 * (i - spmd_handle->system->N_qm)] = spmd_handle->system->atoms[i].f[0]; mm_f[3 * (i - spmd_handle->system->N_qm) + 1] = spmd_handle->system->atoms[i].f[1]; mm_f[3 * (i - spmd_handle->system->N_qm) + 2] = spmd_handle->system->atoms[i].f[2]; } } ret = SPUREMD_SUCCESS; } return ret; } /* Getter for atom charges in QMMM mode * * handle: pointer to wrapper struct with top-level data structures * qm_q: QM atom charges, in Coulombs (allocated by caller) * mm_q: MM atom charges, in Coulombs (allocated by caller) * * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise */ int get_atom_charges_qmmm( const void * const handle, double * const qm_q, double * const mm_q ) { int i, ret; spuremd_handle *spmd_handle; ret = SPUREMD_FAILURE; if ( handle != NULL ) { spmd_handle = (spuremd_handle*) handle; if ( qm_q != NULL ) { for ( i = 0; i < spmd_handle->system->N_qm; ++i ) { qm_q[i] = spmd_handle->system->atoms[i].q; } } if ( mm_q != NULL ) { for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i ) { mm_q[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].q; } } ret = SPUREMD_SUCCESS; } return ret; } #endif