From b8d76adabce7f436edf6f30625698b3c5da6076d Mon Sep 17 00:00:00 2001
From: "Kurt A. O'Hearn" <ohearnku@msu.edu>
Date: Mon, 4 Jan 2021 14:11:33 -0500
Subject: [PATCH] sPuReMD: add QMMM library interface for external codes (e.g.,
 Amber). Rework file I/O parsing to jive with multiple consecutive simulation
 code changes. Improve file parser error checking (numeric types). Other code
 clean-up.

---
 sPuReMD/src/charges.c    |   6 +-
 sPuReMD/src/control.c    | 843 +++++++++++++++++++--------------------
 sPuReMD/src/control.h    |   5 +-
 sPuReMD/src/ffield.c     | 213 +++++-----
 sPuReMD/src/ffield.h     |   3 +-
 sPuReMD/src/forces.c     |   2 +-
 sPuReMD/src/geo_tools.c  |  36 +-
 sPuReMD/src/init_md.c    |  30 +-
 sPuReMD/src/io_tools.c   |  26 +-
 sPuReMD/src/lin_alg.c    |  12 +-
 sPuReMD/src/reax_types.h |   3 +-
 sPuReMD/src/spuremd.c    | 510 +++++++++++++++++++++--
 sPuReMD/src/spuremd.h    |  32 +-
 sPuReMD/src/tool_box.c   | 138 +++++++
 sPuReMD/src/tool_box.h   |  36 +-
 sPuReMD/src/vector.h     |  12 +-
 tools/driver_qmmm.py     | 524 ++++++++++++++++++++++++
 17 files changed, 1777 insertions(+), 654 deletions(-)
 create mode 100644 tools/driver_qmmm.py

