From e01ba7a4c54cc1cf094c5af808042b7fdbac3517 Mon Sep 17 00:00:00 2001
From: "Kurt A. O'Hearn" <ohearnk@msu.edu>
Date: Mon, 12 Nov 2018 09:55:38 -0500
Subject: [PATCH] PuReMD-old: backport control file format changes.

---
 PuReMD/src/control.c     | 777 ++++++++++++++++++++++-----------------
 PuReMD/src/forces.c      |   4 +-
 PuReMD/src/io_tools.c    |   4 +-
 PuReMD/src/qEq.c         |  13 +-
 PuReMD/src/reax_types.h  | 299 ++++++++++++---
 PuReMD/src/reset_tools.c |  15 +-
 PuReMD/src/tool_box.c    |  62 ++++
 PuReMD/src/tool_box.h    |   4 +
 PuReMD/src/traj.c        |   2 +-
 9 files changed, 772 insertions(+), 408 deletions(-)

diff --git a/PuReMD/src/control.c b/PuReMD/src/control.c
index cd95c246..ae9bcee8 100644
--- a/PuReMD/src/control.c
+++ b/PuReMD/src/control.c
@@ -20,12 +20,13 @@
   ----------------------------------------------------------------------*/
 
 #include "reax_types.h"
+
 #if defined(PURE_REAX)
-#include "control.h"
-#include "tool_box.h"
+  #include "control.h"
+  #include "tool_box.h"
 #elif defined(LAMMPS_REAX)
-#include "reax_control.h"
-#include "reax_tool_box.h"
+  #include "reax_control.h"
+  #include "reax_tool_box.h"
 #endif
 
 
@@ -34,49 +35,58 @@ char Read_Control_File( char *control_file, control_params* control,
 {
     FILE *fp;
     char *s, **tmp;
-    int   c, i, ival;
-    real  val;
+    int c, i, ival;
+    real val;
 
-    /* open control file */
-    if ( (fp = fopen( control_file, "r" ) ) == NULL )
-    {
-        fprintf( stderr, "error opening the control file! terminating...\n" );
-        MPI_Abort( MPI_COMM_WORLD,  FILE_NOT_FOUND );
-    }
+    fp = sfopen( control_file, "r", "Read_Control_File::fp" );
 
     /* assign default values */
-    strcpy( control->sim_name, "simulate" );
-    control->ensemble        = NVE;
-    control->nsteps          = 0;
-    control->dt              = 0.25;
-    control->nprocs          = 1;
+    strcpy( control->sim_name, "default.sim" );
+    control->ensemble = NVE;
+    control->nsteps = 100;
+    control->dt = 0.25;
+    control->nprocs = 1;
     control->procs_by_dim[0] = 1;
     control->procs_by_dim[1] = 1;
     control->procs_by_dim[2] = 1;
     control->geo_format = 1;
 
-    control->restart          = 0;
+    control->random_vel = 0;
+    control->restart = 0;
     out_control->restart_format = WRITE_BINARY;
     out_control->restart_freq = 0;
     control->reposition_atoms = 0;
-    control->restrict_bonds   = 0;
-    control->remove_CoM_vel   = 25;
-    out_control->debug_level  = 0;
+    control->restrict_bonds = 0;
+    control->remove_CoM_vel = 25;
+    out_control->debug_level = 0;
     out_control->energy_update_freq = 0;
 
     control->reneighbor = 1;
-    control->vlist_cut = control->nonb_cut;
     control->bond_cut = 5.0;
+    control->vlist_cut = control->nonb_cut;
     control->bg_cut = 0.3;
     control->thb_cut = 0.001;
     control->hbond_cut = 0.0;
 
     control->tabulate = 0;
 
-    control->qeq_freq = 1;
-    control->q_err = 1e-6;
-    control->refactor = 100;
-    control->droptol = 1e-2;;
+    control->charge_method = QEQ_CM;
+    control->charge_freq = 1;
+    control->cm_q_net = 0.0;
+    control->cm_solver_type = CG_S;
+    control->cm_solver_max_iters = 1000;
+    control->cm_solver_restart = 100;
+    control->cm_solver_q_err = 0.000001;
+    control->cm_domain_sparsify_enabled = FALSE;
+    control->cm_init_guess_extrap1 = 3;
+    control->cm_init_guess_extrap2 = 2;
+    control->cm_domain_sparsity = 1.0;
+    control->cm_solver_pre_comp_type = JACOBI_PC;
+    control->cm_solver_pre_comp_sweeps = 3;
+    control->cm_solver_pre_comp_refactor = 100;
+    control->cm_solver_pre_comp_droptol = 0.01;
+    control->cm_solver_pre_app_type = TRI_SOLVE_PA;
+    control->cm_solver_pre_app_jacobi_iters = 50;
 
     control->T_init = 0.;
     control->T_final = 300.;
@@ -97,8 +107,8 @@ char Read_Control_File( char *control_file, control_params* control,
     out_control->traj_method = REG_TRAJ;
     strcpy( out_control->traj_title, "default_title" );
     out_control->atom_info = 0;
-    out_control->bond_info = 0;
-    out_control->angle_info = 0;
+    out_control->bond_info = 1;
+    out_control->angle_info = 1;
 
     control->molecular_analysis = 0;
     control->dipole_anal = 0;
@@ -108,339 +118,440 @@ char Read_Control_File( char *control_file, control_params* control,
     control->restrict_type = 0;
 
     /* memory allocations */
-    s = (char*) malloc(sizeof(char) * MAX_LINE);
-    tmp = (char**) malloc(sizeof(char*)*MAX_TOKENS);
+    s = (char*) smalloc( sizeof(char) * MAX_LINE, "Read_Control_File::s", MPI_COMM_WORLD );
+    tmp = (char**) smalloc( sizeof(char*) * MAX_TOKENS, "Read_Control_File::tmp", MPI_COMM_WORLD );
     for (i = 0; i < MAX_TOKENS; i++)
-        tmp[i] = (char*) malloc(sizeof(char) * MAX_LINE);
+    {
+        tmp[i] = (char*) smalloc( sizeof(char) * MAX_LINE, "Read_Control_File::tmp[i]", MPI_COMM_WORLD );
+    }
 
     /* read control parameters file */
     while ( fgets( s, MAX_LINE, fp ) )
     {
         c = Tokenize( s, &tmp );
-        //fprintf( stderr, "%s\n", s );
 
-        if ( strcmp(tmp[0], "simulation_name") == 0 )
-        {
-            strcpy( control->sim_name, tmp[1] );
-        }
-        else if ( strcmp(tmp[0], "ensemble_type") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->ensemble = ival;
-            if ( ival == iNPT || ival == sNPT || ival == NPT )
-                control->virial = 1;
-        }
-        else if ( strcmp(tmp[0], "nsteps") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->nsteps = ival;
-        }
-        else if ( strcmp(tmp[0], "dt") == 0)
-        {
-            val = atof(tmp[1]);
-            control->dt = val * 1.e-3;  // convert dt from fs to ps!
-        }
-        else if ( strcmp(tmp[0], "proc_by_dim") == 0 )
+        if ( c > 0 )
         {
-            ival = atoi(tmp[1]);
-            control->procs_by_dim[0] = ival;
-            ival = atoi(tmp[2]);
-            control->procs_by_dim[1] = ival;
-            ival = atoi(tmp[3]);
-            control->procs_by_dim[2] = ival;
+            if ( strcmp(tmp[0], "simulation_name") == 0 )
+            {
+                strcpy( control->sim_name, tmp[1] );
+            }
+            else if ( strcmp(tmp[0], "ensemble_type") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->ensemble = ival;
+            }
+            else if ( strcmp(tmp[0], "nsteps") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->nsteps = ival;
+            }
+            else if ( strcmp(tmp[0], "dt") == 0)
+            {
+                val = atof(tmp[1]);
+                control->dt = val * 1.e-3;  // convert dt from fs to ps!
+            }
+            else if ( strncmp(tmp[0], "gpus_per_node", MAX_LINE) == 0 )
+            {
+                // skip since not applicable to non-gpu distributed memory code
+                ;
+            }
+            else if ( strcmp(tmp[0], "proc_by_dim") == 0 )
+            {
+                if ( c < 4 )
+                {
+                    fprintf( stderr, "[ERROR] invalid number of control file parameters (procs_by_dim). terminating!\n" );
+                    MPI_Abort( MPI_COMM_WORLD, INVALID_INPUT );
+                }
 
-            control->nprocs = control->procs_by_dim[0] * control->procs_by_dim[1] *
-                              control->procs_by_dim[2];
-        }
-        //else if( strcmp(tmp[0], "restart") == 0 ) {
-        //  ival = atoi(tmp[1]);
-        //  control->restart = ival;
-        //}
-        //else if( strcmp(tmp[0], "restart_from") == 0 ) {
-        //  strcpy( control->restart_from, tmp[1] );
-        //}
-        else if ( strcmp(tmp[0], "random_vel") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->random_vel = ival;
-        }
-        else if ( strcmp(tmp[0], "restart_format") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->restart_format = ival;
-        }
-        else if ( strcmp(tmp[0], "restart_freq") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->restart_freq = ival;
-        }
-        else if ( strcmp(tmp[0], "reposition_atoms") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->reposition_atoms = ival;
-        }
-        else if ( strcmp(tmp[0], "restrict_bonds") == 0 )
-        {
-            ival = atoi( tmp[1] );
-            control->restrict_bonds = ival;
-        }
-        else if ( strcmp(tmp[0], "remove_CoM_vel") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->remove_CoM_vel = ival;
-        }
-        else if ( strcmp(tmp[0], "debug_level") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->debug_level = ival;
-        }
-        else if ( strcmp(tmp[0], "energy_update_freq") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->energy_update_freq = ival;
-        }
-        else if ( strcmp(tmp[0], "reneighbor") == 0 )
-        {
-            ival = atoi( tmp[1] );
-            control->reneighbor = ival;
-        }
-        else if ( strcmp(tmp[0], "vlist_buffer") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->vlist_cut = val + control->nonb_cut;
-        }
-        else if ( strcmp(tmp[0], "nbrhood_cutoff") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->bond_cut = val;
-        }
-        else if ( strcmp(tmp[0], "bond_graph_cutoff") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->bg_cut = val;
-        }
-        else if ( strcmp(tmp[0], "thb_cutoff") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->thb_cut = val;
-        }
-        else if ( strcmp(tmp[0], "hbond_cutoff") == 0 )
-        {
-            val = atof( tmp[1] );
-            control->hbond_cut = val;
-        }
-        else if ( strcmp(tmp[0], "ghost_cutoff") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->user_ghost_cut = val;
-        }
-        else if ( strcmp(tmp[0], "tabulate_long_range") == 0 )
-        {
-            ival = atoi( tmp[1] );
-            control->tabulate = ival;
-        }
-        else if ( strcmp(tmp[0], "qeq_freq") == 0 )
-        {
-            ival = atoi( tmp[1] );
-            control->qeq_freq = ival;
-        }
-        else if ( strcmp(tmp[0], "q_err") == 0 )
-        {
-            val = atof( tmp[1] );
-            control->q_err = val;
-        }
-        else if ( strcmp(tmp[0], "ilu_refactor") == 0 )
-        {
-            ival = atoi( tmp[1] );
-            control->refactor = ival;
-        }
-        else if ( strcmp(tmp[0], "ilu_droptol") == 0 )
-        {
-            val = atof( tmp[1] );
-            control->droptol = val;
-        }
-        else if ( strcmp(tmp[0], "temp_init") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->T_init = val;
+                ival = atoi(tmp[1]);
+                control->procs_by_dim[0] = ival;
+                ival = atoi(tmp[2]);
+                control->procs_by_dim[1] = ival;
+                ival = atoi(tmp[3]);
+                control->procs_by_dim[2] = ival;
 
-            if ( control->T_init < 0.1 )
-                control->T_init = 0.1;
-        }
-        else if ( strcmp(tmp[0], "temp_final") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->T_final = val;
+                control->nprocs = control->procs_by_dim[0] * control->procs_by_dim[1] *
+                        control->procs_by_dim[2];
+            }
+            //else if( strcmp(tmp[0], "restart") == 0 ) {
+            //  ival = atoi(tmp[1]);
+            //  control->restart = ival;
+            //}
+            //else if( strcmp(tmp[0], "restart_from") == 0 ) {
+            //  strcpy( control->restart_from, tmp[1] );
+            //}
+            else if ( strcmp(tmp[0], "random_vel") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->random_vel = ival;
+            }
+            else if ( strcmp(tmp[0], "restart_format") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->restart_format = ival;
+            }
+            else if ( strcmp(tmp[0], "restart_freq") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->restart_freq = ival;
+            }
+            else if ( strcmp(tmp[0], "reposition_atoms") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->reposition_atoms = ival;
+            }
+            else if ( strcmp(tmp[0], "restrict_bonds") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->restrict_bonds = ival;
+            }
+            else if ( strcmp(tmp[0], "remove_CoM_vel") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->remove_CoM_vel = ival;
+            }
+            else if ( strcmp(tmp[0], "debug_level") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->debug_level = ival;
+            }
+            else if ( strcmp(tmp[0], "energy_update_freq") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->energy_update_freq = ival;
+            }
+            else if ( strcmp(tmp[0], "reneighbor") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->reneighbor = ival;
+            }
+            else if ( strcmp(tmp[0], "vlist_buffer") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->vlist_cut = val + control->nonb_cut;
+            }
+            else if ( strcmp(tmp[0], "nbrhood_cutoff") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->bond_cut = val;
+            }
+            else if ( strcmp(tmp[0], "bond_graph_cutoff") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->bg_cut = val;
+            }
+            else if ( strcmp(tmp[0], "thb_cutoff") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->thb_cut = val;
+            }
+            else if ( strcmp(tmp[0], "hbond_cutoff") == 0 )
+            {
+                val = atof( tmp[1] );
+                control->hbond_cut = val;
+            }
+            else if ( strcmp(tmp[0], "ghost_cutoff") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->user_ghost_cut = val;
+            }
+            else if ( strcmp(tmp[0], "tabulate_long_range") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->tabulate = ival;
+            }
+            else if ( strcmp(tmp[0], "charge_method") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->charge_method = ival;
+            }
+            else if ( strcmp(tmp[0], "charge_freq") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->charge_freq = ival;
+            }
+            else if ( strcmp(tmp[0], "cm_q_net") == 0 )
+            {
+                val = atof( tmp[1] );
+                control->cm_q_net = val;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_type") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->cm_solver_type = ival;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_max_iters") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->cm_solver_max_iters = ival;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_restart") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->cm_solver_restart = ival;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_q_err") == 0 )
+            {
+                val = atof( tmp[1] );
+                control->cm_solver_q_err = val;
+            }
+            else if ( strcmp(tmp[0], "cm_domain_sparsity") == 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_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 ( strcmp(tmp[0], "cm_solver_pre_comp_type") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->cm_solver_pre_comp_type = ival;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_pre_comp_refactor") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->cm_solver_pre_comp_refactor = ival;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_pre_comp_droptol") == 0 )
+            {
+                val = atof( tmp[1] );
+                control->cm_solver_pre_comp_droptol = val;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_pre_comp_sweeps") == 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 ( strcmp(tmp[0], "cm_solver_pre_app_type") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->cm_solver_pre_app_type = ival;
+            }
+            else if ( strcmp(tmp[0], "cm_solver_pre_app_jacobi_iters") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->cm_solver_pre_app_jacobi_iters = ival;
+            }
+            else if ( strcmp(tmp[0], "temp_init") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->T_init = val;
 
-            if ( control->T_final < 0.1 )
-                control->T_final = 0.1;
-        }
-        else if ( strcmp(tmp[0], "t_mass") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->Tau_T = val * 1.e-3;    // convert t_mass from fs to ps
-        }
-        else if ( strcmp(tmp[0], "t_mode") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->T_mode = ival;
-        }
-        else if ( strcmp(tmp[0], "t_rate") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->T_rate = val;
-        }
-        else if ( strcmp(tmp[0], "t_freq") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->T_freq = val;
-        }
-        else if ( strcmp(tmp[0], "pressure") == 0 )
-        {
-            if ( control->ensemble == iNPT )
+                if ( control->T_init < 0.1 )
+                {
+                    control->T_init = 0.1;
+                }
+            }
+            else if ( strcmp(tmp[0], "temp_final") == 0 )
             {
-                control->P[0] = control->P[1] = control->P[2] = atof(tmp[1]);
+                val = atof(tmp[1]);
+                control->T_final = val;
+
+                if ( control->T_final < 0.1 )
+                {
+                    control->T_final = 0.1;
+                }
             }
-            else if ( control->ensemble == sNPT )
+            else if ( strcmp(tmp[0], "t_mass") == 0 )
             {
-                control->P[0] = atof(tmp[1]);
-                control->P[1] = atof(tmp[2]);
-                control->P[2] = atof(tmp[3]);
+                val = atof(tmp[1]);
+                control->Tau_T = val * 1.e-3;    // convert t_mass from fs to ps
             }
-        }
-        else if ( strcmp(tmp[0], "p_mass") == 0 )
-        {
-            // convert p_mass from fs to ps
-            if ( control->ensemble == iNPT )
+            else if ( strcmp(tmp[0], "t_mode") == 0 )
             {
-                control->Tau_P[0] = control->Tau_P[1] = control->Tau_P[2] =
-                        atof(tmp[1]) * 1.e-3;
+                ival = atoi(tmp[1]);
+                control->T_mode = ival;
             }
-            else if ( control->ensemble == sNPT )
+            else if ( strcmp(tmp[0], "t_rate") == 0 )
             {
-                control->Tau_P[0] = atof(tmp[1]) * 1.e-3;
-                control->Tau_P[1] = atof(tmp[2]) * 1.e-3;
-                control->Tau_P[2] = atof(tmp[3]) * 1.e-3;
+                val = atof(tmp[1]);
+                control->T_rate = val;
+            }
+            else if ( strcmp(tmp[0], "t_freq") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->T_freq = val;
+            }
+            else if ( strcmp(tmp[0], "pressure") == 0 )
+            {
+                if ( control->ensemble == iNPT )
+                {
+                    control->P[0] = control->P[1] = control->P[2] = atof(tmp[1]);
+                }
+                else if ( control->ensemble == sNPT )
+                {
+                    control->P[0] = atof(tmp[1]);
+                    control->P[1] = atof(tmp[2]);
+                    control->P[2] = atof(tmp[3]);
+                }
+            }
+            else if ( strcmp(tmp[0], "p_mass") == 0 )
+            {
+                // convert p_mass from fs to ps
+                if ( control->ensemble == iNPT )
+                {
+                    control->Tau_P[0] = control->Tau_P[1] = control->Tau_P[2] =
+                            atof(tmp[1]) * 1.e-3;
+                }
+                else if ( control->ensemble == sNPT )
+                {
+                    control->Tau_P[0] = atof(tmp[1]) * 1.e-3;
+                    control->Tau_P[1] = atof(tmp[2]) * 1.e-3;
+                    control->Tau_P[2] = atof(tmp[3]) * 1.e-3;
+                }
+            }
+            else if ( strcmp(tmp[0], "pt_mass") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->Tau_PT[0] = control->Tau_PT[1] = control->Tau_PT[2] =
+                                         val * 1.e-3;  // convert pt_mass from fs to ps
+            }
+            else if ( strcmp(tmp[0], "compress") == 0 )
+            {
+                val = atof(tmp[1]);
+                control->compressibility = val;
+            }
+            else if ( strcmp(tmp[0], "press_mode") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->press_mode = ival;
+            }
+            else if ( strcmp(tmp[0], "geo_format") == 0 )
+            {
+                ival = atoi( tmp[1] );
+                control->geo_format = ival;
+            }
+            else if ( strcmp(tmp[0], "write_freq") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->write_steps = ival;
+            }
+            else if ( strcmp(tmp[0], "traj_compress") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->traj_compress = ival;
+            }
+            else if ( strcmp(tmp[0], "traj_method") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->traj_method = ival;
+            }
+            else if ( strcmp(tmp[0], "traj_title") == 0 )
+            {
+                strcpy( out_control->traj_title, tmp[1] );
+            }
+            else if ( strcmp(tmp[0], "atom_info") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->atom_info += ival * 4;
+            }
+            else if ( strcmp(tmp[0], "atom_velocities") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->atom_info += ival * 2;
+            }
+            else if ( strcmp(tmp[0], "atom_forces") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->atom_info += ival * 1;
+            }
+            else if ( strcmp(tmp[0], "bond_info") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->bond_info = ival;
+            }
+            else if ( strcmp(tmp[0], "angle_info") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                out_control->angle_info = ival;
+            }
+            else if ( strcmp(tmp[0], "molecular_analysis") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->molecular_analysis = ival;
+            }
+            else if ( strcmp(tmp[0], "ignore") == 0 )
+            {
+                control->num_ignored = atoi(tmp[1]);
+                for ( i = 0; i < control->num_ignored; ++i )
+                {
+                    control->ignore[atoi(tmp[i + 2])] = 1;
+                }
+            }
+            else if ( strcmp(tmp[0], "dipole_anal") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->dipole_anal = ival;
+            }
+            else if ( strcmp(tmp[0], "freq_dipole_anal") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->freq_dipole_anal = ival;
+            }
+            else if ( strcmp(tmp[0], "diffusion_coef") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->diffusion_coef = ival;
+            }
+            else if ( strcmp(tmp[0], "freq_diffusion_coef") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->freq_diffusion_coef = ival;
+            }
+            else if ( strcmp(tmp[0], "restrict_type") == 0 )
+            {
+                ival = atoi(tmp[1]);
+                control->restrict_type = ival;
+            }
+            else
+            {
+                fprintf( stderr, "[ERROR] unknown control file parameter (%s)\n", tmp[0] );
+                MPI_Abort( MPI_COMM_WORLD, INVALID_INPUT );
             }
-        }
-        else if ( strcmp(tmp[0], "pt_mass") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->Tau_PT[0] = control->Tau_PT[1] = control->Tau_PT[2] =
-                                     val * 1.e-3;  // convert pt_mass from fs to ps
-        }
-        else if ( strcmp(tmp[0], "compress") == 0 )
-        {
-            val = atof(tmp[1]);
-            control->compressibility = val;
-        }
-        else if ( strcmp(tmp[0], "press_mode") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->press_mode = ival;
-        }
-        else if ( strcmp(tmp[0], "geo_format") == 0 )
-        {
-            ival = atoi( tmp[1] );
-            control->geo_format = ival;
-        }
-        else if ( strcmp(tmp[0], "write_freq") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->write_steps = ival;
-        }
-        else if ( strcmp(tmp[0], "traj_compress") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->traj_compress = ival;
-        }
-        else if ( strcmp(tmp[0], "traj_method") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->traj_method = ival;
-        }
-        else if ( strcmp(tmp[0], "traj_title") == 0 )
-        {
-            strcpy( out_control->traj_title, tmp[1] );
-        }
-        else if ( strcmp(tmp[0], "atom_info") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->atom_info += ival * 4;
-        }
-        else if ( strcmp(tmp[0], "atom_velocities") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->atom_info += ival * 2;
-        }
-        else if ( strcmp(tmp[0], "atom_forces") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->atom_info += ival * 1;
-        }
-        else if ( strcmp(tmp[0], "bond_info") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->bond_info = ival;
-        }
-        else if ( strcmp(tmp[0], "angle_info") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            out_control->angle_info = ival;
-        }
-        else if ( strcmp(tmp[0], "molecular_analysis") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->molecular_analysis = ival;
-        }
-        else if ( strcmp(tmp[0], "ignore") == 0 )
-        {
-            control->num_ignored = atoi(tmp[1]);
-            for ( i = 0; i < control->num_ignored; ++i )
-                control->ignore[atoi(tmp[i + 2])] = 1;
-        }
-        else if ( strcmp(tmp[0], "dipole_anal") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->dipole_anal = ival;
-        }
-        else if ( strcmp(tmp[0], "freq_dipole_anal") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->freq_dipole_anal = ival;
-        }
-        else if ( strcmp(tmp[0], "diffusion_coef") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->diffusion_coef = ival;
-        }
-        else if ( strcmp(tmp[0], "freq_diffusion_coef") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->freq_diffusion_coef = ival;
-        }
-        else if ( strcmp(tmp[0], "restrict_type") == 0 )
-        {
-            ival = atoi(tmp[1]);
-            control->restrict_type = ival;
-        }
-        else
-        {
-            fprintf( stderr, "WARNING: unknown parameter %s\n", tmp[0] );
-            MPI_Abort( MPI_COMM_WORLD, 15 );
         }
     }
 
+    if ( ferror( fp ) )
+    {
+        fprintf( stderr, "[ERROR] parsing control file failed (I/O error). TERMINATING...\n" );
+        MPI_Abort( MPI_COMM_WORLD, INVALID_INPUT );
+    }
+
     /* determine target T */
     if ( control->T_mode == 0 )
+    {
         control->T = control->T_final;
-    else control->T = control->T_init;
+    }
+    else
+    {
+        control->T = control->T_init;
+    }
 
     /* free memory allocations at the top */
     for ( i = 0; i < MAX_TOKENS; i++ )
-        sfree( tmp[i], "tmp[i]" );
-    sfree( tmp, "tmp" );
-    sfree( s, "s" );
+    {
+        sfree( tmp[i], "Read_Control_File::tmp[i]" );
+    }
+    sfree( tmp, "Read_Control_File::tmp" );
+    sfree( s, "Read_Control_File::s" );
 
     // fprintf( stderr,"%d %d %10.5f %d %10.5f %10.5f\n",
     //   control->ensemble, control->nsteps, control->dt,
diff --git a/PuReMD/src/forces.c b/PuReMD/src/forces.c
index d438a0eb..c406417b 100644
--- a/PuReMD/src/forces.c
+++ b/PuReMD/src/forces.c
@@ -926,7 +926,7 @@ void Compute_Forces( reax_system *system, control_params *control,
     comm = mpi_data->world;
     /********* init forces ************/
 #if defined(PURE_REAX)
-    if ( control->qeq_freq && (data->step - data->prev_steps) % control->qeq_freq == 0 )
+    if ( control->charge_freq && (data->step - data->prev_steps) % control->charge_freq == 0 )
         qeq_flag = 1;
     else qeq_flag = 0;
 #elif defined(LAMMPS_REAX)
@@ -970,7 +970,7 @@ void Compute_Forces( reax_system *system, control_params *control,
 #if defined(LOG_PERFORMANCE)
     //MPI_Barrier( mpi_data->world );
     if ( system->my_rank == MASTER_NODE )
-        Update_Timing_Info( &t_start, &(data->timing.qEq) );
+        Update_Timing_Info( &t_start, &data->timing.cm );
 #endif
 #if defined(DEBUG_FOCUS)
     fprintf(stderr, "p%d @ step%d: qeq completed\n", system->my_rank, data->step);
diff --git a/PuReMD/src/io_tools.c b/PuReMD/src/io_tools.c
index 560bb5a1..7f3c4c02 100644
--- a/PuReMD/src/io_tools.c
+++ b/PuReMD/src/io_tools.c
@@ -1274,8 +1274,8 @@ void Output_Results( reax_system *system, control_params *control,
                      data->timing.init_forces * denom,
                      data->timing.bonded * denom,
                      data->timing.nonb * denom,
-                     data->timing.qEq * denom,
-                     (int)((data->timing.s_matvecs + data->timing.t_matvecs)*denom) );
+                     data->timing.cm * denom,
+                     (int)(data->timing.cm_solver_iters * denom) );
 
             Reset_Timing( &(data->timing) );
             fflush( out_control->log );
diff --git a/PuReMD/src/qEq.c b/PuReMD/src/qEq.c
index c8a348c7..15cc0249 100644
--- a/PuReMD/src/qEq.c
+++ b/PuReMD/src/qEq.c
@@ -382,18 +382,18 @@ void QEq( reax_system *system, control_params *control, simulation_data *data,
 #endif
 
     //s_matvecs = dual_CG(system, workspace, workspace->H, workspace->b,
-    //          control->q_err, workspace->x, mpi_data, out_control->log);
+    //          control->cm_solver_q_err, workspace->x, mpi_data, out_control->log);
     //t_matvecs = 0;
 
     for ( j = 0; j < system->n; ++j )
         workspace->s[j] = workspace->x[j][0];
     s_matvecs = CG(system, workspace, workspace->H, workspace->b_s,//newQEq sCG
-                   control->q_err, workspace->s, mpi_data, out_control->log );
+                   control->cm_solver_q_err, workspace->s, mpi_data, out_control->log );
     for ( j = 0; j < system->n; ++j )
         workspace->x[j][0] = workspace->s[j];
 
     //s_matvecs = PCG( system, workspace, workspace->H, workspace->b_s,
-    //   control->q_err, workspace->L, workspace->U, workspace->s,
+    //   control->cm_solver_q_err, workspace->L, workspace->U, workspace->s,
     //   mpi_data, out_control->log );
 #if defined(DEBUG)
     fprintf( stderr, "p%d: first CG completed\n", system->my_rank );
@@ -402,12 +402,12 @@ void QEq( reax_system *system, control_params *control, simulation_data *data,
     for ( j = 0; j < system->n; ++j )
         workspace->t[j] = workspace->x[j][1];
     t_matvecs = CG(system, workspace, workspace->H, workspace->b_t,//newQEq sCG
-                   control->q_err, workspace->t, mpi_data, out_control->log );
+                   control->cm_solver_q_err, workspace->t, mpi_data, out_control->log );
     for ( j = 0; j < system->n; ++j )
         workspace->x[j][1] = workspace->t[j];
 
     //t_matvecs = PCG( system, workspace, workspace->H, workspace->b_t,
-    //   control->q_err, workspace->L, workspace->U, workspace->t,
+    //   control->cm_solver_q_err, workspace->L, workspace->U, workspace->t,
     //   mpi_data, out_control->log );
 #if defined(DEBUG)
     fprintf( stderr, "p%d: second CG completed\n", system->my_rank );
@@ -422,8 +422,7 @@ void QEq( reax_system *system, control_params *control, simulation_data *data,
 #if defined(LOG_PERFORMANCE)
     if ( system->my_rank == MASTER_NODE )
     {
-        data->timing.s_matvecs += s_matvecs;
-        data->timing.t_matvecs += t_matvecs;
+        data->timing.cm_solver_iters += s_matvecs + t_matvecs;
     }
 #endif
 }
diff --git a/PuReMD/src/reax_types.h b/PuReMD/src/reax_types.h
index 152c0c54..dfaa9c37 100644
--- a/PuReMD/src/reax_types.h
+++ b/PuReMD/src/reax_types.h
@@ -22,6 +22,11 @@
 #ifndef __REAX_TYPES_H_
 #define __REAX_TYPES_H_
 
+#if (defined(HAVE_CONFIG_H) && !defined(__CONFIG_H_))
+  #define __CONFIG_H_
+  #include "config.h"
+#endif
+
 #include <ctype.h>
 #include <math.h>
 #include <mpi.h>
@@ -36,7 +41,6 @@
 
 #define PURE_REAX
 //#define LAMMPS_REAX
-
 //#define DEBUG
 //#define DEBUG_FOCUS
 //#define TEST_ENERGY
@@ -47,12 +51,13 @@
 //#define OLD_BOUNDARIES
 //#define MIDPOINT_BOUNDARIES
 
-#define REAX_MAX_STR            1024
-#define REAX_MAX_NBRS           6
-#define REAX_MAX_3BODY_PARAM    5
-#define REAX_MAX_4BODY_PARAM    5
-#define REAX_MAX_ATOM_TYPES     25
-#define REAX_MAX_MOLECULE_SIZE  20
+#define ZERO                    (0.000000000000000e+00)
+#define REAX_MAX_STR            (1024)
+#define REAX_MAX_NBRS           (6)
+#define REAX_MAX_3BODY_PARAM    (5)
+#define REAX_MAX_4BODY_PARAM    (5)
+#define REAX_MAX_ATOM_TYPES     (25)
+#define REAX_MAX_MOLECULE_SIZE  (20)
 
 /* NaN IEEE 754 representation for C99 in math.h
  * Note: function choice must match REAL typedef below */
@@ -63,6 +68,68 @@
 #define NAN_REAL(a) (0)
 #endif
 
+
+/* method for computing atomic charges */
+enum charge_method
+{
+    QEQ_CM = 0,
+    EE_CM = 1,
+    ACKS2_CM = 2,
+};
+
+/* linear solver type used in charge method */
+enum solver
+{
+    GMRES_S = 0,
+    GMRES_H_S = 1,
+    CG_S = 2,
+    SDM_S = 3,
+    BiCGStab_S = 4,
+};
+
+/* preconditioner computation type for charge method linear solver */
+enum pre_comp
+{
+    NONE_PC = 0,
+    JACOBI_PC = 1,
+    ICHOLT_PC = 2,
+    ILUT__PC = 3,
+    ILUTP_PC = 4,
+    FG_ILUT_PC = 5,
+    SAI_PC = 6,
+};
+
+/* preconditioner application type for ICHOL/ILU preconditioners,
+ * used for charge method linear solver */
+enum pre_app
+{
+    TRI_SOLVE_PA = 0,
+    TRI_SOLVE_LEVEL_SCHED_PA = 1,
+    TRI_SOLVE_GC_PA = 2,
+    JACOBI_ITER_PA = 3,
+};
+
+/* interaction list (reax_list) storage format */
+enum reax_list_format
+{
+    /* store half of interactions, when i < j (atoms i and j) */
+    HALF_LIST = 0,
+    /* store all interactions */
+    FULL_LIST = 1,
+};
+
+/* sparse matrix (sparse_matrix) storage format */
+enum sparse_matrix_format
+{
+    /* store upper half of nonzeros in a symmetric matrix (a_{ij}, i >= j) */
+    SYM_HALF_MATRIX = 0,
+    /* store all nonzeros in a symmetric matrix */
+    SYM_FULL_MATRIX = 1,
+    /* store all nonzeros in a matrix */
+    FULL_MATRIX = 2,
+};
+
+
 /********************** TYPE DEFINITIONS ********************/
 typedef int  ivec[3];
 typedef double real;
@@ -148,15 +215,8 @@ typedef struct
     MPI_Datatype bond_view;
     MPI_Datatype angle_line;
     MPI_Datatype angle_view;
-
-    //MPI_Request  send_req1[REAX_MAX_NBRS];
-    //MPI_Request  send_req2[REAX_MAX_NBRS];
-    //MPI_Status   send_stat1[REAX_MAX_NBRS];
-    //MPI_Status   send_stat2[REAX_MAX_NBRS];
-    //MPI_Status   recv_stat1[REAX_MAX_NBRS];
-    //MPI_Status   recv_stat2[REAX_MAX_NBRS];
-
     mpi_out_data out_buffers[REAX_MAX_NBRS];
+
     void *in1_buffer;
     void *in2_buffer;
 } mpi_datatypes;
@@ -493,64 +553,161 @@ typedef struct
 /* system control parameters */
 typedef struct
 {
+    /* simulation name, as supplied via control file */
     char sim_name[REAX_MAX_STR];
-    int  nprocs;
+    /* number of MPI processors, as supplied via control file */
+    int nprocs;
+    /* MPI processors per each simulation dimension (cartesian topology),
+     * as supplied via control file */
     ivec procs_by_dim;
-    /* ensemble values:
-       0 : NVE
-       1 : bNVT (Berendsen)
-       2 : nhNVT (Nose-Hoover)
-       3 : sNPT (Parrinello-Rehman-Nose-Hoover) semiisotropic
-       4 : iNPT (Parrinello-Rehman-Nose-Hoover) isotropic
-       5 : NPT  (Parrinello-Rehman-Nose-Hoover) Anisotropic*/
-    int  ensemble;
-    int  nsteps;
+    /* ensemble type for simulation, values:
+     * 0 : NVE
+     * 1 : bNVT (Berendsen)
+     * 2 : nhNVT (Nose-Hoover)
+     * 3 : sNPT (Parrinello-Rehman-Nose-Hoover) semiisotropic
+     * 4 : iNPT (Parrinello-Rehman-Nose-Hoover) isotropic
+     * 5 : NPT  (Parrinello-Rehman-Nose-Hoover) Anisotropic */
+    int ensemble;
+    /* num. of simulation time steps */
+    int nsteps;
+    /* length of time step, in femtoseconds */
     real dt;
-    int  geo_format;
-    int  restart;
-
-    int  restrict_bonds;
-    int  remove_CoM_vel;
-    int  random_vel;
-    int  reposition_atoms;
-
-    int  reneighbor;
+    /* format of geometry input file */
+    int geo_format;
+    /* format of restart file */
+    int restart;
+
+    /**/
+    int restrict_bonds;
+    /* flag to control if center of mass velocity is removed */
+    int remove_CoM_vel;
+    /* flag to control if atomic initial velocity is randomly assigned */
+    int random_vel;
+    /* flag to control how atom repositioning is performed, values:
+     * 0: fit to periodic box
+     * 1: put center of mass to box center
+     * 2: put center of mass to box origin  */
+    int reposition_atoms;
+
+    /* flag to control the frequency (in terms of simulation time stesp)
+     * at which atom reneighboring is performed */
+    int reneighbor;
+    /* far neighbor (Verlet list) interaction cutoff, in Angstroms */
     real vlist_cut;
+    /* bond interaction cutoff, in Angstroms */
     real bond_cut;
-    real nonb_cut, nonb_low;
+    /* non-bonded interaction cutoff, in Angstroms */
+    real nonb_cut;
+    /* ???, as supplied by force field parameters, in Angstroms */
+    real nonb_low;
+    /* hydrogen bond interaction cutoff, in Angstroms */
     real hbond_cut;
+    /* ghost region cutoff (user-supplied via control file), in Angstroms */
     real user_ghost_cut;
 
+    /* bond graph cutoff, as supplied by control file, in Angstroms */
     real bg_cut;
+    /* bond order cutoff, as supplied by force field parameters, in Angstroms */
     real bo_cut;
+    /* three body interaction cutoff, as supplied by control file, in Angstroms */
     real thb_cut;
 
+    /* flag to control if force computations are tablulated */
     int tabulate;
 
-    int qeq_freq;
-    real q_err;
-    int refactor;
-    real droptol;
-
-    real T_init, T_final, T;
+    /* method for computing atomic charges */
+    unsigned int charge_method;
+    /* frequency (in terms of simulation time steps) at which to
+     * re-compute atomic charge distribution */
+    int charge_freq;
+    /* iterative linear solver type */
+    unsigned int cm_solver_type;
+    /* system net charge */
+    real cm_q_net;
+    /* max. iterations for linear solver */
+    unsigned int cm_solver_max_iters;
+    /* max. iterations before restarting in specific solvers, e.g., GMRES(k) */
+    unsigned int cm_solver_restart;
+    /* error tolerance of solution produced by charge distribution
+     * sparse iterative linear solver */
+    real cm_solver_q_err;
+    /* ratio used in computing sparser charge matrix,
+     * between 0.0 and 1.0 */
+    real cm_domain_sparsity;
+    /* TRUE if enabled, FALSE otherwise */
+    unsigned int cm_domain_sparsify_enabled;
+    /* order of spline extrapolation used for computing initial guess
+     * to linear solver */
+    unsigned int cm_init_guess_extrap1;
+    /* order of spline extrapolation used for computing initial guess
+     * to linear solver */
+    unsigned int cm_init_guess_extrap2;
+    /* preconditioner type for linear solver */
+    unsigned int cm_solver_pre_comp_type;
+    /* frequency (in terms of simulation time steps) at which to recompute
+     * incomplete factorizations */
+    unsigned int cm_solver_pre_comp_refactor;
+    /* drop tolerance of incomplete factorization schemes (ILUT, ICHOLT, etc.)
+     * used for preconditioning the iterative linear solver used in charge distribution */
+    real cm_solver_pre_comp_droptol;
+    /* num. of sweeps for computing preconditioner factors
+     * in fine-grained iterative methods (FG-ICHOL, FG-ILU) */
+    unsigned int cm_solver_pre_comp_sweeps;
+    /* relative num. of non-zeros to charge matrix used to
+     * compute the sparse approximate inverse preconditioner,
+     * between 0.0 and 1.0 */
+    real cm_solver_pre_comp_sai_thres;
+    /* preconditioner application type */
+    unsigned int cm_solver_pre_app_type;
+    /* num. of iterations used to apply preconditioner via
+     * Jacobi relaxation scheme (truncated Neumann series) */
+    unsigned int cm_solver_pre_app_jacobi_iters;
+
+    /* initial temperature of simulation, in Kelvin */
+    real T_init;
+    /* final temperature of simulation, in Kelvin */
+    real T_final;
+    /* current temperature of simulation, in Kelvin */
+    real T;
+    /**/
     real Tau_T;
+    /**/
     int  T_mode;
-    real T_rate, T_freq;
+    /**/
+    real T_rate;
+    /**/
+    real T_freq;
 
+    /**/
     int  virial;
-    rvec P, Tau_P, Tau_PT;
-    int  press_mode;
+    /**/
+    rvec P;
+    /**/
+    rvec Tau_P;
+    /**/
+    rvec Tau_PT;
+    /**/
+    int press_mode;
+    /**/
     real compressibility;
 
-    int  molecular_analysis;
-    int  num_ignored;
+    /**/
+    int molecular_analysis;
+    /**/
+    int num_ignored;
+    /**/
     int  ignore[REAX_MAX_ATOM_TYPES];
 
-    int  dipole_anal;
-    int  freq_dipole_anal;
-    int  diffusion_coef;
-    int  freq_diffusion_coef;
-    int  restrict_type;
+    /**/
+    int dipole_anal;
+    /**/
+    int freq_dipole_anal;
+    /**/
+    int diffusion_coef;
+    /**/
+    int freq_diffusion_coef;
+    /**/
+    int restrict_type;
 } control_params;
 
 
@@ -596,19 +753,46 @@ typedef struct
 
 typedef struct
 {
+    /* start time of event */
     real start;
+    /* end time of event */
     real end;
+    /* total elapsed time of event */
     real elapsed;
-
+    /* total simulation time */
     real total;
+    /* communication time */
     real comm;
+    /* neighbor list generation time */
     real nbrs;
+    /* force initialization time */
     real init_forces;
+    /* bonded force calculation time */
     real bonded;
+    /* non-bonded force calculation time */
     real nonb;
-    real qEq;
-    int  s_matvecs;
-    int  t_matvecs;
+    /* atomic charge distribution calculation time */
+    real cm;
+    /**/
+    real cm_sort_mat_rows;
+    /**/
+    real cm_solver_comm;
+    /**/
+    real cm_solver_allreduce;
+    /**/
+    real cm_solver_pre_comp;
+    /**/
+    real cm_solver_pre_app; // update CG()
+    /* num. of steps in iterative linear solver for charge distribution */
+    int cm_solver_iters;
+    /**/
+    real cm_solver_spmv; // update CG()
+    /**/
+    real cm_solver_vector_ops; // update CG()
+    /**/
+    real cm_solver_orthog;
+    /**/
+    real cm_solver_tri_solve;
 } reax_timing;
 
 
@@ -763,6 +947,8 @@ typedef struct
 
 typedef struct
 {
+    /* matrix storage format */
+    int format;
     int cap, n, m;
     int *start, *end;
     sparse_matrix_entry *entries;
@@ -894,6 +1080,9 @@ typedef struct
     int type;
 //    list_type select;
 
+    /* list storage format (half or full) */
+    int format;
+
     void *v;
     three_body_interaction_data *three_body_list;
     bond_data *bond_list;
diff --git a/PuReMD/src/reset_tools.c b/PuReMD/src/reset_tools.c
index eb7c6465..1acbc002 100644
--- a/PuReMD/src/reset_tools.c
+++ b/PuReMD/src/reset_tools.c
@@ -107,14 +107,13 @@ void Reset_Simulation_Data( simulation_data* data, int virial )
 void Reset_Timing( reax_timing *rt )
 {
     rt->total = Get_Time();
-    rt->comm = 0;
-    rt->nbrs = 0;
-    rt->init_forces = 0;
-    rt->bonded = 0;
-    rt->nonb = 0;
-    rt->qEq = 0;
-    rt->s_matvecs = 0;
-    rt->t_matvecs = 0;
+    rt->comm = 0.0;
+    rt->nbrs = 0.0;
+    rt->init_forces = 0.0;
+    rt->bonded = 0.0;
+    rt->nonb = 0.0;
+    rt->cm = 0.0;
+    rt->cm_solver_iters = 0;
 }
 
 #ifdef TEST_FORCES
diff --git a/PuReMD/src/tool_box.c b/PuReMD/src/tool_box.c
index a0892870..d898f219 100644
--- a/PuReMD/src/tool_box.c
+++ b/PuReMD/src/tool_box.c
@@ -486,3 +486,65 @@ void sfree( void *ptr, char *name )
     free( ptr );
     ptr = NULL;
 }
+
+
+/* Safe wrapper around libc fopen
+ *
+ * fname: name of file to be opened
+ * mode: mode in which to open file
+ * msg: message to be printed in case of error
+ * */
+FILE * sfopen( const char * fname, const char * mode, const char * msg )
+{
+    FILE * ptr;
+
+    if ( fname == NULL )
+    {
+        fprintf( stderr, "[ERROR] trying to open file: NULL file name (%s). Terminating...\n",
+                msg );
+        exit( INVALID_INPUT );
+    }
+    if ( mode == NULL )
+    {
+        fprintf( stderr, "[ERROR] trying to open file: NULL mode (%s). Terminating...\n",
+                msg );
+        exit( INVALID_INPUT );
+    }
+
+    ptr = fopen( fname, mode );
+
+    if ( ptr == NULL )
+    {
+        fprintf( stderr, "[ERROR] failed to open file %s with mode %s (%s)\n",
+              fname, mode, msg );
+        exit( INVALID_INPUT );
+    }
+
+    return ptr;
+}
+
+
+/* Safe wrapper around libc fclose
+ *
+ * fname: name of file to be opened
+ * mode: mode in which to open file
+ * msg: message to be printed in case of error
+ * */
+void sfclose( FILE * fp, const char * msg )
+{
+    int ret;
+
+    if ( fp == NULL )
+    {
+        fprintf( stderr, "[WARNING] trying to close NULL file pointer (%s). Returning...\n", msg );
+        return;
+    }
+
+    ret = fclose( fp );
+
+    if ( ret != 0 )
+    {
+        fprintf( stderr, "[ERROR] error detected when closing file (%s). Terminating...\n", msg );
+        exit( INVALID_INPUT );
+    }
+}
diff --git a/PuReMD/src/tool_box.h b/PuReMD/src/tool_box.h
index bf25c64f..22cbc195 100644
--- a/PuReMD/src/tool_box.h
+++ b/PuReMD/src/tool_box.h
@@ -66,4 +66,8 @@ void *smalloc( long, char*, MPI_Comm );
 void *scalloc( int, int, char*, MPI_Comm );
 void sfree( void*, char* );
 
+FILE * sfopen( const char *, const char *, const char * );
+
+void sfclose( FILE *, const char * );
+
 #endif
diff --git a/PuReMD/src/traj.c b/PuReMD/src/traj.c
index 40df8bbd..d03a8289 100644
--- a/PuReMD/src/traj.c
+++ b/PuReMD/src/traj.c
@@ -261,7 +261,7 @@ int Write_Header( reax_system *system, control_params *control,
                  control->thb_cut );
         strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN + 1 );
 
-        sprintf( out_control->line, SCI_LINE, "QEq_tolerance:", control->q_err );
+        sprintf( out_control->line, SCI_LINE, "QEq_tolerance:", control->cm_solver_q_err );
         strncat( out_control->buffer, out_control->line, HEADER_LINE_LEN + 1 );
 
         /* temperature controls */
-- 
GitLab