diff --git a/sPuReMD/src/charges.c b/sPuReMD/src/charges.c
index a392fbfc..4695942e 100644
--- a/sPuReMD/src/charges.c
+++ b/sPuReMD/src/charges.c
@@ -588,7 +588,7 @@ static void Compute_Preconditioner_QEq( const reax_system * const system,
     //if ( control->cm_solver_pre_comp_refactor == -1 )
     //{
     //    data->timing.cm_last_pre_comp = data->timing.cm_solver_pre_comp;
-    //    data->timing.cm_total_loss = ZERO;
+    //    data->timing.cm_total_loss = 0.0;
     //}
 
 #if defined(DEBUG)
@@ -710,7 +710,7 @@ static void Compute_Preconditioner_EE( const reax_system * const system,
     //if ( control->cm_solver_pre_comp_refactor == -1 )
     //{
     //    data->timing.cm_last_pre_comp = data->timing.cm_solver_pre_comp;
-    //    data->timing.cm_total_loss = ZERO;
+    //    data->timing.cm_total_loss = 0.0;
     //}
 
     if ( control->cm_solver_pre_app_type == TRI_SOLVE_GC_PA )
@@ -851,7 +851,7 @@ static void Compute_Preconditioner_ACKS2( const reax_system * const system,
     //if ( control->cm_solver_pre_comp_refactor == -1 )
     //{
     //    data->timing.cm_last_pre_comp = data->timing.cm_solver_pre_comp;
-    //    data->timing.cm_total_loss = ZERO;
+    //    data->timing.cm_total_loss = 0.0;
     //}
 
     if ( control->cm_solver_pre_app_type == TRI_SOLVE_GC_PA )
diff --git a/sPuReMD/src/control.c b/sPuReMD/src/control.c
index 28978fa2..8019737a 100644
--- a/sPuReMD/src/control.c
+++ b/sPuReMD/src/control.c
@@ -29,13 +29,416 @@
 #include "tool_box.h"
 
 
-void Read_Control_File( FILE* fp, reax_system *system, control_params* control,
-        output_controls *out_control )
+int Set_Control_Parameter( const char * const keyword,
+        const char ** const values, control_params * const control,
+        output_controls * const out_control )
 {
-    char *s, **tmp;
-    int c, i, ival;
+    int i, ret;
     real val;
 
+    ret = SUCCESS;
+
+    if ( strncmp(keyword, "simulation_name", MAX_LINE) == 0 )
+    {
+        strncpy( control->sim_name, values[0], sizeof(control->sim_name) - 1 );
+        control->sim_name[sizeof(control->sim_name) - 1] = '\0';
+    }
+    //else if( strncmp(keyword, "restart", MAX_LINE) == 0 ) {
+    //  control->restart = sstrtol( values[0], __FILE__, __LINE__ );
+    //}
+    else if ( strncmp(keyword, "restart_format", MAX_LINE) == 0 )
+    {
+        out_control->restart_format = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "restart_freq", MAX_LINE) == 0 )
+    {
+        out_control->restart_freq = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "random_vel", MAX_LINE) == 0 )
+    {
+        control->random_vel = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "reposition_atoms", MAX_LINE) == 0 )
+    {
+        control->reposition_atoms = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "ensemble_type", MAX_LINE) == 0 )
+    {
+        control->ensemble = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "nsteps", MAX_LINE) == 0 )
+    {
+        control->nsteps = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "dt", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        /* convert from fs to ps */
+        control->dt = val * 1.0e-3;
+    }
+    else if ( strncmp(keyword, "gpus_per_node", MAX_LINE) == 0 )
+    {
+        // skip since not applicable to shared memory code
+        ;
+    }
+    else if ( strncmp(keyword, "proc_by_dim", MAX_LINE) == 0 )
+    {
+        // skip since not applicable to shared memory code
+        ;
+    }
+    else if ( strncmp(keyword, "periodic_boundaries", MAX_LINE) == 0 )
+    {
+        control->periodic_boundaries = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "geo_format", MAX_LINE) == 0 )
+    {
+        control->geo_format = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "restrict_bonds", MAX_LINE) == 0 )
+    {
+        control->restrict_bonds = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "tabulate_long_range", MAX_LINE) == 0 )
+    {
+        control->tabulate = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "reneighbor", MAX_LINE) == 0 )
+    {
+        control->reneighbor = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "vlist_buffer", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->vlist_cut = control->nonb_cut + val;
+    }
+    else if ( strncmp(keyword, "nbrhood_cutoff", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->bond_cut = val;
+    }
+    else if ( strncmp(keyword, "thb_cutoff", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->thb_cut = val;
+    }
+    else if ( strncmp(keyword, "hbond_cutoff", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->hbond_cut = val;
+    }
+    else if ( strncmp(keyword, "charge_method", MAX_LINE) == 0 )
+    {
+        control->charge_method = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_q_net", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->cm_q_net = val;
+    }
+    else if ( strncmp(keyword, "cm_solver_type", MAX_LINE) == 0 )
+    {
+        control->cm_solver_type = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_max_iters", MAX_LINE) == 0 )
+    {
+        control->cm_solver_max_iters = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_restart", MAX_LINE) == 0 )
+    {
+        control->cm_solver_restart = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_q_err", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->cm_solver_q_err = val;
+    }
+    else if ( strncmp(keyword, "cm_domain_sparsity", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->cm_domain_sparsity = val;
+        if ( val < 1.0 )
+        {
+            control->cm_domain_sparsify_enabled = TRUE;
+        }
+    }
+    else if ( strncmp(keyword, "cm_init_guess_type", MAX_LINE) == 0 )
+    {
+        control->cm_init_guess_type = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_init_guess_extrap1", MAX_LINE) == 0 )
+    {
+        control->cm_init_guess_extrap1 = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_init_guess_extrap2", MAX_LINE) == 0 )
+    {
+        control->cm_init_guess_extrap2 = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_init_guess_gd_model", MAX_LINE) == 0 )
+    {
+        strncpy( control->cm_init_guess_gd_model, values[0], sizeof(control->cm_init_guess_gd_model) - 1 );
+        control->cm_init_guess_gd_model[sizeof(control->cm_init_guess_gd_model) - 1] = '\0';
+    }
+    else if ( strncmp(keyword, "cm_init_guess_win_size", MAX_LINE) == 0 )
+    {
+        control->cm_init_guess_win_size = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_pre_comp_type", MAX_LINE) == 0 )
+    {
+        control->cm_solver_pre_comp_type = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_pre_comp_refactor", MAX_LINE) == 0 )
+    {
+        control->cm_solver_pre_comp_refactor = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_pre_comp_droptol", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->cm_solver_pre_comp_droptol = val;
+    }
+    else if ( strncmp(keyword, "cm_solver_pre_comp_sweeps", MAX_LINE) == 0 )
+    {
+        control->cm_solver_pre_comp_sweeps = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_pre_comp_sai_thres", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->cm_solver_pre_comp_sai_thres = val;
+    }
+    else if ( strncmp(keyword, "cm_solver_pre_app_type", MAX_LINE) == 0 )
+    {
+        control->cm_solver_pre_app_type = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "cm_solver_pre_app_jacobi_iters", MAX_LINE) == 0 )
+    {
+        control->cm_solver_pre_app_jacobi_iters = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "temp_init", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->T_init = val;
+
+        if ( control->T_init < 0.001 )
+        {
+            control->T_init = 0.001;
+        }
+    }
+    else if ( strncmp(keyword, "temp_final", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->T_final = val;
+
+        if ( control->T_final < 0.1 )
+        {
+            control->T_final = 0.1;
+        }
+    }
+    else if ( strncmp(keyword, "t_mass", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        /* convert from fs to s */
+        control->Tau_T = val * 1.0e-15;
+    }
+    else if ( strncmp(keyword, "t_mode", MAX_LINE) == 0 )
+    {
+        control->T_mode = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "t_rate", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->T_rate = val;
+    }
+    else if ( strncmp(keyword, "t_freq", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->T_freq = val;
+    }
+    else if ( strncmp(keyword, "pressure", MAX_LINE) == 0 )
+    {
+        if ( control->ensemble == iNPT )
+        {
+            val = sstrtod( values[0], __FILE__, __LINE__ );
+            control->P[0] = val;
+            control->P[1] = val;
+            control->P[2] = val;
+        }
+        else if ( control->ensemble == sNPT )
+        {
+            val = sstrtod( values[0], __FILE__, __LINE__ );
+            control->P[0] = val;
+
+            val = sstrtod( values[1], __FILE__, __LINE__ );
+            control->P[1] = val;
+
+            val = sstrtod( values[2], __FILE__, __LINE__ );
+            control->P[2] = val;
+        }
+    }
+    else if ( strncmp(keyword, "p_mass", MAX_LINE) == 0 )
+    {
+        if ( control->ensemble == iNPT )
+        {
+            val = sstrtod( values[0], __FILE__, __LINE__ );
+            control->Tau_P[0] = val * 1.0e-3;   // convert p_mass from fs to ps
+        }
+        else if ( control->ensemble == sNPT )
+        {
+            val = sstrtod( values[0], __FILE__, __LINE__ );
+            control->Tau_P[0] = val * 1.0e-3;   // convert p_mass from fs to ps
+
+            val = sstrtod( values[1], __FILE__, __LINE__ );
+            control->Tau_P[1] = val * 1.0e-3;   // convert p_mass from fs to ps
+
+            val = sstrtod( values[2], __FILE__, __LINE__ );
+            control->Tau_P[2] = val * 1.0e-3;   // convert p_mass from fs to ps
+        }
+    }
+    else if ( strncmp(keyword, "pt_mass", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->Tau_PT = val * 1.0e-3;  // convert pt_mass from fs to ps
+    }
+    else if ( strncmp(keyword, "compress", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->compressibility = val;
+    }
+    else if ( strncmp(keyword, "press_mode", MAX_LINE) == 0 )
+    {
+        control->press_mode = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "compute_pressure", MAX_LINE) == 0 )
+    {
+        control->compute_pressure = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "remove_CoM_vel", MAX_LINE) == 0 )
+    {
+        control->remove_CoM_vel = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "energy_update_freq", MAX_LINE) == 0 )
+    {
+        out_control->log_update_freq = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "write_freq", MAX_LINE) == 0 )
+    {
+        out_control->write_steps = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "traj_compress", MAX_LINE) == 0 )
+    {
+        out_control->traj_compress = sstrtol( values[0], __FILE__, __LINE__ );
+
+        if ( out_control->traj_compress )
+        {
+            out_control->write = (int (*)(FILE *, const char *, ...)) &gzprintf;
+        }
+        else
+        {
+            out_control->write = &fprintf;
+        }
+    }
+    else if ( strncmp(keyword, "traj_format", MAX_LINE) == 0 )
+    {
+        out_control->traj_format = sstrtol( values[0], __FILE__, __LINE__ );
+
+        if ( out_control->traj_format == 0 )
+        {
+            out_control->write_header = &Write_Custom_Header;
+            out_control->append_traj_frame = &Append_Custom_Frame;
+        }
+        else if ( out_control->traj_format == 1 )
+        {
+            out_control->write_header = &Write_xyz_Header;
+            out_control->append_traj_frame = &Append_xyz_Frame;
+        }
+    }
+    else if ( strncmp(keyword, "traj_title", MAX_LINE) == 0 )
+    {
+        strncpy( out_control->traj_title, values[0], sizeof(out_control->traj_title) - 1 );
+        out_control->traj_title[sizeof(out_control->traj_title) - 1] = '\0';
+    }
+    else if ( strncmp(keyword, "atom_info", MAX_LINE) == 0 )
+    {
+        out_control->atom_format +=
+            sstrtol( values[0], __FILE__, __LINE__ ) * 4;
+    }
+    else if ( strncmp(keyword, "atom_velocities", MAX_LINE) == 0 )
+    {
+        out_control->atom_format +=
+            sstrtol( values[0], __FILE__, __LINE__ ) * 2;
+    }
+    else if ( strncmp(keyword, "atom_forces", MAX_LINE) == 0 )
+    {
+        out_control->atom_format +=
+            sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "bond_info", MAX_LINE) == 0 )
+    {
+        out_control->bond_info = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "angle_info", MAX_LINE) == 0 )
+    {
+        out_control->angle_info = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "test_forces", MAX_LINE) == 0 )
+    {
+        ;
+    }
+    else if ( strncmp(keyword, "molec_anal", MAX_LINE) == 0 )
+    {
+        control->molec_anal = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "freq_molec_anal", MAX_LINE) == 0 )
+    {
+        control->freq_molec_anal = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "bond_graph_cutoff", MAX_LINE) == 0 )
+    {
+        val = sstrtod( values[0], __FILE__, __LINE__ );
+        control->bg_cut = val;
+    }
+    else if ( strncmp(keyword, "ignore", MAX_LINE) == 0 )
+    {
+        control->num_ignored = sstrtol( values[0], __FILE__, __LINE__ );
+        for ( i = 0; i < control->num_ignored; ++i )
+            control->ignore[ sstrtol( values[i + 1], __FILE__, __LINE__ ) ] = 1;
+    }
+    else if ( strncmp(keyword, "dipole_anal", MAX_LINE) == 0 )
+    {
+        control->dipole_anal = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "freq_dipole_anal", MAX_LINE) == 0 )
+    {
+        control->freq_dipole_anal = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "diffusion_coef", MAX_LINE) == 0 )
+    {
+        control->diffusion_coef = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "freq_diffusion_coef", MAX_LINE) == 0 )
+    {
+        control->freq_diffusion_coef = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else if ( strncmp(keyword, "restrict_type", MAX_LINE) == 0 )
+    {
+        control->restrict_type = sstrtol( values[0], __FILE__, __LINE__ );
+    }
+    else
+    {
+        ret = FAILURE;
+    }
+
+    return ret;
+}
+
+
+void Read_Control_File( const char * const control_file, reax_system * const system,
+        control_params * const  control, output_controls * const out_control )
+{
+    char *s, **tmp;
+    int c, i, ret;
+    FILE *fp;
+
+    fp = sfopen( control_file, "r" );
+
     assert( fp != NULL );
 
     /* assign default values */
@@ -166,432 +569,10 @@ void Read_Control_File( FILE* fp, reax_system *system, control_params* control,
 
             if ( c > 0 )
             {
-                if ( strncmp(tmp[0], "simulation_name", MAX_LINE) == 0 )
-                {
-                    strncpy( control->sim_name, tmp[1], sizeof(control->sim_name) - 1 );
-                    control->sim_name[sizeof(control->sim_name) - 1] = '\0';
-                }
-                //else if( strncmp(tmp[0], "restart", MAX_LINE) == 0 ) {
-                //  ival = atoi(tmp[1]);
-                //  control->restart = ival;
-                //}
-                else if ( strncmp(tmp[0], "restart_format", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->restart_format = ival;
-                }
-                else if ( strncmp(tmp[0], "restart_freq", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->restart_freq = ival;
-                }
-                else if ( strncmp(tmp[0], "random_vel", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->random_vel = ival;
-                }
-                else if ( strncmp(tmp[0], "reposition_atoms", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->reposition_atoms = ival;
-                }
-                else if ( strncmp(tmp[0], "ensemble_type", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->ensemble = ival;
-                }
-                else if ( strncmp(tmp[0], "nsteps", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->nsteps = ival;
-                }
-                else if ( strncmp(tmp[0], "dt", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    /* convert from fs to ps */
-                    control->dt = val * 1.0e-3;
-                }
-                else if ( strncmp(tmp[0], "gpus_per_node", MAX_LINE) == 0 )
-                {
-                    // skip since not applicable to shared memory code
-                    ;
-                }
-                else if ( strncmp(tmp[0], "proc_by_dim", MAX_LINE) == 0 )
-                {
-                    // skip since not applicable to shared memory code
-                    ;
-                }
-                else if ( strncmp(tmp[0], "periodic_boundaries", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->periodic_boundaries = ival;
-                }
-                else if ( strncmp(tmp[0], "geo_format", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->geo_format = ival;
-                }
-                else if ( strncmp(tmp[0], "restrict_bonds", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->restrict_bonds = ival;
-                }
-                else if ( strncmp(tmp[0], "tabulate_long_range", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->tabulate = ival;
-                }
-                else if ( strncmp(tmp[0], "reneighbor", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->reneighbor = ival;
-                }
-                else if ( strncmp(tmp[0], "vlist_buffer", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->vlist_cut = control->nonb_cut + val;
-                }
-                else if ( strncmp(tmp[0], "nbrhood_cutoff", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->bond_cut = val;
-                }
-                else if ( strncmp(tmp[0], "thb_cutoff", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->thb_cut = val;
-                }
-                else if ( strncmp(tmp[0], "hbond_cutoff", MAX_LINE) == 0 )
-                {
-                    val = atof( tmp[1] );
-                    control->hbond_cut = val;
-                }
-                else if ( strncmp(tmp[0], "charge_method", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->charge_method = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_q_net", MAX_LINE) == 0 )
-                {
-                    val = atof( tmp[1] );
-                    control->cm_q_net = val;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_type", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_type = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_max_iters", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_max_iters = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_restart", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_restart = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_q_err", MAX_LINE) == 0 )
-                {
-                    val = atof( tmp[1] );
-                    control->cm_solver_q_err = val;
-                }
-                else if ( strncmp(tmp[0], "cm_domain_sparsity", MAX_LINE) == 0 )
-                {
-                    val = atof( tmp[1] );
-                    control->cm_domain_sparsity = val;
-                    if ( val < 1.0 )
-                    {
-                        control->cm_domain_sparsify_enabled = TRUE;
-                    }
-                }
-                else if ( strncmp(tmp[0], "cm_init_guess_type", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_init_guess_type = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_init_guess_extrap1", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_init_guess_extrap1 = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_init_guess_extrap2", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_init_guess_extrap2 = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_init_guess_gd_model", MAX_LINE) == 0 )
-                {
-                    strncpy( control->cm_init_guess_gd_model, tmp[1], sizeof(control->cm_init_guess_gd_model) - 1 );
-                    control->cm_init_guess_gd_model[sizeof(control->cm_init_guess_gd_model) - 1] = '\0';
-                }
-                else if ( strncmp(tmp[0], "cm_init_guess_win_size", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_init_guess_win_size = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_pre_comp_type", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_pre_comp_type = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_pre_comp_refactor", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_pre_comp_refactor = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_pre_comp_droptol", MAX_LINE) == 0 )
-                {
-                    val = atof( tmp[1] );
-                    control->cm_solver_pre_comp_droptol = val;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_pre_comp_sweeps", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_pre_comp_sweeps = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_pre_comp_sai_thres", MAX_LINE) == 0 )
-                {
-                    val = atof( tmp[1] );
-                    control->cm_solver_pre_comp_sai_thres = val;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_pre_app_type", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_pre_app_type = ival;
-                }
-                else if ( strncmp(tmp[0], "cm_solver_pre_app_jacobi_iters", MAX_LINE) == 0 )
-                {
-                    ival = atoi( tmp[1] );
-                    control->cm_solver_pre_app_jacobi_iters = ival;
-                }
-                else if ( strncmp(tmp[0], "temp_init", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->T_init = val;
-
-                    if ( control->T_init < 0.001 )
-                    {
-                        control->T_init = 0.001;
-                    }
-                }
-                else if ( strncmp(tmp[0], "temp_final", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->T_final = val;
+                ret = Set_Control_Parameter( tmp[0],
+                        (const char ** const) &tmp[1], control, out_control );
 
-                    if ( control->T_final < 0.1 )
-                    {
-                        control->T_final = 0.1;
-                    }
-                }
-                else if ( strncmp(tmp[0], "t_mass", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    /* convert from fs to s */
-                    control->Tau_T = val * 1.0e-15;
-                }
-                else if ( strncmp(tmp[0], "t_mode", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->T_mode = ival;
-                }
-                else if ( strncmp(tmp[0], "t_rate", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->T_rate = val;
-                }
-                else if ( strncmp(tmp[0], "t_freq", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->T_freq = val;
-                }
-                else if ( strncmp(tmp[0], "pressure", MAX_LINE) == 0 )
-                {
-                    if ( control->ensemble == iNPT )
-                    {
-                        val = atof(tmp[1]);
-                        control->P[0] = val;
-                        control->P[1] = val;
-                        control->P[2] = val;
-                    }
-                    else if ( control->ensemble == sNPT )
-                    {
-                        val = atof(tmp[1]);
-                        control->P[0] = val;
-
-                        val = atof(tmp[2]);
-                        control->P[1] = val;
-
-                        val = atof(tmp[3]);
-                        control->P[2] = val;
-                    }
-                }
-                else if ( strncmp(tmp[0], "p_mass", MAX_LINE) == 0 )
-                {
-                    if ( control->ensemble == iNPT )
-                    {
-                        val = atof(tmp[1]);
-                        control->Tau_P[0] = val * 1.0e-3;   // convert p_mass from fs to ps
-                    }
-                    else if ( control->ensemble == sNPT )
-                    {
-                        val = atof(tmp[1]);
-                        control->Tau_P[0] = val * 1.0e-3;   // convert p_mass from fs to ps
-
-                        val = atof(tmp[2]);
-                        control->Tau_P[1] = val * 1.0e-3;   // convert p_mass from fs to ps
-
-                        val = atof(tmp[3]);
-                        control->Tau_P[2] = val * 1.0e-3;   // convert p_mass from fs to ps
-                    }
-                }
-                else if ( strncmp(tmp[0], "pt_mass", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->Tau_PT = val * 1.0e-3;  // convert pt_mass from fs to ps
-                }
-                else if ( strncmp(tmp[0], "compress", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->compressibility = val;
-                }
-                else if ( strncmp(tmp[0], "press_mode", MAX_LINE) == 0 )
-                {
-                    val = atoi(tmp[1]);
-                    control->press_mode = val;
-                }
-                else if ( strncmp(tmp[0], "compute_pressure", MAX_LINE) == 0 )
-                {
-                    val = atoi(tmp[1]);
-                    control->compute_pressure = val;
-                }
-                else if ( strncmp(tmp[0], "remove_CoM_vel", MAX_LINE) == 0 )
-                {
-                    val = atoi(tmp[1]);
-                    control->remove_CoM_vel = val;
-                }
-                else if ( strncmp(tmp[0], "energy_update_freq", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->log_update_freq = ival;
-                }
-                else if ( strncmp(tmp[0], "write_freq", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->write_steps = ival;
-                }
-                else if ( strncmp(tmp[0], "traj_compress", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->traj_compress = ival;
-
-                    if ( out_control->traj_compress )
-                    {
-                        out_control->write = (int (*)(FILE *, const char *, ...)) &gzprintf;
-                    }
-                    else
-                    {
-                        out_control->write = &fprintf;
-                    }
-                }
-                else if ( strncmp(tmp[0], "traj_format", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->traj_format = ival;
-
-                    if ( out_control->traj_format == 0 )
-                    {
-                        out_control->write_header = &Write_Custom_Header;
-                        out_control->append_traj_frame = &Append_Custom_Frame;
-                    }
-                    else if ( out_control->traj_format == 1 )
-                    {
-                        out_control->write_header = &Write_xyz_Header;
-                        out_control->append_traj_frame = &Append_xyz_Frame;
-                    }
-                }
-                else if ( strncmp(tmp[0], "traj_title", MAX_LINE) == 0 )
-                {
-                    strncpy( out_control->traj_title, tmp[1], sizeof(out_control->traj_title) - 1 );
-                    out_control->traj_title[sizeof(out_control->traj_title) - 1] = '\0';
-                }
-                else if ( strncmp(tmp[0], "atom_info", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->atom_format += ival * 4;
-                }
-                else if ( strncmp(tmp[0], "atom_velocities", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->atom_format += ival * 2;
-                }
-                else if ( strncmp(tmp[0], "atom_forces", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->atom_format += ival * 1;
-                }
-                else if ( strncmp(tmp[0], "bond_info", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->bond_info = ival;
-                }
-                else if ( strncmp(tmp[0], "angle_info", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    out_control->angle_info = ival;
-                }
-                else if ( strncmp(tmp[0], "test_forces", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                }
-                else if ( strncmp(tmp[0], "molec_anal", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->molec_anal = ival;
-                }
-                else if ( strncmp(tmp[0], "freq_molec_anal", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->freq_molec_anal = ival;
-                }
-                else if ( strncmp(tmp[0], "bond_graph_cutoff", MAX_LINE) == 0 )
-                {
-                    val = atof(tmp[1]);
-                    control->bg_cut = val;
-                }
-                else if ( strncmp(tmp[0], "ignore", MAX_LINE) == 0 )
-                {
-                    control->num_ignored = atoi(tmp[1]);
-                    for ( i = 0; i < control->num_ignored; ++i )
-                        control->ignore[atoi(tmp[i + 2])] = 1;
-                }
-                else if ( strncmp(tmp[0], "dipole_anal", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->dipole_anal = ival;
-                }
-                else if ( strncmp(tmp[0], "freq_dipole_anal", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->freq_dipole_anal = ival;
-                }
-                else if ( strncmp(tmp[0], "diffusion_coef", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->diffusion_coef = ival;
-                }
-                else if ( strncmp(tmp[0], "freq_diffusion_coef", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->freq_diffusion_coef = ival;
-                }
-                else if ( strncmp(tmp[0], "restrict_type", MAX_LINE) == 0 )
-                {
-                    ival = atoi(tmp[1]);
-                    control->restrict_type = ival;
-                }
-                else
+                if ( ret == FAILURE )
                 {
                     fprintf( stderr, "WARNING: unknown parameter %s\n", tmp[0] );
                     exit( UNKNOWN_OPTION );
@@ -651,6 +632,8 @@ void Read_Control_File( FILE* fp, reax_system *system, control_params* control,
              control->ensemble, control->nsteps, control->dt, control->tabulate,
              control->T, control->P[0], control->P[1], control->P[2] );
 
-    fprintf(stderr, "control file read\n" );
+    fprintf( stderr, "control file read\n" );
 #endif
+
+    sfclose( fp, "Read_Control_File::fp" );
 }
diff --git a/sPuReMD/src/control.h b/sPuReMD/src/control.h
index 14fe5493..13ae7da0 100644
--- a/sPuReMD/src/control.h
+++ b/sPuReMD/src/control.h
@@ -24,7 +24,10 @@
 
 #include "reax_types.h"
 
+int Set_Control_Parameter( const char * const, const char ** const,
+        control_params * const, output_controls * const );
 
-void Read_Control_File( FILE*, reax_system*, control_params*, output_controls* );
+void Read_Control_File( const char * const, reax_system * const, control_params * const,
+        output_controls * const );
 
 #endif
diff --git a/sPuReMD/src/ffield.c b/sPuReMD/src/ffield.c
index 84028b33..569b6844 100644
--- a/sPuReMD/src/ffield.c
+++ b/sPuReMD/src/ffield.c
@@ -26,14 +26,17 @@
 #include "tool_box.h"
 
 
-void Read_Force_Field( FILE *fp, reax_system * const system,
-        reax_interaction * const reax )
+void Read_Force_Field( const char * const ffield_file,
+        reax_system * const system, reax_interaction * const reax )
 {
     char *s;
     char **tmp;
     char ****tor_flag;
     int i, j, k, l, m, n, o, p, cnt;
     real val;
+    FILE *fp;
+
+    fp = sfopen( ffield_file, "r" );
 
     assert( fp != NULL );
 
@@ -54,7 +57,7 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
         Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
         /* reading the number of global parameters */
-        n = atoi(tmp[0]);
+        n = sstrtol( tmp[0], __FILE__, __LINE__ );
         if ( n < 1 )
         {
             fprintf( stderr, "[WARNING] number of globals in ffield file is 0!\n" );
@@ -83,7 +86,7 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            val = (real) atof(tmp[0]);
+            val = (real) sstrtod( tmp[0], __FILE__, __LINE__ );
 
             reax->gp.l[i] = val;
         }
@@ -91,7 +94,7 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
         /* next line is number of atom types and some comments */
         fgets( s, MAX_LINE, fp );
         Tokenize( s, &tmp, MAX_TOKEN_LEN );
-        n = atoi(tmp[0]);
+        n = sstrtol( tmp[0], __FILE__, __LINE__ );
 
         /* 3 lines of comments */
         fgets( s, MAX_LINE, fp );
@@ -260,21 +263,21 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
                 reax->sbp[i].name[j] = toupper( reax->sbp[i].name[j] );
             }
 
-            val = atof(tmp[1]);
+            val = sstrtod( tmp[1], __FILE__, __LINE__ );
             reax->sbp[i].r_s = val;
-            val = atof(tmp[2]);
+            val = sstrtod( tmp[2], __FILE__, __LINE__ );
             reax->sbp[i].valency = val;
-            val = atof(tmp[3]);
+            val = sstrtod( tmp[3], __FILE__, __LINE__ );
             reax->sbp[i].mass = val;
-            val = atof(tmp[4]);
+            val = sstrtod( tmp[4], __FILE__, __LINE__ );
             reax->sbp[i].r_vdw = val;
-            val = atof(tmp[5]);
+            val = sstrtod( tmp[5], __FILE__, __LINE__ );
             reax->sbp[i].epsilon = val;
-            val = atof(tmp[6]);
+            val = sstrtod( tmp[6], __FILE__, __LINE__ );
             reax->sbp[i].gamma = val;
-            val = atof(tmp[7]);
+            val = sstrtod( tmp[7], __FILE__, __LINE__ );
             reax->sbp[i].r_pi = val;
-            val = atof(tmp[8]);
+            val = sstrtod( tmp[8], __FILE__, __LINE__ );
             reax->sbp[i].valency_e  = val;
             reax->sbp[i].nlp_opt = 0.5 * (reax->sbp[i].valency_e - reax->sbp[i].valency);
 
@@ -282,23 +285,23 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            val = atof(tmp[0]);
+            val = sstrtod( tmp[0], __FILE__, __LINE__ );
             reax->sbp[i].alpha = val;
-            val = atof(tmp[1]);
+            val = sstrtod( tmp[1], __FILE__, __LINE__ );
             reax->sbp[i].gamma_w = val;
-            val = atof(tmp[2]);
+            val = sstrtod( tmp[2], __FILE__, __LINE__ );
             reax->sbp[i].valency_boc = val;
-            val = atof(tmp[3]);
+            val = sstrtod( tmp[3], __FILE__, __LINE__ );
             reax->sbp[i].p_ovun5 = val;
-            val = atof(tmp[4]);
-            val = atof(tmp[5]);
+            val = sstrtod( tmp[4], __FILE__, __LINE__ );
+            val = sstrtod( tmp[5], __FILE__, __LINE__ );
             reax->sbp[i].chi = val;
-            val = atof(tmp[6]);
+            val = sstrtod( tmp[6], __FILE__, __LINE__ );
             reax->sbp[i].eta = 2.0 * val;
             /* this is the parameter that is used to determine
              * which type of atoms participate in h-bonds.
              * 1 is for H - 2 for O, N, S - 0 for all others.*/
-            val = atof(tmp[7]);
+            val = sstrtod( tmp[7], __FILE__, __LINE__ );
             reax->sbp[i].p_hbond = (int)(val + 0.1);
             //0.1 is to avoid from truncating down!
 
@@ -306,39 +309,39 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            val = atof(tmp[0]);
+            val = sstrtod( tmp[0], __FILE__, __LINE__ );
             reax->sbp[i].r_pi_pi = val;
-            val = atof(tmp[1]);
+            val = sstrtod( tmp[1], __FILE__, __LINE__ );
             reax->sbp[i].p_lp2 = val;
-            val = atof(tmp[2]);
-            val = atof(tmp[3]);
+            val = sstrtod( tmp[2], __FILE__, __LINE__ );
+            val = sstrtod( tmp[3], __FILE__, __LINE__ );
             reax->sbp[i].b_o_131 = val;
-            val = atof(tmp[4]);
+            val = sstrtod( tmp[4], __FILE__, __LINE__ );
             reax->sbp[i].b_o_132 = val;
-            val = atof(tmp[5]);
+            val = sstrtod( tmp[5], __FILE__, __LINE__ );
             reax->sbp[i].b_o_133 = val;
-            val = atof(tmp[6]);
+            val = sstrtod( tmp[6], __FILE__, __LINE__ );
             reax->sbp[i].b_s_acks2 = val;
-            val = atof(tmp[7]);
+            val = sstrtod( tmp[7], __FILE__, __LINE__ );
 
             /* line 4  */
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            val = atof(tmp[0]);
+            val = sstrtod( tmp[0], __FILE__, __LINE__ );
             reax->sbp[i].p_ovun2 = val;
-            val = atof(tmp[1]);
+            val = sstrtod( tmp[1], __FILE__, __LINE__ );
             reax->sbp[i].p_val3 = val;
-            val = atof(tmp[2]);
-            val = atof(tmp[3]);
+            val = sstrtod( tmp[2], __FILE__, __LINE__ );
+            val = sstrtod( tmp[3], __FILE__, __LINE__ );
             reax->sbp[i].valency_val = val;
-            val = atof(tmp[4]);
+            val = sstrtod( tmp[4], __FILE__, __LINE__ );
             reax->sbp[i].p_val5 = val;
-            val = atof(tmp[5]);
+            val = sstrtod( tmp[5], __FILE__, __LINE__ );
             reax->sbp[i].rcore2 = val;
-            val = atof(tmp[6]);
+            val = sstrtod( tmp[6], __FILE__, __LINE__ );
             reax->sbp[i].ecore2 = val;
-            val = atof(tmp[7]);
+            val = sstrtod( tmp[7], __FILE__, __LINE__ );
             reax->sbp[i].acore2 = val;
 
             /* inner-wall parameters present */
@@ -442,7 +445,7 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
         /* next line is number of two body combination and some comments */
         fgets( s, MAX_LINE, fp );
         Tokenize( s, &tmp, MAX_TOKEN_LEN );
-        l = atoi(tmp[0]);
+        l = sstrtol( tmp[0], __FILE__, __LINE__ );
 
         /* a line of comments */
         fgets(s, MAX_LINE, fp);
@@ -453,35 +456,35 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            j = atoi(tmp[0]) - 1;
-            k = atoi(tmp[1]) - 1;
+            j = sstrtol( tmp[0], __FILE__, __LINE__ ) - 1;
+            k = sstrtol( tmp[1], __FILE__, __LINE__ ) - 1;
 
             if ( j < reax->num_atom_types && k < reax->num_atom_types )
             {
 
-                val = atof(tmp[2]);
+                val = sstrtod( tmp[2], __FILE__, __LINE__ );
                 reax->tbp[j][k].De_s = val;
                 reax->tbp[k][j].De_s = val;
-                val = atof(tmp[3]);
+                val = sstrtod( tmp[3], __FILE__, __LINE__ );
                 reax->tbp[j][k].De_p = val;
                 reax->tbp[k][j].De_p = val;
-                val = atof(tmp[4]);
+                val = sstrtod( tmp[4], __FILE__, __LINE__ );
                 reax->tbp[j][k].De_pp = val;
                 reax->tbp[k][j].De_pp = val;
-                val = atof(tmp[5]);
+                val = sstrtod( tmp[5], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_be1 = val;
                 reax->tbp[k][j].p_be1 = val;
-                val = atof(tmp[6]);
+                val = sstrtod( tmp[6], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_bo5 = val;
                 reax->tbp[k][j].p_bo5 = val;
-                val = atof(tmp[7]);
+                val = sstrtod( tmp[7], __FILE__, __LINE__ );
                 reax->tbp[j][k].v13cor = val;
                 reax->tbp[k][j].v13cor = val;
 
-                val = atof(tmp[8]);
+                val = sstrtod( tmp[8], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_bo6 = val;
                 reax->tbp[k][j].p_bo6 = val;
-                val = atof(tmp[9]);
+                val = sstrtod( tmp[9], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_ovun1 = val;
                 reax->tbp[k][j].p_ovun1 = val;
 
@@ -489,28 +492,28 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
                 fgets( s, MAX_LINE, fp );
                 Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-                val = atof(tmp[0]);
+                val = sstrtod( tmp[0], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_be2 = val;
                 reax->tbp[k][j].p_be2 = val;
-                val = atof(tmp[1]);
+                val = sstrtod( tmp[1], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_bo3 = val;
                 reax->tbp[k][j].p_bo3 = val;
-                val = atof(tmp[2]);
+                val = sstrtod( tmp[2], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_bo4 = val;
                 reax->tbp[k][j].p_bo4 = val;
-                val = atof(tmp[3]);
+                val = sstrtod( tmp[3], __FILE__, __LINE__ );
 
-                val = atof(tmp[4]);
+                val = sstrtod( tmp[4], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_bo1 = val;
                 reax->tbp[k][j].p_bo1 = val;
-                val = atof(tmp[5]);
+                val = sstrtod( tmp[5], __FILE__, __LINE__ );
                 reax->tbp[j][k].p_bo2 = val;
                 reax->tbp[k][j].p_bo2 = val;
-                val = atof(tmp[6]);
+                val = sstrtod( tmp[6], __FILE__, __LINE__ );
                 reax->tbp[j][k].ovc = val;
                 reax->tbp[k][j].ovc = val;
 
-                val = atof(tmp[7]);
+                val = sstrtod( tmp[7], __FILE__, __LINE__ );
             }
         }
 
@@ -568,54 +571,54 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
          * combination rules defined above */
         fgets( s, MAX_LINE, fp );
         Tokenize( s, &tmp, MAX_TOKEN_LEN );
-        l = atoi(tmp[0]);
+        l = sstrtol( tmp[0], __FILE__, __LINE__ );
 
         for ( i = 0; i < l; i++ )
         {
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            j = atoi(tmp[0]) - 1;
-            k = atoi(tmp[1]) - 1;
+            j = sstrtol( tmp[0], __FILE__, __LINE__ ) - 1;
+            k = sstrtol( tmp[1], __FILE__, __LINE__ ) - 1;
 
             if ( j < reax->num_atom_types && k < reax->num_atom_types )
             {
-                val = atof(tmp[2]);
+                val = sstrtod( tmp[2], __FILE__, __LINE__ );
                 if ( val > 0.0 )
                 {
                     reax->tbp[j][k].D = val;
                     reax->tbp[k][j].D = val;
                 }
 
-                val = atof(tmp[3]);
+                val = sstrtod( tmp[3], __FILE__, __LINE__ );
                 if ( val > 0.0 )
                 {
                     reax->tbp[j][k].r_vdW = 2.0 * val;
                     reax->tbp[k][j].r_vdW = 2.0 * val;
                 }
 
-                val = atof(tmp[4]);
+                val = sstrtod( tmp[4], __FILE__, __LINE__ );
                 if ( val > 0.0 )
                 {
                     reax->tbp[j][k].alpha = val;
                     reax->tbp[k][j].alpha = val;
                 }
 
-                val = atof(tmp[5]);
+                val = sstrtod( tmp[5], __FILE__, __LINE__ );
                 if ( val > 0.0 )
                 {
                     reax->tbp[j][k].r_s = val;
                     reax->tbp[k][j].r_s = val;
                 }
 
-                val = atof(tmp[6]);
+                val = sstrtod( tmp[6], __FILE__, __LINE__ );
                 if ( val > 0.0 )
                 {
                     reax->tbp[j][k].r_p = val;
                     reax->tbp[k][j].r_p = val;
                 }
 
-                val = atof(tmp[7]);
+                val = sstrtod( tmp[7], __FILE__, __LINE__ );
                 if ( val > 0.0 )
                 {
                     reax->tbp[j][k].r_pp = val;
@@ -641,16 +644,16 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
         /* next line is number of 3-body params and some comments */
         fgets( s, MAX_LINE, fp );
         Tokenize( s, &tmp, MAX_TOKEN_LEN );
-        l = atoi( tmp[0] );
+        l = sstrtol( tmp[0], __FILE__, __LINE__ );
 
         for ( i = 0; i < l; i++ )
         {
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            j = atoi(tmp[0]) - 1;
-            k = atoi(tmp[1]) - 1;
-            m = atoi(tmp[2]) - 1;
+            j = sstrtol( tmp[0], __FILE__, __LINE__ ) - 1;
+            k = sstrtol( tmp[1], __FILE__, __LINE__ ) - 1;
+            m = sstrtol( tmp[2], __FILE__, __LINE__ ) - 1;
 
             if ( j < reax->num_atom_types
                     && k < reax->num_atom_types
@@ -660,31 +663,31 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
                 reax->thbp[j][k][m].cnt++;
                 reax->thbp[m][k][j].cnt++;
 
-                val = atof(tmp[3]);
+                val = sstrtod( tmp[3], __FILE__, __LINE__ );
                 reax->thbp[j][k][m].prm[cnt].theta_00 = val;
                 reax->thbp[m][k][j].prm[cnt].theta_00 = val;
 
-                val = atof(tmp[4]);
+                val = sstrtod( tmp[4], __FILE__, __LINE__ );
                 reax->thbp[j][k][m].prm[cnt].p_val1 = val;
                 reax->thbp[m][k][j].prm[cnt].p_val1 = val;
 
-                val = atof(tmp[5]);
+                val = sstrtod( tmp[5], __FILE__, __LINE__ );
                 reax->thbp[j][k][m].prm[cnt].p_val2 = val;
                 reax->thbp[m][k][j].prm[cnt].p_val2 = val;
 
-                val = atof(tmp[6]);
+                val = sstrtod( tmp[6], __FILE__, __LINE__ );
                 reax->thbp[j][k][m].prm[cnt].p_coa1 = val;
                 reax->thbp[m][k][j].prm[cnt].p_coa1 = val;
 
-                val = atof(tmp[7]);
+                val = sstrtod( tmp[7], __FILE__, __LINE__ );
                 reax->thbp[j][k][m].prm[cnt].p_val7 = val;
                 reax->thbp[m][k][j].prm[cnt].p_val7 = val;
 
-                val = atof(tmp[8]);
+                val = sstrtod( tmp[8], __FILE__, __LINE__ );
                 reax->thbp[j][k][m].prm[cnt].p_pen1 = val;
                 reax->thbp[m][k][j].prm[cnt].p_pen1 = val;
 
-                val = atof(tmp[9]);
+                val = sstrtod( tmp[9], __FILE__, __LINE__ );
                 reax->thbp[j][k][m].prm[cnt].p_val4 = val;
                 reax->thbp[m][k][j].prm[cnt].p_val4 = val;
             }
@@ -717,17 +720,17 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
         /* next line is number of 4-body params and some comments */
         fgets( s, MAX_LINE, fp );
         Tokenize( s, &tmp, MAX_TOKEN_LEN );
-        l = atoi( tmp[0] );
+        l = sstrtol( tmp[0], __FILE__, __LINE__ );
 
         for ( i = 0; i < l; i++ )
         {
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            j = atoi(tmp[0]) - 1;
-            k = atoi(tmp[1]) - 1;
-            m = atoi(tmp[2]) - 1;
-            n = atoi(tmp[3]) - 1;
+            j = sstrtol( tmp[0], __FILE__, __LINE__ ) - 1;
+            k = sstrtol( tmp[1], __FILE__, __LINE__ ) - 1;
+            m = sstrtol( tmp[2], __FILE__, __LINE__ ) - 1;
+            n = sstrtol( tmp[3], __FILE__, __LINE__ ) - 1;
 
             /* this means the entry is not in compact form */
             if ( j >= 0 && n >= 0 )
@@ -749,23 +752,23 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
     //                reax->fbp[j][k][m][n].cnt++;
     //                reax->fbp[n][m][k][j].cnt++;
 
-                    val = atof(tmp[4]);
+                    val = sstrtod( tmp[4], __FILE__, __LINE__ );
                     reax->fbp[j][k][m][n].prm[0].V1 = val;
                     reax->fbp[n][m][k][j].prm[0].V1 = val;
 
-                    val = atof(tmp[5]);
+                    val = sstrtod( tmp[5], __FILE__, __LINE__ );
                     reax->fbp[j][k][m][n].prm[0].V2 = val;
                     reax->fbp[n][m][k][j].prm[0].V2 = val;
 
-                    val = atof(tmp[6]);
+                    val = sstrtod( tmp[6], __FILE__, __LINE__ );
                     reax->fbp[j][k][m][n].prm[0].V3 = val;
                     reax->fbp[n][m][k][j].prm[0].V3 = val;
 
-                    val = atof(tmp[7]);
+                    val = sstrtod( tmp[7], __FILE__, __LINE__ );
                     reax->fbp[j][k][m][n].prm[0].p_tor1 = val;
                     reax->fbp[n][m][k][j].prm[0].p_tor1 = val;
 
-                    val = atof(tmp[8]);
+                    val = sstrtod( tmp[8], __FILE__, __LINE__ );
                     reax->fbp[j][k][m][n].prm[0].p_cot1 = val;
                     reax->fbp[n][m][k][j].prm[0].p_cot1 = val;
                 }
@@ -788,20 +791,20 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
 
                             if ( tor_flag[p][k][m][o] == 0 )
                             {
-                                reax->fbp[p][k][m][o].prm[0].V1 = atof(tmp[4]);
-                                reax->fbp[p][k][m][o].prm[0].V2 = atof(tmp[5]);
-                                reax->fbp[p][k][m][o].prm[0].V3 = atof(tmp[6]);
-                                reax->fbp[p][k][m][o].prm[0].p_tor1 = atof(tmp[7]);
-                                reax->fbp[p][k][m][o].prm[0].p_cot1 = atof(tmp[8]);
+                                reax->fbp[p][k][m][o].prm[0].V1 = sstrtod( tmp[4], __FILE__, __LINE__ );
+                                reax->fbp[p][k][m][o].prm[0].V2 = sstrtod( tmp[5], __FILE__, __LINE__ );
+                                reax->fbp[p][k][m][o].prm[0].V3 = sstrtod( tmp[6], __FILE__, __LINE__ );
+                                reax->fbp[p][k][m][o].prm[0].p_tor1 = sstrtod( tmp[7], __FILE__, __LINE__ );
+                                reax->fbp[p][k][m][o].prm[0].p_cot1 = sstrtod( tmp[8], __FILE__, __LINE__ );
                             }
 
                             if ( tor_flag[o][m][k][p] == 0 )
                             {
-                                reax->fbp[o][m][k][p].prm[0].V1 = atof(tmp[4]);
-                                reax->fbp[o][m][k][p].prm[0].V2 = atof(tmp[5]);
-                                reax->fbp[o][m][k][p].prm[0].V3 = atof(tmp[6]);
-                                reax->fbp[o][m][k][p].prm[0].p_tor1 = atof(tmp[7]);
-                                reax->fbp[o][m][k][p].prm[0].p_cot1 = atof(tmp[8]);
+                                reax->fbp[o][m][k][p].prm[0].V1 = sstrtod( tmp[4], __FILE__, __LINE__ );
+                                reax->fbp[o][m][k][p].prm[0].V2 = sstrtod( tmp[5], __FILE__, __LINE__ );
+                                reax->fbp[o][m][k][p].prm[0].V3 = sstrtod( tmp[6], __FILE__, __LINE__ );
+                                reax->fbp[o][m][k][p].prm[0].p_tor1 = sstrtod( tmp[7], __FILE__, __LINE__ );
+                                reax->fbp[o][m][k][p].prm[0].p_cot1 = sstrtod( tmp[8], __FILE__, __LINE__ );
                             }
                         }
                     }
@@ -812,29 +815,29 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
         /* next line is number of hydrogen bond params and some comments */
         fgets( s, MAX_LINE, fp );
         Tokenize( s, &tmp, MAX_TOKEN_LEN );
-        l = atoi( tmp[0] );
+        l = sstrtol( tmp[0], __FILE__, __LINE__ );
 
         for ( i = 0; i < l; i++ )
         {
             fgets( s, MAX_LINE, fp );
             Tokenize( s, &tmp, MAX_TOKEN_LEN );
 
-            j = atoi(tmp[0]) - 1;
-            k = atoi(tmp[1]) - 1;
-            m = atoi(tmp[2]) - 1;
+            j = sstrtol( tmp[0], __FILE__, __LINE__ ) - 1;
+            k = sstrtol( tmp[1], __FILE__, __LINE__ ) - 1;
+            m = sstrtol( tmp[2], __FILE__, __LINE__ ) - 1;
 
             if ( j < reax->num_atom_types && m < reax->num_atom_types )
             {
-                val = atof(tmp[3]);
+                val = sstrtod( tmp[3], __FILE__, __LINE__ );
                 reax->hbp[j][k][m].r0_hb = val;
 
-                val = atof(tmp[4]);
+                val = sstrtod( tmp[4], __FILE__, __LINE__ );
                 reax->hbp[j][k][m].p_hb1 = val;
 
-                val = atof(tmp[5]);
+                val = sstrtod( tmp[5], __FILE__, __LINE__ );
                 reax->hbp[j][k][m].p_hb2 = val;
 
-                val = atof(tmp[6]);
+                val = sstrtod( tmp[6], __FILE__, __LINE__ );
                 reax->hbp[j][k][m].p_hb3 = val;
 
             }
@@ -866,4 +869,6 @@ void Read_Force_Field( FILE *fp, reax_system * const system,
 
         sfree( tor_flag, "Read_Force_Field::tor_flag" );
     }
+
+    sfclose( fp, "Read_Force_Field::fp" );
 }
diff --git a/sPuReMD/src/ffield.h b/sPuReMD/src/ffield.h
index 692e772c..88bb91a9 100644
--- a/sPuReMD/src/ffield.h
+++ b/sPuReMD/src/ffield.h
@@ -25,7 +25,8 @@
 #include "reax_types.h"
 
 
-void Read_Force_Field( FILE *, reax_system * const, reax_interaction * const );
+void Read_Force_Field( const char * const, reax_system * const,
+        reax_interaction * const );
 
 
 #endif
diff --git a/sPuReMD/src/forces.c b/sPuReMD/src/forces.c
index cf3efeca..3b6afe5b 100644
--- a/sPuReMD/src/forces.c
+++ b/sPuReMD/src/forces.c
@@ -168,7 +168,7 @@ static void Compute_NonBonded_Forces( reax_system *system, control_params *contr
                 + data->timing.cm_solver_vector_ops
                 + data->timing.cm_solver_orthog
                 + data->timing.cm_solver_tri_solve;
-            data->timing.cm_total_loss = ZERO;
+            data->timing.cm_total_loss = 0.0;
         }
         else
         {
diff --git a/sPuReMD/src/geo_tools.c b/sPuReMD/src/geo_tools.c
index 068f1408..88f8799c 100644
--- a/sPuReMD/src/geo_tools.c
+++ b/sPuReMD/src/geo_tools.c
@@ -351,12 +351,9 @@ void Read_PDB( const char * const pdb_file, reax_system* system, control_params
     char occupancy[7], temp_factor[7];
     char seg_id[5], element[3], charge[3];
     char alt_loc, chain_id, icode;
-    char *endptr;
     rvec x;
     reax_atom *atom;
 
-    endptr = NULL;
-
     pdb = sfopen( pdb_file, "r" );
 
     Allocate_Tokenizer_Space( &s, MAX_LINE, &s1, MAX_LINE,
@@ -459,8 +456,9 @@ void Read_PDB( const char * const pdb_file, reax_system* system, control_params
             }
 
             /* if the point is inside my_box, add it to my lists */
-            Make_Point( strtod( s_x, &endptr ), strtod( s_y, &endptr ),
-                    strtod( s_z, &endptr ), &x );
+            Make_Point( sstrtod( s_x, __FILE__, __LINE__ ),
+                    sstrtod( s_y, __FILE__, __LINE__ ),
+                    sstrtod( s_z, __FILE__, __LINE__ ), &x );
 
             Fit_to_Periodic_Box( &system->box, x );
 
@@ -468,7 +466,7 @@ void Read_PDB( const char * const pdb_file, reax_system* system, control_params
             {
                 /* store orig_id, type, name and coord info of the new atom */
                 atom = &system->atoms[top];
-                pdb_serial = (int) strtod( serial, &endptr );
+                pdb_serial = (int) sstrtod( serial, __FILE__, __LINE__ );
                 workspace->orig_id[top] = pdb_serial;
 
                 Trim_Spaces( element, sizeof(element) );
@@ -508,13 +506,13 @@ void Read_PDB( const char * const pdb_file, reax_system* system, control_params
 //                        "CONECT line exceeds max num restrictions allowed.\n" );
 
                 /* read bond restrictions */
-                // if( is_Valid_Serial( workspace, pdb_serial = atoi(tmp[1]) ) )
+                // if( is_Valid_Serial( workspace, pdb_serial = sstrtol( tmp[1]), __FILE__, __LINE__ ) )
                 //   ratom = workspace->map_serials[ pdb_serial ];
 
                 // workspace->restricted[ ratom ] = c1 - 2;
                 // for( i = 2; i < c1; ++i )
                 //  {
-                //    if( is_Valid_Serial(workspace, pdb_serial = atoi(tmp[i])) )
+                //    if( is_Valid_Serial(workspace, pdb_serial = sstrtol( tmp[i], __FILE__, __LINE__ )) )
                 //        workspace->restricted_list[ ratom ][ i-2 ] =
                 //          workspace->map_serials[ pdb_serial ];
                 //  }
@@ -625,10 +623,8 @@ void Read_BGF( const char * const bgf_file, reax_system* system, control_params
     char element[6], charge[9];
     char chain_id;
     char s_a[12], s_b[12], s_c[12], s_alpha[12], s_beta[12], s_gamma[12];
-    char *endptr;
     int i, n, atom_cnt, token_cnt, bgf_serial, ratom, crystx_found;
 
-    endptr = NULL;
     ratom = 0;
     crystx_found = FALSE;
 
@@ -727,15 +723,15 @@ void Read_BGF( const char * const bgf_file, reax_system* system, control_params
 //                    occupancy, temp_factor, charge );
 
             /* add to mapping */
-            bgf_serial = strtod( serial, &endptr );
+            bgf_serial = sstrtod( serial, __FILE__, __LINE__ );
             Check_Input_Range( bgf_serial, 0, MAX_ATOM_ID, "Invalid bgf serial" );
             workspace->map_serials[ bgf_serial ] = atom_cnt;
             workspace->orig_id[ atom_cnt ] = bgf_serial;
 
             /* copy atomic positions */
-            system->atoms[atom_cnt].x[0] = strtod( s_x, &endptr );
-            system->atoms[atom_cnt].x[1] = strtod( s_y, &endptr );
-            system->atoms[atom_cnt].x[2] = strtod( s_z, &endptr );
+            system->atoms[atom_cnt].x[0] = sstrtod( s_x, __FILE__, __LINE__ );
+            system->atoms[atom_cnt].x[1] = sstrtod( s_y, __FILE__, __LINE__ );
+            system->atoms[atom_cnt].x[2] = sstrtod( s_z, __FILE__, __LINE__ );
 
             /* atom name and type */
             strncpy( system->atoms[atom_cnt].name, atom_name,
@@ -763,8 +759,12 @@ void Read_BGF( const char * const bgf_file, reax_system* system, control_params
                     s_a, s_b, s_c, s_alpha, s_beta, s_gamma );
 
             /* compute full volume tensor from the angles */
-            Setup_Box( atof(s_a), atof(s_b), atof(s_c),
-                    atof(s_alpha), atof(s_beta), atof(s_gamma),
+            Setup_Box( sstrtod( s_a, __FILE__, __LINE__ ),
+                    sstrtod( s_b, __FILE__, __LINE__ ),
+                    sstrtod( s_c, __FILE__, __LINE__ ),
+                    sstrtod( s_alpha, __FILE__, __LINE__ ),
+                    sstrtod( s_beta, __FILE__, __LINE__ ),
+                    sstrtod( s_gamma, __FILE__, __LINE__ ),
                     &system->box );
 
             crystx_found = TRUE;
@@ -778,7 +778,7 @@ void Read_BGF( const char * const bgf_file, reax_system* system, control_params
                         "CONECT line exceeds max restrictions allowed.\n" );
 
                 /* read bond restrictions */
-                bgf_serial = atoi(tokens[1]);
+                bgf_serial = sstrtol( tokens[1], __FILE__, __LINE__ );
                 if ( is_Valid_Serial( workspace, bgf_serial ) )
                 {
                     ratom = workspace->map_serials[ bgf_serial ];
@@ -787,7 +787,7 @@ void Read_BGF( const char * const bgf_file, reax_system* system, control_params
                 workspace->restricted[ ratom ] = token_cnt - 2;
                 for ( i = 2; i < token_cnt; ++i )
                 {
-                    if ( is_Valid_Serial( workspace, bgf_serial = atoi(tokens[i]) ) )
+                    if ( is_Valid_Serial( workspace, bgf_serial = sstrtol( tokens[i], __FILE__, __LINE__ )) )
                     {
                         workspace->restricted_list[ratom][i - 2] =
                             workspace->map_serials[bgf_serial];
diff --git a/sPuReMD/src/init_md.c b/sPuReMD/src/init_md.c
index caf475ee..0b13e1bc 100644
--- a/sPuReMD/src/init_md.c
+++ b/sPuReMD/src/init_md.c
@@ -259,22 +259,22 @@ static void Init_Simulation_Data( reax_system *system, control_params *control,
     /* init timing info */
     data->timing.start = Get_Time( );
     data->timing.total = data->timing.start;
-    data->timing.nbrs = 0;
-    data->timing.init_forces = 0;
-    data->timing.bonded = 0;
-    data->timing.nonb = 0;
-    data->timing.cm = ZERO;
-    data->timing.cm_sort_mat_rows = ZERO;
-    data->timing.cm_solver_pre_comp = ZERO;
-    data->timing.cm_solver_pre_app = ZERO;
+    data->timing.nbrs = 0.0;
+    data->timing.init_forces = 0.0;
+    data->timing.bonded = 0.0;
+    data->timing.nonb = 0.0;
+    data->timing.cm = 0.0;
+    data->timing.cm_sort_mat_rows = 0.0;
+    data->timing.cm_solver_pre_comp = 0.0;
+    data->timing.cm_solver_pre_app = 0.0;
     data->timing.cm_solver_iters = 0;
-    data->timing.cm_solver_spmv = ZERO;
-    data->timing.cm_solver_vector_ops = ZERO;
-    data->timing.cm_solver_orthog = ZERO;
-    data->timing.cm_solver_tri_solve = ZERO;
-    data->timing.cm_last_pre_comp = ZERO;
-    data->timing.cm_total_loss = ZERO;
-    data->timing.cm_optimum = ZERO;
+    data->timing.cm_solver_spmv = 0.0;
+    data->timing.cm_solver_vector_ops = 0.0;
+    data->timing.cm_solver_orthog = 0.0;
+    data->timing.cm_solver_tri_solve = 0.0;
+    data->timing.cm_last_pre_comp = 0.0;
+    data->timing.cm_total_loss = 0.0;
+    data->timing.cm_optimum = 0.0;
 }
 
 
diff --git a/sPuReMD/src/io_tools.c b/sPuReMD/src/io_tools.c
index ad19a383..819d7678 100644
--- a/sPuReMD/src/io_tools.c
+++ b/sPuReMD/src/io_tools.c
@@ -642,7 +642,7 @@ void Output_Results( reax_system *system, control_params *control,
                  data->timing.nonb * f_update,
                  data->timing.cm * f_update,
                  data->timing.cm_sort_mat_rows * f_update,
-                 (double)data->timing.cm_solver_iters * f_update,
+                 (double) data->timing.cm_solver_iters * f_update,
                  data->timing.cm_solver_pre_comp * f_update,
                  data->timing.cm_solver_pre_app * f_update,
                  data->timing.cm_solver_spmv * f_update,
@@ -651,19 +651,19 @@ void Output_Results( reax_system *system, control_params *control,
                  data->timing.cm_solver_tri_solve * f_update );
 
         data->timing.total = Get_Time( );
-        data->timing.nbrs = 0;
-        data->timing.init_forces = 0;
-        data->timing.bonded = 0;
-        data->timing.nonb = 0;
-        data->timing.cm = ZERO;
-        data->timing.cm_sort_mat_rows = ZERO;
-        data->timing.cm_solver_pre_comp = ZERO;
-        data->timing.cm_solver_pre_app = ZERO;
+        data->timing.nbrs = 0.0;
+        data->timing.init_forces = 0.0;
+        data->timing.bonded = 0.0;
+        data->timing.nonb = 0.0;
+        data->timing.cm = 0.0;
+        data->timing.cm_sort_mat_rows = 0.0;
+        data->timing.cm_solver_pre_comp = 0.0;
+        data->timing.cm_solver_pre_app = 0.0;
         data->timing.cm_solver_iters = 0;
-        data->timing.cm_solver_spmv = ZERO;
-        data->timing.cm_solver_vector_ops = ZERO;
-        data->timing.cm_solver_orthog = ZERO;
-        data->timing.cm_solver_tri_solve = ZERO;
+        data->timing.cm_solver_spmv = 0.0;
+        data->timing.cm_solver_vector_ops = 0.0;
+        data->timing.cm_solver_orthog = 0.0;
+        data->timing.cm_solver_tri_solve = 0.0;
 
         fflush( out_control->out );
         fflush( out_control->pot );
diff --git a/sPuReMD/src/lin_alg.c b/sPuReMD/src/lin_alg.c
index 7fe4ec4b..53f736e3 100644
--- a/sPuReMD/src/lin_alg.c
+++ b/sPuReMD/src/lin_alg.c
@@ -1153,7 +1153,7 @@ real FG_ICHOLT( const sparse_matrix * const A, const real * droptol,
 #endif
     for ( i = 0; i < A->n; ++i )
     {
-        if ( A->val[A->start[i + 1] - 1] < ZERO )
+        if ( A->val[A->start[i + 1] - 1] < 0.0 )
         {
             gamma[i] = -1.0;
         }
@@ -1224,7 +1224,7 @@ real FG_ICHOLT( const sparse_matrix * const A, const real * droptol,
             y = U_T_temp.start[U_T_temp.j[pj]];
             ei_y = U_T_temp.start[U_T_temp.j[pj] + 1];
 
-            sum = ZERO;
+            sum = 0.0;
 
             /* sparse vector-sparse vector inner product for nonzero (i, j):
              *   dot( U^T(i,1:j-1), U^T(j,1:j-1) ) */
@@ -1252,7 +1252,7 @@ real FG_ICHOLT( const sparse_matrix * const A, const real * droptol,
             {
 #if defined(DEBUG_FOCUS)
                 /* sanity check */
-                if ( sum < ZERO )
+                if ( sum < 0.0 )
                 {
                     fprintf( stderr, "[ERROR] Numeric breakdown in FG_ICHOLT. Terminating.\n");
                     fprintf( stderr, "  [INFO] DAD(%5d,%5d) = %10.3f\n",
@@ -1362,7 +1362,7 @@ real FG_ILUT( const sparse_matrix * const A, const real * droptol,
 #endif
     for ( i = 0; i < A->n; ++i )
     {
-        if ( A->val[A->start[i + 1] - 1] < ZERO )
+        if ( A->val[A->start[i + 1] - 1] < 0.0 )
         {
             gamma[i] = -1.0;
         }
@@ -1452,7 +1452,7 @@ real FG_ILUT( const sparse_matrix * const A, const real * droptol,
                 y = L_temp.start[L_temp.j[pj]];
                 ei_y = L_temp.start[L_temp.j[pj] + 1];
 
-                sum = ZERO;
+                sum = 0.0;
 
                 /* sparse vector-sparse vector inner products for nonzero (i, j):
                  *   dot( L(i,1:j-1), U^T(j,1:j-1) )
@@ -1505,7 +1505,7 @@ real FG_ILUT( const sparse_matrix * const A, const real * droptol,
             y = L_temp.start[L_temp.j[pj]];
             ei_y = L_temp.start[L_temp.j[pj] + 1];
 
-            sum = ZERO;
+            sum = 0.0;
 
             /* sparse vector-sparse vector inner products for nonzero (i, j):
              *   dot( L(j,1:j-1), U^T(i,1:j-1) )
diff --git a/sPuReMD/src/reax_types.h b/sPuReMD/src/reax_types.h
index fa5401d1..097c99c9 100644
--- a/sPuReMD/src/reax_types.h
+++ b/sPuReMD/src/reax_types.h
@@ -195,7 +195,6 @@
 /* min. temperature scaler for atomic positions and velocities in NPT ensembles */
 #define MIN_dT (0.0)
 
-#define ZERO (0.000000000000000e+00)
 #define ALMOST_ZERO (1.0e-10)
 #define NEG_INF (-1.0e10)
 #define NO_BOND (1.0e-3)
@@ -1073,7 +1072,7 @@ struct control_params
 
 struct thermostat
 {
-    /* temperature scaler of the system at the current simulation step */
+    /* temperature scalar of the system at the current simulation step */
     real T;
     /* temperature tensor of the system at the current simulation step */
     rtensor Temp;
diff --git a/sPuReMD/src/spuremd.c b/sPuReMD/src/spuremd.c
index 41fa92f7..694dfc78 100644
--- a/sPuReMD/src/spuremd.c
+++ b/sPuReMD/src/spuremd.c
@@ -21,10 +21,9 @@
 
 #include "spuremd.h"
 
+#include "allocate.h"
 #include "analyze.h"
-#if defined(DEBUG_FOCUS)
-  #include "box.h"
-#endif
+#include "box.h"
 #include "control.h"
 #include "ffield.h"
 #include "forces.h"
@@ -101,49 +100,196 @@ static void Read_Input_Files( const char * const geo_file,
         simulation_data * const data, static_storage * const workspace,
         output_controls * const out_control )
 {
-    FILE *ffield, *ctrl;
-
-    ffield = sfopen( ffield_file, "r" );
-    ctrl = sfopen( control_file, "r" );
-
-    Read_Force_Field( ffield, system, &system->reax_param );
-
-    Read_Control_File( ctrl, system, control, out_control );
-
-    if ( control->geo_format == CUSTOM )
+    if ( ffield_file != NULL )
     {
-        Read_Geo( geo_file, system, control, data, workspace );
+        Read_Force_Field( ffield_file, system, &system->reax_param );
     }
-    else if ( control->geo_format == PDB )
+
+    if ( control_file != NULL )
     {
-        Read_PDB( geo_file, system, control, data, workspace );
+        Read_Control_File( control_file, system, control, out_control );
     }
-    else if ( control->geo_format == BGF )
+
+    if ( geo_file != NULL )
     {
-        Read_BGF( geo_file, system, control, data, workspace );
+        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 );
+        }
     }
-    else if ( control->geo_format == ASCII_RESTART )
+
+#if defined(DEBUG_FOCUS)
+    Print_Box( &system->box, stderr );
+#endif
+}
+
+
+/* Allocate top-level data structures and parse input files
+ * for the first simulation
+ *
+ * qm_num_atoms: num. atoms in the QM region
+ * qm_types: element types for QM atoms
+ * qm_pos_x: x-coordinate of QM atom positions, in Angstroms
+ * qm_pos_y: y-coordinate of QM atom positions, in Angstroms
+ * qm_pos_z: z-coordinate of QM atom positions, in Angstroms
+ * mm_num_atoms: num. atoms in the MM region
+ * mm_types: element types for MM atoms
+ * mm_pos_x: x-coordinate of MM atom positions, in Angstroms
+ * mm_pos_y: y-coordinate of MM atom positions, in Angstroms
+ * mm_pos_z: z-coordinate of MM atom positions, in Angstroms
+ * mm_q: charge of MM atom, in Coulombs
+ * sim_box: simulation box information, where the entries are
+ *  - box length per dimension (3 entries)
+ *  - angles per dimension (3 entries)
+ * ffield_file: file containing force field parameters
+ * control_file: file containing simulation parameters
+ */
+void * setup_qmmm_( int qm_num_atoms, const int * const qm_types,
+        const double * const qm_pos_x, const double * const qm_pos_y,
+        const double * const qm_pos_z,
+        int mm_num_atoms, const int * const mm_types,
+        const double * const mm_pos_x, const double * const mm_pos_y,
+        const double * const mm_pos_z, const double * const mm_q,
+        const double * const sim_box,
+        const char * const ffield_file,
+        const char * const control_file )
+{
+    int i;
+//    char atom_name[9];
+    rvec x;
+    spuremd_handle *spmd_handle;
+
+    /* top-level allocation */
+    spmd_handle = (spuremd_handle*) smalloc( sizeof(spuremd_handle),
+            "setup::spmd_handle" );
+
+    /* second-level allocations */
+    spmd_handle->system = smalloc( sizeof(reax_system),
+           "Setup::spmd_handle->system" );
+    spmd_handle->system->prealloc_allocated = FALSE;
+    spmd_handle->system->ffield_params_allocated = FALSE;
+    spmd_handle->system->g.allocated = FALSE;
+
+    spmd_handle->control = smalloc( sizeof(control_params),
+           "Setup::spmd_handle->control" );
+
+    spmd_handle->data = smalloc( sizeof(simulation_data),
+           "Setup::spmd_handle->data" );
+
+    spmd_handle->workspace = smalloc( sizeof(static_storage),
+           "Setup::spmd_handle->workspace" );
+    spmd_handle->workspace->H.allocated = FALSE;
+    spmd_handle->workspace->H_full.allocated = FALSE;
+    spmd_handle->workspace->H_sp.allocated = FALSE;
+    spmd_handle->workspace->H_p.allocated = FALSE;
+    spmd_handle->workspace->H_spar_patt.allocated = FALSE;
+    spmd_handle->workspace->H_spar_patt_full.allocated = FALSE;
+    spmd_handle->workspace->H_app_inv.allocated = FALSE;
+    spmd_handle->workspace->L.allocated = FALSE;
+    spmd_handle->workspace->U.allocated = FALSE;
+
+    spmd_handle->lists = smalloc( sizeof(reax_list *) * LIST_N,
+           "Setup::spmd_handle->lists" );
+    for ( i = 0; i < LIST_N; ++i )
     {
-        Read_ASCII_Restart( geo_file, system, control, data, workspace );
-        control->restart = TRUE;
+        spmd_handle->lists[i] = smalloc( sizeof(reax_list),
+                "Setup::spmd_handle->lists[i]" );
+        spmd_handle->lists[i]->allocated = FALSE;
     }
-    else if ( control->geo_format == BINARY_RESTART )
+    spmd_handle->out_control = smalloc( sizeof(output_controls),
+           "Setup::spmd_handle->out_control" );
+
+    spmd_handle->output_enabled = FALSE;
+    spmd_handle->realloc = TRUE;
+    spmd_handle->callback = NULL;
+    spmd_handle->data->sim_id = 0;
+
+    spmd_handle->system->N = qm_num_atoms + mm_num_atoms;
+
+    PreAllocate_Space( spmd_handle->system, spmd_handle->control,
+            spmd_handle->workspace, spmd_handle->system->N );
+
+    Setup_Box( sim_box[0], sim_box[1], sim_box[2],
+            sim_box[3], sim_box[4], sim_box[5],
+            &spmd_handle->system->box );
+
+    for ( i = 0; i < qm_num_atoms; ++i )
     {
-        Read_Binary_Restart( geo_file, system, control, data, workspace );
-        control->restart = TRUE;
+        x[0] = qm_pos_x[i];
+        x[1] = qm_pos_y[i];
+        x[2] = qm_pos_z[i];
+
+        Fit_to_Periodic_Box( &spmd_handle->system->box, x );
+
+        spmd_handle->workspace->orig_id[i] = i + 1;
+//        spmd_handle->system->atoms[i].type = Get_Atom_Type( &system->reax_param,
+//                element, sizeof(element) );
+        spmd_handle->system->atoms[i].type = qm_types[i];
+//        strncpy( spmd_handle->system->atoms[i].name, atom_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;
+
+//        mask[i] = 1;
     }
-    else
+
+    for ( i = qm_num_atoms; i < qm_num_atoms + mm_num_atoms; ++i )
     {
-        fprintf( stderr, "[ERROR] unknown geo file format. terminating!\n" );
-        exit( INVALID_GEO );
+        x[0] = mm_pos_x[i - qm_num_atoms];
+        x[1] = mm_pos_y[i - qm_num_atoms];
+        x[2] = mm_pos_z[i - qm_num_atoms];
+
+        Fit_to_Periodic_Box( &spmd_handle->system->box, x );
+
+        spmd_handle->workspace->orig_id[i] = i + 1;
+//        spmd_handle->system->atoms[i].type = Get_Atom_Type( &system->reax_param,
+//                element, sizeof(element) );
+        spmd_handle->system->atoms[i].type = mm_types[i - qm_num_atoms];
+//        strncpy( spmd_handle->system->atoms[i].name, atom_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 = mm_q[i - qm_num_atoms];
+
+//        mask[i] = 0;
     }
 
-    sfclose( ffield, "Read_Input_Files::ffield" );
-    sfclose( ctrl, "Read_Input_Files::ctrl" );
+    Read_Input_Files( NULL, ffield_file, control_file,
+            spmd_handle->system, spmd_handle->control,
+            spmd_handle->data, spmd_handle->workspace,
+            spmd_handle->out_control );
 
-#if defined(DEBUG_FOCUS)
-    Print_Box( &system->box, stderr );
-#endif
+    spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N );
+
+    return (void *) spmd_handle;
 }
 
 
@@ -154,7 +300,7 @@ static void Read_Input_Files( const char * const geo_file,
  * 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,
+void * setup( const char * const geo_file, const char * const ffield_file,
         const char * const control_file )
 {
     int i;
@@ -212,7 +358,7 @@ void* setup( const char * const geo_file, const char * const ffield_file,
 
     spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N );
 
-    return (void*) spmd_handle;
+    return (void *) spmd_handle;
 }
 
 
@@ -220,6 +366,8 @@ void* setup( const char * const geo_file, const char * const ffield_file,
  *
  * 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  )
 {
@@ -243,6 +391,8 @@ int setup_callback( const void * const handle, const callback_function callback
 /* 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 )
 {
@@ -391,6 +541,8 @@ int simulate( const void * const handle )
 /* 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 )
 {
@@ -427,6 +579,139 @@ int cleanup( const void * const 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_types: element types for QM atoms
+ * qm_pos_x: x-coordinate of QM atom positions, in Angstroms
+ * qm_pos_y: y-coordinate of QM atom positions, in Angstroms
+ * qm_pos_z: z-coordinate of QM atom positions, in Angstroms
+ * mm_num_atoms: num. atoms in the MM region
+ * mm_types: element types for MM atoms
+ * mm_pos_x: x-coordinate of MM atom positions, in Angstroms
+ * mm_pos_y: y-coordinate of MM atom positions, in Angstroms
+ * mm_pos_z: z-coordinate of MM atom positions, in Angstroms
+ * mm_q: charge of MM atom, in Coulombs
+ * sim_box: simulation box information, where the entries are
+ *  - box length per dimension (3 entries)
+ *  - angles per dimension (3 entries)
+ * 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 int * const qm_types,
+        const double * const qm_pos_x, const double * const qm_pos_y,
+        const double * const qm_pos_z,
+        int mm_num_atoms, const int * const mm_types,
+        const double * const mm_pos_x, const double * const mm_pos_y,
+        const double * const mm_pos_z, const double * const mm_q,
+        const double * const sim_box,
+        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++;
+
+        spmd_handle->system->N = qm_num_atoms + mm_num_atoms;
+
+        PreAllocate_Space( spmd_handle->system, spmd_handle->control,
+                spmd_handle->workspace, spmd_handle->system->N );
+
+        Setup_Box( sim_box[0], sim_box[1], sim_box[2],
+                sim_box[3], sim_box[4], sim_box[5],
+                &spmd_handle->system->box );
+
+        for ( i = 0; i < qm_num_atoms; ++i )
+        {
+            x[0] = qm_pos_x[i];
+            x[1] = qm_pos_y[i];
+            x[2] = qm_pos_z[i];
+
+            Fit_to_Periodic_Box( &spmd_handle->system->box, x );
+
+            spmd_handle->workspace->orig_id[i] = i + 1;
+//            spmd_handle->system->atoms[i].type = Get_Atom_Type( &system->reax_param,
+//                    element, sizeof(element) );
+            spmd_handle->system->atoms[i].type = qm_types[i];
+//            strncpy( spmd_handle->system->atoms[i].name, atom_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;
+
+//            mask[i] = 1;
+        }
+
+        for ( i = qm_num_atoms; i < qm_num_atoms + mm_num_atoms; ++i )
+        {
+            x[0] = mm_pos_x[i - qm_num_atoms];
+            x[1] = mm_pos_y[i - qm_num_atoms];
+            x[2] = mm_pos_z[i - qm_num_atoms];
+
+            Fit_to_Periodic_Box( &spmd_handle->system->box, x );
+
+            spmd_handle->workspace->orig_id[i] = i + 1;
+//            spmd_handle->system->atoms[i].type = Get_Atom_Type( &system->reax_param,
+//                    element, sizeof(element) );
+            spmd_handle->system->atoms[i].type = mm_types[i - qm_num_atoms];
+//            strncpy( spmd_handle->system->atoms[i].name, atom_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 = mm_q[i - qm_num_atoms];
+
+//            mask[i] = 0;
+        }
+
+        Read_Input_Files( NULL, ffield_file, control_file,
+                spmd_handle->system, spmd_handle->control,
+                spmd_handle->data, spmd_handle->workspace,
+                spmd_handle->out_control );
+
+        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;
+}
+
+
 /* Reset for the next simulation by parsing input files and triggering
  * reallocation if more space is needed
  *
@@ -434,6 +719,8 @@ int cleanup( const void * const handle )
  * 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 )
@@ -485,9 +772,11 @@ int reset( const void * const handle, const char * const geo_file,
 /* Getter for atom positions
  *
  * handle: pointer to wrapper struct with top-level data structures
- * pos_x: x-coordinate of atom positions (allocated by caller)
- * pos_y: y-coordinate of atom positions (allocated by caller)
- * pos_z: z-coordinate of atom positions (allocated by caller)
+ * pos_x: x-coordinate of atom positions, in Angstroms (allocated by caller)
+ * pos_y: y-coordinate of atom positions, in Angstroms (allocated by caller)
+ * pos_z: z-coordinate 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_x,
         double * const pos_y, double * const pos_z )
@@ -515,10 +804,82 @@ int get_atom_positions( const void * const handle, double * const pos_x,
 }
 
 
+/* Getter for atom velocities
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * vel_x: x-coordinate of atom velocities, in Angstroms / ps (allocated by caller)
+ * vel_y: y-coordinate of atom velocities, in Angstroms / ps (allocated by caller)
+ * vel_z: z-coordinate 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_x,
+        double * const vel_y, double * const vel_z )
+{
+    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_x[i] = spmd_handle->system->atoms[i].v[0];
+            vel_y[i] = spmd_handle->system->atoms[i].v[1];
+            vel_z[i] = 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_x: x-coordinate of atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * f_y: y-coordinate of atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * f_z: z-coordinate 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_x,
+        double * const f_y, double * const f_z )
+{
+    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_x[i] = spmd_handle->system->atoms[i].f[0];
+            f_y[i] = spmd_handle->system->atoms[i].f[1];
+            f_z[i] = 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 (allocated by caller)
+ * 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 )
 {
@@ -543,10 +904,52 @@ int get_atom_charges( const void * const handle, double * const q )
 }
 
 
+/* 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;
+
+        *e_pot = spmd_handle->data->E_Pot;
+        *e_kin = spmd_handle->data->E_Kin;
+        *e_tot = spmd_handle->data->E_Tot;
+        *temp = spmd_handle->data->therm.T;
+        *vol = spmd_handle->system->box.volume;
+        *pres = (spmd_handle->control->P[0] + spmd_handle->control->P[1]
+                + spmd_handle->control->P[2]) / 3.0;
+
+        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 )
 {
@@ -564,3 +967,34 @@ int set_output_enabled( const void * const handle, const int enabled )
 
     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;
+}
diff --git a/sPuReMD/src/spuremd.h b/sPuReMD/src/spuremd.h
index d84c1875..3ee91704 100644
--- a/sPuReMD/src/spuremd.h
+++ b/sPuReMD/src/spuremd.h
@@ -33,7 +33,15 @@
 extern "C"  {
 #endif
 
-void* setup( const char * const, const char * const,
+void * setup_qmmm_( int, const int * const,
+        const double * const, const double * const,
+        const double * const, int, const int * const,
+        const double * const, const double * const,
+        const double * const, const double * const,
+        const double * const,
+        const char * const, const char * const );
+
+void * setup( const char * const, const char * const,
         const char * const );
 
 int setup_callback( const void * const, const callback_function );
@@ -42,16 +50,38 @@ int simulate( const void * const );
 
 int cleanup( const void * const );
 
+int reset_qmmm_( const void * const, int,
+        const int * const,
+        const double * const, const double * const,
+        const double * const, int, const int * const,
+        const double * const, const double * const,
+        const double * const, const double * const,
+        const double * const,
+        const char * const, const char * const );
+
 int reset( const void * const, const char * const,
         const char * const, const char * const );
 
 int get_atom_positions( const void * const, double * const,
         double * const, double * const );
 
+int get_atom_velocities( const void * const, double * const,
+        double * const, double * const );
+
+int get_atom_forces( const void * const, double * const,
+        double * const, double * const );
+
 int get_atom_charges( const void * const, double * const );
 
+int get_system_info( const void * const, double * const,
+        double * const, double * const, double * const,
+        double * const, double * const );
+
 int set_output_enabled( const void * const, const int );
 
+int set_control_parameter( const void * const, const char * const,
+       const char ** const );
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/sPuReMD/src/tool_box.c b/sPuReMD/src/tool_box.c
index b9ed9cbe..1766879c 100644
--- a/sPuReMD/src/tool_box.c
+++ b/sPuReMD/src/tool_box.c
@@ -21,9 +21,15 @@
 
 #include "tool_box.h"
 
+#include <stdlib.h>
 #include <ctype.h>
+#include <limits.h>
+#include <errno.h>
 #include <time.h>
 
+/* base 10 for result of string-to-integer conversion */
+#define INTBASE (10)
+
 
 /************** taken from box.c **************/
 /* Applies transformation on atomic position between Cartesian and
@@ -553,3 +559,135 @@ void sfclose( FILE * fp, const char * msg )
         exit( INVALID_INPUT );
     }
 }
+
+
+/* Safe wrapper around strtol
+ *
+ * str: string to be converted
+ * filename: source filename of caller
+ * line: source line of caller
+ *
+ * returns: result of conversion (integer)
+ * */
+int sstrtol( const char * const str,
+        const char * const filename, int line )
+{
+    long ret;
+    char *endptr;
+
+    if ( str[0] == '\0' )
+    {
+        fprintf( stderr, "[ERROR] sstrtol: NULL string\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        exit( INVALID_INPUT );
+    }
+
+    errno = 0;
+    ret = strtol( str, &endptr, INTBASE );
+
+    if ( (errno == ERANGE && (ret == LONG_MAX || ret == LONG_MIN) )
+            || (errno != 0 && ret == 0) )
+    {
+        fprintf( stderr, "[ERROR] strtol: invalid string\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        fprintf( stderr, "    [INFO] str: %.*s\n",
+                (int) strlen(str), str );
+        exit( INVALID_INPUT );
+    }
+    else if ( endptr == str )
+    {
+        fprintf( stderr, "[ERROR] strtol: no digits found\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        fprintf( stderr, "    [INFO] str: %.*s\n",
+                (int) strlen(str), str );
+        exit( INVALID_INPUT );
+    }
+    else if ( *endptr != '\0' )
+    {
+        fprintf( stderr, "[ERROR] strtol: non-numeric trailing characters\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        fprintf( stderr, "    [INFO] str: %.*s\n",
+                (int) strlen(str), str );
+        exit( INVALID_INPUT );
+    }
+
+    return (int) ret;
+}
+
+
+/* Safe wrapper around strtod
+ *
+ * str: string to be converted
+ * filename: source filename of caller
+ * line: source line of caller
+ *
+ * returns: result of conversion (double)
+ * */
+double sstrtod( const char * const str,
+        const char * const filename, int line )
+{
+    double ret;
+    char *endptr;
+
+    if ( str[0] == '\0' )
+    {
+        fprintf( stderr, "[ERROR] sstrtod: NULL string\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        exit( INVALID_INPUT );
+    }
+
+    errno = 0;
+    ret = strtod( str, &endptr );
+
+    if ( (errno == ERANGE && (ret == LONG_MAX || ret == LONG_MIN) )
+            || (errno != 0 && ret == 0) )
+    {
+        fprintf( stderr, "[ERROR] strtod: invalid string\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        fprintf( stderr, "    [INFO] str: %.*s\n",
+                (int) strlen(str), str );
+        exit( INVALID_INPUT );
+    }
+    else if ( endptr == str )
+    {
+        fprintf( stderr, "[ERROR] strtod: no digits found\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        fprintf( stderr, "    [INFO] str: %.*s\n",
+                (int) strlen(str), str );
+        exit( INVALID_INPUT );
+    }
+    else if ( *endptr != '\0' )
+    {
+        fprintf( stderr, "[ERROR] strtod: non-numeric trailing characters\n" );
+        /* strlen safe here only if filename is NULL-terminated
+         * before calling sconvert_string_to_int */
+        fprintf( stderr, "    [INFO] At line %d in file %.*s\n",
+                line, (int) strlen(filename), filename );
+        fprintf( stderr, "    [INFO] str: %.*s\n",
+                (int) strlen(str), str );
+        exit( INVALID_INPUT );
+    }
+
+    return ret;
+}
diff --git a/sPuReMD/src/tool_box.h b/sPuReMD/src/tool_box.h
index a76bd32d..2c232b1b 100644
--- a/sPuReMD/src/tool_box.h
+++ b/sPuReMD/src/tool_box.h
@@ -26,20 +26,20 @@
 
 
 /* from box.h */
-void Transform( rvec, simulation_box*, int, rvec );
+void Transform( rvec, simulation_box *, int, rvec );
 
-void Transform_to_UnitBox( rvec, simulation_box*, int, rvec );
+void Transform_to_UnitBox( rvec, simulation_box *, int, rvec );
 
-void Fit_to_Periodic_Box( simulation_box*, rvec );
+void Fit_to_Periodic_Box( simulation_box *, rvec );
 
-int is_Inside_Box( simulation_box*, rvec );
+int is_Inside_Box( simulation_box *, rvec );
 
 /* from geo_tools.h */
-void Make_Point( real, real, real, rvec* );
+void Make_Point( real, real, real, rvec * );
 
-int is_Valid_Serial( static_storage*, int );
+int is_Valid_Serial( static_storage *, int );
 
-int Check_Input_Range( int, int, int, char* );
+int Check_Input_Range( int, int, int, char * );
 
 void Trim_Spaces( char * const, const size_t );
 
@@ -49,26 +49,26 @@ real Get_Time( );
 real Get_Timing_Info( real );
 
 /* from io_tools.h */
-int Get_Atom_Type( reax_interaction*, char*, size_t );
+int Get_Atom_Type( reax_interaction *, char *, size_t );
 
-char *Get_Element( reax_system*, int );
+char * Get_Element( reax_system *, int );
 
-char *Get_Atom_Name( reax_system*, int );
+char * Get_Atom_Name( reax_system *, int );
 
-void Allocate_Tokenizer_Space( char**, size_t, char**, size_t, char***,
+void Allocate_Tokenizer_Space( char **, size_t, char **, size_t, char ***,
         size_t, size_t );
 
 void Deallocate_Tokenizer_Space( char **, char **, char ***,
         size_t );
 
-int Tokenize( char*, char***, size_t );
+int Tokenize( char *, char ***, size_t );
 
 /* from lammps */
-void *smalloc( size_t, const char * );
+void * smalloc( size_t, const char * );
 
-void* srealloc( void *, size_t, const char * );
+void * srealloc( void *, size_t, const char * );
 
-void* scalloc( size_t, size_t, const char * );
+void * scalloc( size_t, size_t, const char * );
 
 void sfree( void *, const char * );
 
@@ -76,4 +76,10 @@ FILE * sfopen( const char *, const char * );
 
 void sfclose( FILE *, const char * );
 
+int sstrtol( const char * const,
+        const char * const, int );
+
+double sstrtod( const char * const,
+        const char * const, int );
+
 #endif
diff --git a/sPuReMD/src/vector.h b/sPuReMD/src/vector.h
index f713804a..2f3dd52e 100644
--- a/sPuReMD/src/vector.h
+++ b/sPuReMD/src/vector.h
@@ -73,7 +73,7 @@ static inline void Vector_MakeZero( real * const v, const unsigned int k )
 #endif
     for ( i = 0; i < k; ++i )
     {
-        v[i] = ZERO;
+        v[i] = 0.0;
     }
 }
 
@@ -146,7 +146,7 @@ static inline real Dot( const real * const v1, const real * const v2,
     #pragma omp single
 #endif
     {
-        ret2_omp = ZERO;
+        ret2_omp = 0.0;
     }
 
 #if defined(_OPENMP)
@@ -169,7 +169,7 @@ static inline real Norm( const real * const v1, const unsigned int k )
     #pragma omp single
 #endif
     {
-        ret2_omp = ZERO;
+        ret2_omp = 0.0;
     }
 
 #if defined(_OPENMP)
@@ -478,7 +478,7 @@ static inline void rvec_MakeZero( rvec v )
 #endif
     for ( i = 0; i < 3; ++i )
     {
-        v[i] = ZERO;
+        v[i] = 0.0;
     }
 }
 
@@ -662,7 +662,7 @@ static inline void rtensor_Identity( rtensor t )
     {
         for ( j = 0; j < 3; ++j )
         {
-            t[i][j] = (i == j ? 1.0 : ZERO);
+            t[i][j] = (i == j ? 1.0 : 0.0);
         }
     }
 }
@@ -676,7 +676,7 @@ static inline void rtensor_MakeZero( rtensor t )
     {
         for ( j = 0; j < 3; ++j )
         {
-            t[i][j] = ZERO;
+            t[i][j] = 0.0;
         }
     }
 }
diff --git a/tools/driver_qmmm.py b/tools/driver_qmmm.py
new file mode 100644
index 00000000..ec315724
--- /dev/null
+++ b/tools/driver_qmmm.py
@@ -0,0 +1,524 @@
+#!/bin/python3
+
+from ctypes import c_int, c_double, c_char, c_char_p, c_void_p, \
+        Structure, Union, POINTER, CFUNCTYPE, cdll
+import sqlite3 as sq3
+from os import path
+
+
+class BondOrderData(Structure):
+    _fields_ = [
+            ("BO", c_double),
+            ("BO_s", c_double),
+            ("BO_pi", c_double),
+            ("BO_pi2", c_double),
+            ("Cdbo", c_double),
+            ("Cdbopi", c_double),
+            ("Cdbopi2", c_double),
+            ("C1dbo", c_double),
+            ("C2dbo", c_double),
+            ("C3dbo", c_double),
+            ("C1dbopi", c_double),
+            ("C2dbopi", c_double),
+            ("C3dbopi", c_double),
+            ("C4dbopi", c_double),
+            ("C1dbopi2", c_double),
+            ("C2dbopi2", c_double),
+            ("C3dbopi2", c_double),
+            ("C4dbopi2", c_double),
+            ("dBOp", c_double * 3),
+            ("dln_BOp_s", c_double * 3),
+            ("dln_BOp_pi", c_double * 3),
+            ("dln_BOp_pi2", c_double * 3),
+            ]
+
+
+class ThreeBodyData(Structure):
+    _fields_ = [
+            ("thb", c_int),
+            ("pthb", c_int),
+            ("theta", c_double),
+            ("cos_theta", c_double),
+            ("dcos_di", c_double * 3),
+            ("dcos_dj", c_double * 3),
+            ("dcos_dk", c_double * 3),
+            ]
+
+
+class BondData(Structure):
+    _fields_ = [
+            ("nbr", c_int),
+            ("sym_index", c_int),
+            ("dbond_index", c_int),
+            ("rel_box", c_int * 3),
+            ("d", c_double),
+            ("dvec", c_double * 3),
+            ("bo_data", BondOrderData),
+            ]
+
+
+class DBondData(Structure):
+    _fields_ = [
+            ("wrt", c_int),
+            ("dBO", c_double * 3),
+            ("dBOpi", c_double * 3),
+            ("dBOpi2", c_double * 3),
+            ]
+
+
+class DDeltaData(Structure):
+    _fields_ = [
+            ("wrt", c_int),
+            ("dVal", c_double * 3),
+            ]
+
+
+class FarNbrData(Structure):
+    _fields_ = [
+            ("nbr", c_int),
+            ("rel_box", c_int * 3),
+            ("d", c_double),
+            ("dvec", c_double * 3),
+            ]
+
+
+class NearNbrData(Structure):
+    _fields_ = [
+            ("nbr", c_int),
+            ("rel_box", c_int * 3),
+            ("d", c_double),
+            ("dvec", c_double * 3),
+            ]
+
+
+class HBondData(Structure):
+    _fields_ = [
+            ("nbr", c_int),
+            ("scl", c_int),
+            ("ptr", POINTER(FarNbrData)),
+            ]
+
+
+class Thermostat(Structure):
+    _fields_ = [
+            ("T", c_double),
+            ("xi", c_double),
+            ("v_xi", c_double),
+            ("v_xi_old", c_double),
+            ("G_xi", c_double),
+            ]
+
+
+class IsotropicBarostat(Structure):
+    _fields_ = [
+            ("P", c_double),
+            ("eps", c_double),
+            ("v_eps", c_double),
+            ("v_eps_old", c_double),
+            ("a_eps", c_double),
+            ]
+
+
+class FlexibleBarostat(Structure):
+    _fields_ = [
+            ("P", c_double * 9),
+            ("P_scalar", c_double),
+            ("eps", c_double),
+            ("v_eps", c_double),
+            ("v_eps_old", c_double),
+            ("a_eps", c_double),
+            ("h0", c_double * 9),
+            ("v_g0", c_double * 9),
+            ("v_g0_old", c_double * 9),
+            ("a_g0", c_double * 9),
+            ]
+
+
+class ReaxTiming(Structure):
+    _fields_ = [
+            ("start", c_double),
+            ("end", c_double),
+            ("elapsed", c_double),
+            ("total", c_double),
+            ("nbrs", c_double),
+            ("init_forces", c_double),
+            ("bonded", c_double),
+            ("nonb", c_double),
+            ("cm", c_double),
+            ("cm_sort_mat_rows", c_double),
+            ("cm_solver_pre_comp", c_double),
+            ("cm_solver_pre_app", c_double),
+            ("cm_solver_iters", c_int),
+            ("cm_solver_spmv", c_double),
+            ("cm_solver_vector_ops", c_double),
+            ("cm_solver_orthog", c_double),
+            ("cm_solver_tri_solve", c_double),
+            ("cm_last_pre_comp", c_double),
+            ("cm_total_loss", c_double),
+            ("cm_optimum", c_double),
+            ("num_retries", c_int),
+            ]
+
+
+class SimulationData(Structure):
+    _fields_ = [
+            ("sim_id", c_int),
+            ("step", c_int),
+            ("prev_step", c_int),
+            ("time", c_double),
+            ("M", c_double),
+            ("inv_M", c_double),
+            ("xcm", c_double * 3),
+            ("vcm", c_double * 3),
+            ("fcm", c_double * 3),
+            ("amcm", c_double * 3),
+            ("avcm", c_double * 3),
+            ("etran_cm", c_double),
+            ("erot_cm", c_double),
+            ("kinetic", c_double * 9),
+            ("virial", c_double * 9),
+            ("E_Tot", c_double),
+            ("E_Kin", c_double),
+            ("E_Pot", c_double),
+            ("E_BE", c_double),
+            ("E_Ov", c_double),
+            ("E_Un", c_double),
+            ("E_Lp", c_double),
+            ("E_Ang", c_double),
+            ("E_Pen", c_double),
+            ("E_Coa", c_double),
+            ("E_HB", c_double),
+            ("E_Tor", c_double),
+            ("E_Con", c_double),
+            ("E_vdW", c_double),
+            ("E_Ele", c_double),
+            ("E_Pol", c_double),
+            ("N_f", c_double),
+            ("t_scale", c_double * 3),
+            ("p_scale", c_double * 9),
+            ("therm", Thermostat),
+            ("iso_bar", IsotropicBarostat),
+            ("flex_bar", FlexibleBarostat),
+            ("inv_W", c_double),
+            ("int_press", c_double * 3),
+            ("ext_press", c_double * 3),
+            ("kin_press", c_double),
+            ("tot_press", c_double * 3),
+            ("timing", ReaxTiming),
+            ]
+
+
+class ReaxAtom(Structure):
+    _fields_ = [
+            ("type", c_int),
+            ("rel_map", c_int * 3),
+            ("name", c_char * 9),
+            ("x", c_double * 3),
+            ("v", c_double * 3),
+            ("f", c_double * 3),
+            ("q", c_double),
+            ]
+
+
+def create_db(name='spuremd.db'):
+    conn = sq3.connect(name)
+
+    conn.executescript("""
+        CREATE TABLE simulation(
+            id integer,
+            date text,
+            name text,
+            ensemble_type integer,
+            steps integer,
+            time_step integer,
+            restart_format integer,
+            random_velocity integer,
+            reposition_atoms integer,
+            peroidic_boundary integer,
+            geo_format integer,
+            restrict_bonds integer,
+            tabulate_long_range integer,
+            reneighbor integer,
+            vlist_cutoff real,
+            neighbor_cutoff real,
+            three_body_cutoff real,
+            hydrogen_bond_cutoff real,
+            bond_graph_cutoff real,
+            charge_method integer,
+            cm_q_net real,
+            cm_solver_type integer,
+            cm_solver_max_iters integer,
+            cm_solver_restart integer,
+            cm_solver_q_err real,
+            cm_domain_sparsity real,
+            cm_solver_pre_comp_type integer,
+            cm_solver_pre_comp_refactor integer,
+            cm_solver_pre_comp_droptol real,
+            cm_solver_pre_comp_sweeps integer,
+            cm_solver_pre_comp_sai_thres real,
+            cm_solver_pre_app_type integer,
+            cm_solver_pre_app_jacobi_iters integer,
+            temp_init real,
+            temp_final real,
+            temp_mass real,
+            temp_mode integer,
+            temp_rate real,
+            temp_freq integer,
+            pressure real,
+            pressure_mass real,
+            compress integer,
+            pressure_mode integer,
+            remove_center_of_mass integer,
+            debug_level integer,
+            write_freq integer,
+            traj_compress integer,
+            traj_format integer,
+            traj_title text,
+            atom_info integer,
+            atom_velocities integer,
+            atom_forces integer,
+            bond_info integer,
+            angle_info integer,
+            test_forces integer,
+            molecule_analysis integer,
+            freq_molecule_analysis integer,
+            ignore integer,
+            dipole_analysis integer,
+            freq_dipole_analysis integer,
+            diffusion_coefficient integer,
+            freq_diffusion_coefficient integer,
+            restrict_type integer,
+            PRIMARY KEY (id)
+        );
+
+        CREATE TABLE system_properties(
+            id integer,
+            step integer,
+            total_energy real,
+            potential_energy real,
+            kinetic_energy real,
+            temperature real,
+            volume real,
+            pressure real,
+            PRIMARY KEY (id, step)
+        );
+
+        CREATE TABLE potential(
+            id integer,
+            step integer,
+            bond_energy real,
+            atom_energy real,
+            lone_pair_energy real,
+            angle_energy real,
+            coa_energy real,
+            hydrogen_bond_energy real,
+            torsion_energy real,
+            conjugation_energy real,
+            van_der_waals_energy real,
+            coulombic_energy real,
+            polarization_energy real,
+            PRIMARY KEY (id, step)
+        );
+
+        CREATE TABLE trajectory(
+            id integer,
+            step integer,
+            atom_id integer,
+            position_x real,
+            position_y real,
+            position_z real,
+            charge real,
+            PRIMARY KEY (id, step, atom_id)
+        );
+
+        CREATE TABLE performance(
+            id integer,
+            step integer,
+            time_total real,
+            time_nbrs real,
+            time_init real,
+            time_bonded real,
+            time_nonbonded real,
+            time_cm real,
+            time_cm_sort real,
+            cm_solver_iters integer,
+            time_cm_pre_comp real,
+            time_cm_pre_app real,
+            time_cm_solver_spmv real,
+            time_cm_solver_vec_ops real,
+            time_cm_solver_orthog real,
+            time_cm_solver_tri_solve real,
+            PRIMARY KEY (id, step)
+        );
+    """)
+
+    conn.close()
+
+
+if __name__ == '__main__':
+    lib = cdll.LoadLibrary("libspuremd.so.1")
+
+    setup_qmmm = lib.setup_qmmm_
+    setup_qmmm.argtypes = [c_int, POINTER(c_int),
+            POINTER(c_double), POINTER(c_double), POINTER(c_double),
+            c_int, POINTER(c_int), POINTER(c_double), POINTER(c_double),
+            POINTER(c_double), POINTER(c_double), POINTER(c_double),
+            c_char_p, c_char_p]
+    setup_qmmm.restype = c_void_p
+
+    simulate = lib.simulate
+    simulate.argtypes = [c_void_p]
+    simulate.restype = c_int
+
+    cleanup = lib.cleanup
+    cleanup.argtypes = [c_void_p]
+    cleanup.restype = c_int
+
+    reset_qmmm = lib.reset_qmmm_
+    reset_qmmm.argtypes = [c_void_p, c_int, POINTER(c_int),
+            POINTER(c_double), POINTER(c_double), POINTER(c_double),
+            c_int, POINTER(c_int), POINTER(c_double), POINTER(c_double),
+            POINTER(c_double), POINTER(c_double), POINTER(c_double),
+            c_char_p, c_char_p]
+    reset_qmmm.restype = c_int
+
+    CALLBACKFUNC = CFUNCTYPE(None, c_int, POINTER(ReaxAtom),
+            POINTER(SimulationData))
+
+    setup_callback = lib.setup_callback
+    setup_callback.argtypes = [c_void_p, CALLBACKFUNC]
+    setup_callback.restype = c_int
+
+    set_control_parameter = lib.set_control_parameter
+    set_control_parameter.argtypes = [c_void_p, c_char_p, POINTER(c_char_p)]
+    set_control_parameter.restype = c_int
+
+    get_atom_positions = lib.get_atom_positions
+    get_atom_positions.argtypes = [c_void_p, POINTER(c_double),
+            POINTER(c_double), POINTER(c_double)]
+    get_atom_positions.restype = c_int
+
+    get_atom_forces = lib.get_atom_forces
+    get_atom_forces.argtypes = [c_void_p, POINTER(c_double),
+            POINTER(c_double), POINTER(c_double)]
+    get_atom_forces.restype = c_int
+
+    get_atom_charges = lib.get_atom_charges
+    get_atom_charges.argtypes = [c_void_p, POINTER(c_double)]
+    get_atom_charges.restype = c_int
+
+    def get_simulation_step_results(num_atoms, atoms, data):
+        print("{0:24.15f} {1:24.15f} {2:24.15f}".format(
+            data[0].E_Tot, data[0].E_Kin, data[0].E_Pot))
+
+    # bulk water
+    sim_box = (c_double * 6)(40.299, 40.299, 40.299, 90.0, 90.0, 90.0)
+    num_qm_atoms = 10
+    num_mm_atoms = 10
+    num_atoms = num_qm_atoms + num_mm_atoms
+    qm_types = (c_int * num_qm_atoms)(2, 1, 1, 2, 1, 1, 2, 1, 1, 2)
+    qm_p_x = (c_double * num_qm_atoms)(5.690, 4.760, 5.800, 15.551, 14.981, 14.961, 17.431, 17.761, 17.941, 11.351)
+    qm_p_y = (c_double * num_qm_atoms)(12.751, 12.681, 13.641, 15.111, 14.951, 15.211, 6.180, 7.120, 5.640, 7.030)
+    qm_p_z = (c_double * num_qm_atoms)(11.651, 11.281, 12.091, 7.030, 7.840, 6.230, 8.560, 8.560, 9.220, 7.170)
+    mm_types = (c_int * num_qm_atoms)(1, 1, 2, 1, 1, 2, 1, 1, 2, 1)
+    mm_p_x = (c_double * num_mm_atoms)(11.921, 10.751, 17.551, 17.431, 17.251, 7.680, 6.900, 8.020, 8.500, 8.460)
+    mm_p_y = (c_double * num_mm_atoms)(7.810, 7.290, 6.070, 5.940, 5.260, 11.441, 11.611, 12.311, 7.980, 8.740)
+    mm_p_z = (c_double * num_mm_atoms)(6.920, 7.930, 2.310, 1.320, 2.800, 10.231, 10.831, 9.871, 18.231, 18.881)
+    mm_q = (c_double * num_mm_atoms)(-2.0, 1.0, 1.0, -2.0, 1.0, 1.0, -2.0, 1.0, 1.0, -2.0)
+
+    handle = setup_qmmm(c_int(num_qm_atoms), qm_types, qm_p_x, qm_p_y, qm_p_z,
+            c_int(num_mm_atoms), mm_types, mm_p_x, mm_p_y, mm_p_z, mm_q, sim_box,
+            b"data/benchmarks/water/ffield.water",
+            b"environ/control_water")
+
+    ret = setup_callback(handle, CALLBACKFUNC(get_simulation_step_results))
+
+    if ret != 0:
+        print("[ERROR] setup_callback returned {0}".format(ret))
+
+    keyword = b"nsteps"
+    values = (c_char_p)(b"10")
+    ret = set_control_parameter(handle, keyword, values)
+
+    if ret != 0:
+        print("[ERROR] set_control_parameter returned {0}".format(ret))
+
+    print("{0:24}|{1:24}|{2:24}".format("Total Energy", "Kinetic Energy", "Potential Energy"))
+
+    ret = simulate(handle)
+
+    if ret != 0:
+        print("[ERROR] simulate returned {0}".format(ret))
+
+    p_x = (c_double * num_atoms)()
+    p_y = (c_double * num_atoms)()
+    p_z = (c_double * num_atoms)()
+    ret = get_atom_positions(handle, p_x, p_y, p_z)
+
+    if ret != 0:
+        print("[ERROR] get_atom_positions returned {0}".format(ret))
+
+    f_x = (c_double * num_atoms)()
+    f_y = (c_double * num_atoms)()
+    f_z = (c_double * num_atoms)()
+    ret = get_atom_forces(handle, f_x, f_y, f_z)
+
+    if ret != 0:
+        print("[ERROR] get_atom_forces returned {0}".format(ret))
+
+    q = (c_double * num_atoms)()
+    ret = get_atom_charges(handle, q)
+
+    if ret != 0:
+        print("[ERROR] get_atom_charges returned {0}".format(ret))
+
+    # silica
+    sim_box = (c_double * 6)(36.477, 50.174, 52.110, 90.0, 90.0, 90.0)
+    num_qm_atoms = 15
+    num_mm_atoms = 15
+    num_atoms = num_qm_atoms + num_mm_atoms
+    qm_types = (c_int * num_qm_atoms)(2, 2, 2, 2, 10, 2, 10, 2, 2, 10, 2, 10, 2, 2)
+    qm_p_x = (c_double * num_qm_atoms)(56.987, 32.795, 26.543, 27.616, 26.560, 54.035, 54.425, 29.979, 38.008, 48.769, 57.113, 26.458, 52.299, 55.789, 45.752)
+    qm_p_y = (c_double * num_qm_atoms)(39.868, 24.104, 26.261, 27.534, 39.146, 39.112, 37.117, 43.558, 47.170, 42.454, 35.565, 35.477, 39.113, 41.444, 44.237)
+    qm_p_z = (c_double * num_qm_atoms)(41.795, 25.968, 36.254, 24.459, 32.281, 23.745, 32.278, 21.696, 27.275, 20.461, 31.366, 23.522, 26.519, 30.466, 10.521)
+    mm_types = (c_int * num_qm_atoms)(10, 2, 10, 2, 2, 2, 10, 2, 10, 2, 2, 10, 2, 2, 10)
+    mm_p_x = (c_double * num_mm_atoms)(49.617, 26.736, 58.166, 36.655, 55.773, 53.905, 52.254, 32.196, 53.817, 56.164, 28.678, 58.824, 24.807, 51.299, 28.950)
+    mm_p_y = (c_double * num_mm_atoms)(42.379, 37.815, 5.488, 48.615, 36.249, 1.450, 35.399, 6.595, 8.586, 1.585, 7.208, 36.067, 6.365, 25.234, 11.190)
+    mm_p_z = (c_double * num_mm_atoms)(21.790, 33.119, 0.945, 25.664, 31.954, 22.720, 33.665, 23.147, 31.684, 23.550, 30.801, 40.036, 24.849, 29.146, 24.542)
+    mm_q = (c_double * num_mm_atoms)(-1.0, -2.0, -1.0, -2.0, -2.0, -2.0, -1.0, -2.0, -1.0, -2.0, -2.0, -1.0, -2.0, -2.0, -1.0)
+
+    ret = reset_qmmm(handle, c_int(num_qm_atoms), qm_types, qm_p_x, qm_p_y, qm_p_z,
+            c_int(num_mm_atoms), mm_types, mm_p_x, mm_p_y, mm_p_z, mm_q, sim_box,
+            b"data/benchmarks/silica/ffield-bio",
+            b"environ/control_silica")
+
+    print("\n{0:24}|{1:24}|{2:24}".format("Total Energy", "Kinetic Energy", "Potential Energy"))
+
+    ret = simulate(handle)
+
+    if ret != 0:
+        print("[ERROR] simulate returned {0}".format(ret))
+
+    p_x = (c_double * num_atoms)()
+    p_y = (c_double * num_atoms)()
+    p_z = (c_double * num_atoms)()
+    ret = get_atom_positions(handle, p_x, p_y, p_z)
+
+    if ret != 0:
+        print("[ERROR] get_atom_positions returned {0}".format(ret))
+
+    f_x = (c_double * num_atoms)()
+    f_y = (c_double * num_atoms)()
+    f_z = (c_double * num_atoms)()
+    ret = get_atom_forces(handle, f_x, f_y, f_z)
+
+    if ret != 0:
+        print("[ERROR] get_atom_forces returned {0}".format(ret))
+
+    q = (c_double * num_atoms)()
+    ret = get_atom_charges(handle, q)
+
+    if ret != 0:
+        print("[ERROR] get_atom_charges returned {0}".format(ret))
+
+    cleanup(handle)
-- 
GitLab