diff --git a/configure.ac b/configure.ac
index 18133ec5aaffafcb1a27c11db895f5535b9e8867..07bcc4539b094206dabc3c013589928615b330d4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,12 @@ AC_ARG_ENABLE([qmmm],
 			      [enable build for code in QM/MM mode @<:@default: no@:>@])],
 	      [qmmm=${enableval}], [qmmm=no])
 
+# Build code with Fortran interface in QM/MM mode.
+AC_ARG_ENABLE([qmmm_fortran],
+	      [AS_HELP_STRING([--enable-qmmm_fortran],
+			      [enable build for code in QM/MM mode @<:@default: no@:>@])],
+	      [qmmm_fortran=${enableval}], [qmmm_fortran=no])
+
 # Build LAMMPS/reaxc integration code.
 AC_ARG_ENABLE([lammps-reaxc],
 	      [AS_HELP_STRING([--enable-lammps-reaxc],
@@ -326,9 +332,13 @@ if test "x${pack_serial_enabled}" = "xyes" || test "x${pack_openmp_enabled}" = "
 	AC_SUBST([G_LIBS], ["${GSL_LIBS}"])
 
 	# Build code in QM/MM mode
-	AS_IF([test "x${qmmm}" = "xyes"],
+	AS_IF([test "x${qmmm}" = "xyes" || test "x${qmmm_fortran}" = "xyes"],
 	      [AC_DEFINE([QMMM], [1], [Define to 1 to build PuReMD code in QMMM mode.])])
 
+	# Build code with Fortran interface in QM/MM mode
+	AS_IF([test "x${qmmm_fortran}" = "xyes"],
+	      [AC_DEFINE([QMMM_FORTRAN], [1], [Define to 1 to build PuReMD code in QMMM mode.])])
+
 	AC_LANG_POP([C])
 fi
 AM_CONDITIONAL([BUILD_S_OMP], [test "x${pack_serial_enabled}" = "xyes" || test "x${pack_openmp_enabled}" = "xyes"])
diff --git a/sPuReMD/src/charges.c b/sPuReMD/src/charges.c
index 3d8b8021f864c457df31359abc99610043b2d078..73a87973706eb8c70a7ee20539b677c878a9125a 100644
--- a/sPuReMD/src/charges.c
+++ b/sPuReMD/src/charges.c
@@ -1391,12 +1391,8 @@ static void QEq( reax_system * const system, control_params * const control,
     }
 
 #if defined(QMMM)
-    for ( int i = 0; i < system->N; ++i )
-    {
-        workspace->s[0][i] = system->atoms[i].q_init;
-        workspace->t[0][i] = system->atoms[i].q_init;
-        workspace->mask_qmmm[i] = system->atoms[i].qmmm_mask;
-    }
+    fprintf( stderr, "[ERROR] QEq charge method is not supported in QM/MM mode. Use EEM instead. Terminating...\n" );
+    exit( INVALID_INPUT );
 #endif
 
     switch ( control->cm_solver_type )
@@ -1412,7 +1408,7 @@ static void QEq( reax_system * const system, control_params * const control,
         iters = GMRES_HouseHolder( workspace, control, data, &workspace->H,
                 workspace->b_s, control->cm_solver_q_err, workspace->s[0], refactor );
         iters += GMRES_HouseHolder( workspace, control, data, &workspace->H,
-                workspace->b_t, control->cm_solver_q_err, workspace->t[0], 0 );
+                workspace->b_t, control->cm_solver_q_err, workspace->t[0], FALSE );
         break;
 
     case CG_S:
@@ -1512,11 +1508,16 @@ static void EE( reax_system * const system, control_params * const control,
     }
 
 #if defined(QMMM)
-    for ( int i = 0; i < system->N; ++i )
+    for ( int i = 0; i < system->N_qm; ++i )
+    {
+        workspace->mask_qmmm[i] = system->atoms[i].qmmm_mask;
+    }
+    for ( int i = system->N_qm; i < system->N; ++i )
     {
         workspace->s[0][i] = system->atoms[i].q_init;
         workspace->mask_qmmm[i] = system->atoms[i].qmmm_mask;
     }
+    workspace->mask_qmmm[system->N_cm - 1] = 1;
 #endif
 
     switch ( control->cm_solver_type )
@@ -1631,11 +1632,22 @@ static void ACKS2( reax_system * const system, control_params * const control,
 #endif
 
 #if defined(QMMM)
-    for ( int i = 0; i < system->N; ++i )
+    /* TODO: further testing needed for QM/MM mode with ACKS2 */
+    for ( int i = 0; i < system->N_qm; ++i )
+    {
+        workspace->mask_qmmm[i] = system->atoms[i].qmmm_mask;
+    }
+    for ( int i = system->N_qm; i < system->N; ++i )
     {
         workspace->s[0][i] = system->atoms[i].q_init;
         workspace->mask_qmmm[i] = system->atoms[i].qmmm_mask;
     }
+    for ( int i = system->N; i < 2 * system->N; ++i )
+    {
+        workspace->mask_qmmm[i] = system->atoms[i - system->N].qmmm_mask;
+    }
+    workspace->mask_qmmm[2 * system->N_cm] = 1;
+    workspace->mask_qmmm[2 * system->N_cm + 1] = 1;
 #endif
 
     switch ( control->cm_solver_type )
diff --git a/sPuReMD/src/init_md.c b/sPuReMD/src/init_md.c
index e850ce3218f6aabfeae08569176ee68a3cd04432..16eb339829d948b619bc6163aae14d7f04d415dc 100644
--- a/sPuReMD/src/init_md.c
+++ b/sPuReMD/src/init_md.c
@@ -684,7 +684,7 @@ static void Init_Workspace( reax_system *system, control_params *control,
         }
 
 #if defined(QMMM)
-        workspace->mask_qmmm = smalloc( system->N_max * sizeof( int ),
+        workspace->mask_qmmm = smalloc( system->N_cm_max * sizeof( int ),
                "Init_Workspace::workspace->mask_qmmm" );
 #endif
 
diff --git a/sPuReMD/src/nonbonded.c b/sPuReMD/src/nonbonded.c
index 74383c8c033bf05811fdfe30698335ff0b03c43c..807226d532052aea191e3889115d4ea3e6ec9627 100644
--- a/sPuReMD/src/nonbonded.c
+++ b/sPuReMD/src/nonbonded.c
@@ -153,10 +153,6 @@ void vdW_Coulomb_Energy( reax_system *system, control_params *control,
                     nbr_pj = &far_nbrs->far_nbr_list[pj];
                     j = nbr_pj->nbr;
 
-#if defined(QMMM)
-                    if ( system->atoms[i].qmmm_mask == TRUE || system->atoms[j].qmmm_mask == TRUE )
-                    {
-#endif
                     r_ij = nbr_pj->d;
                     twbp = &system->reax_param.tbp[ system->atoms[i].type ]
                              [ system->atoms[j].type ];
@@ -243,9 +239,6 @@ void vdW_Coulomb_Energy( reax_system *system, control_params *control,
                     {
                         e_core = 0.0;
                         de_core = 0.0;
-                        e_vdW = 0.0;
-                        e_base = 0.0;
-                        de_base = 0.0;
                         CEvd = 0.0;
                     }
 #endif
@@ -256,11 +249,11 @@ void vdW_Coulomb_Energy( reax_system *system, control_params *control,
                             e_base, de_base, e_core, de_core ); fflush( stderr );
 #endif
 
+                    /* Coulomb Calculations */
 #if defined(QMMM)
-                    if ( system->atoms[i].qmmm_mask == TRUE && system->atoms[j].qmmm_mask == TRUE )
+                    if ( system->atoms[i].qmmm_mask == TRUE || system->atoms[j].qmmm_mask == TRUE )
                     {
 #endif
-                    /* Coulomb Calculations */
                     dr3gamij_1 = r_ij * r_ij * r_ij + POW( twbp->gamma, -3.0 );
                     dr3gamij_3 = POW( dr3gamij_1 , 1.0 / 3.0 );
                     e_clb = C_ELE * (system->atoms[i].q * system->atoms[j].q) / dr3gamij_3;
@@ -274,8 +267,6 @@ void vdW_Coulomb_Energy( reax_system *system, control_params *control,
                     }
                     else
                     {
-                        e_clb = 0.0;
-                        e_ele = 0.0;
                         de_clb = 0.0;
                         CEclmb = 0.0;
                     }
@@ -392,9 +383,6 @@ void vdW_Coulomb_Energy( reax_system *system, control_params *control,
                     rvec_ScaledAdd( workspace->f_vdw[j], +CEvd, nbr_pj->dvec );
                     rvec_ScaledAdd( workspace->f_ele[i], -CEclmb, nbr_pj->dvec );
                     rvec_ScaledAdd( workspace->f_ele[j], +CEclmb, nbr_pj->dvec );
-#endif
-#if defined(QMMM)
-                }
 #endif
                 }
             }
diff --git a/sPuReMD/src/spuremd.c b/sPuReMD/src/spuremd.c
index eb70ead6c641e94ef5f0e49f6d6d2640605ff563..dfc00cab8d5358d94c7ad12671934c41640a15ef 100644
--- a/sPuReMD/src/spuremd.c
+++ b/sPuReMD/src/spuremd.c
@@ -151,156 +151,6 @@ static void Read_Input_Files( const char * const geo_file,
 }
 
 
-#if defined(QMMM)
-/* Allocate top-level data structures and parse input files
- * for the first simulation
- *
- * qm_num_atoms: num. atoms in the QM region
- * qm_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_info: 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_info, 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 )
-    {
-        spmd_handle->lists[i] = smalloc( sizeof(reax_list),
-                "Setup::spmd_handle->lists[i]" );
-        spmd_handle->lists[i]->allocated = FALSE;
-    }
-    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 = qm_num_atoms;
-    spmd_handle->system->N_mm = mm_num_atoms;
-    spmd_handle->system->N = spmd_handle->system->N_qm + spmd_handle->system->N_mm;
-
-    PreAllocate_Space( spmd_handle->system, spmd_handle->control,
-            spmd_handle->workspace, spmd_handle->system->N );
-
-    Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2],
-            sim_box_info[3], sim_box_info[4], sim_box_info[5],
-            &spmd_handle->system->box );
-
-    for ( i = 0; i < spmd_handle->system->N_qm; ++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;
-        spmd_handle->system->atoms[i].q_init = 0.0;
-
-        spmd_handle->system->atoms[i].qmmm_mask = TRUE;
-    }
-
-    for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
-    {
-        x[0] = mm_pos_x[i - spmd_handle->system->N_qm];
-        x[1] = mm_pos_y[i - spmd_handle->system->N_qm];
-        x[2] = mm_pos_z[i - spmd_handle->system->N_qm];
-
-        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 - spmd_handle->system->N_qm];
-//        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 - spmd_handle->system->N_qm];
-        spmd_handle->system->atoms[i].q_init = mm_q[i - spmd_handle->system->N_qm];
-
-        spmd_handle->system->atoms[i].qmmm_mask = FALSE;
-    }
-
-    Read_Input_Files( NULL, ffield_file, control_file,
-            spmd_handle->system, spmd_handle->control,
-            spmd_handle->data, spmd_handle->workspace,
-            spmd_handle->out_control );
-
-    spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N );
-
-    return (void *) spmd_handle;
-}
-#endif
-
-
 /* Allocate top-level data structures and parse input files
  * for the first simulation
  *
@@ -588,42 +438,20 @@ int cleanup( const void * const handle )
 }
 
 
-#if defined(QMMM)
 /* 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_info: simulation box information, where the entries are
- *  - box length per dimension (3 entries)
- *  - angles per dimension (3 entries)
+ * 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_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_info,
+int reset( const void * const handle, const char * const geo_file,
         const char * const ffield_file, const char * const control_file )
 {
-    int i, ret;
-    rvec x;
+    int ret;
     spuremd_handle *spmd_handle;
 
     ret = SPUREMD_FAILURE;
@@ -642,64 +470,7 @@ int reset_qmmm_( const void * const handle,
         spmd_handle->realloc = FALSE;
         spmd_handle->data->sim_id++;
 
-        spmd_handle->system->N_qm = qm_num_atoms;
-        spmd_handle->system->N_mm = mm_num_atoms;
-        spmd_handle->system->N = spmd_handle->system->N_qm + spmd_handle->system->N_mm;
-
-        PreAllocate_Space( spmd_handle->system, spmd_handle->control,
-                spmd_handle->workspace, spmd_handle->system->N );
-
-        Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2],
-                sim_box_info[3], sim_box_info[4], sim_box_info[5],
-                &spmd_handle->system->box );
-
-        for ( i = 0; i < spmd_handle->system->N_qm; ++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;
-
-            spmd_handle->system->atoms[i].qmmm_mask = TRUE;
-        }
-
-        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
-        {
-            x[0] = mm_pos_x[i - spmd_handle->system->N_qm];
-            x[1] = mm_pos_y[i - spmd_handle->system->N_qm];
-            x[2] = mm_pos_z[i - spmd_handle->system->N_qm];
-
-            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 - spmd_handle->system->N_qm];
-//            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 - spmd_handle->system->N_qm];
-
-            spmd_handle->system->atoms[i].qmmm_mask = FALSE;
-        }
-
-        Read_Input_Files( NULL, ffield_file, control_file,
+        Read_Input_Files( geo_file, ffield_file, control_file,
                 spmd_handle->system, spmd_handle->control,
                 spmd_handle->data, spmd_handle->workspace,
                 spmd_handle->out_control );
@@ -722,23 +493,21 @@ int reset_qmmm_( const void * const handle,
 
     return ret;
 }
-#endif
 
 
-/* Reset for the next simulation by parsing input files and triggering
- * reallocation if more space is needed
+/* Getter for atom positions
  *
  * handle: pointer to wrapper struct with top-level data structures
- * geo_file: file containing geometry info of the structure to simulate
- * ffield_file: file containing force field parameters
- * control_file: file containing simulation parameters
+ * 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 reset( const void * const handle, const char * const geo_file,
-        const char * const ffield_file, const char * const control_file )
+int get_atom_positions( const void * const handle, double * const pos_x,
+        double * const pos_y, double * const pos_z )
 {
-    int ret;
+    int i, ret;
     spuremd_handle *spmd_handle;
 
     ret = SPUREMD_FAILURE;
@@ -747,240 +516,7 @@ int reset( const void * const handle, const char * const geo_file,
     {
         spmd_handle = (spuremd_handle*) handle;
 
-        /* close files used in previous simulation */
-        if ( spmd_handle->output_enabled == TRUE )
-        {
-            Finalize_Out_Controls( spmd_handle->system, spmd_handle->control,
-                    spmd_handle->workspace, spmd_handle->out_control );
-        }
-
-        spmd_handle->realloc = FALSE;
-        spmd_handle->data->sim_id++;
-
-        Read_Input_Files( geo_file, ffield_file, control_file,
-                spmd_handle->system, spmd_handle->control,
-                spmd_handle->data, spmd_handle->workspace,
-                spmd_handle->out_control );
-
-        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;
-}
-
-
-#if defined(QMMM)
-/* Getter for atom positions in QMMM mode
- *
- * handle: pointer to wrapper struct with top-level data structures
- * qm_pos_x: x-coordinate of QM atom positions, in Angstroms (allocated by caller)
- * qm_pos_y: y-coordinate of QM atom positions, in Angstroms (allocated by caller)
- * qm_pos_z: z-coordinate of QM atom positions, in Angstroms (allocated by caller)
- * mm_pos_x: x-coordinate of MM atom positions, in Angstroms (allocated by caller)
- * mm_pos_y: y-coordinate of MM atom positions, in Angstroms (allocated by caller)
- * mm_pos_z: z-coordinate of MM atom positions, in Angstroms (allocated by caller)
- *
- * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
- */
-int get_atom_positions_qmmm_( const void * const handle, double * const qm_pos_x,
-        double * const qm_pos_y, double * const qm_pos_z, double * const mm_pos_x,
-        double * const mm_pos_y, double * const mm_pos_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_qm; ++i )
-        {
-            qm_pos_x[i] = spmd_handle->system->atoms[i].x[0];
-            qm_pos_y[i] = spmd_handle->system->atoms[i].x[1];
-            qm_pos_z[i] = spmd_handle->system->atoms[i].x[2];
-        }
-
-        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
-        {
-            mm_pos_x[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].x[0];
-            mm_pos_y[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].x[1];
-            mm_pos_z[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].x[2];
-        }
-
-        ret = SPUREMD_SUCCESS;
-    }
-
-    return ret;
-}
-
-
-/* Getter for atom velocities in QMMM mode
- *
- * handle: pointer to wrapper struct with top-level data structures
- * qm_vel_x: x-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
- * qm_vel_y: y-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
- * qm_vel_z: z-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
- * mm_vel_x: x-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
- * mm_vel_y: y-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
- * mm_vel_z: z-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
- *
- * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
- */
-int get_atom_velocities_qmmm_( const void * const handle, double * const qm_vel_x,
-        double * const qm_vel_y, double * const qm_vel_z, double * const mm_vel_x,
-        double * const mm_vel_y, double * const mm_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_qm; ++i )
-        {
-            qm_vel_x[i] = spmd_handle->system->atoms[i].v[0];
-            qm_vel_y[i] = spmd_handle->system->atoms[i].v[1];
-            qm_vel_z[i] = spmd_handle->system->atoms[i].v[2];
-        }
-
-        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
-        {
-            mm_vel_x[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].v[0];
-            mm_vel_y[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].v[1];
-            mm_vel_z[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].v[2];
-        }
-
-        ret = SPUREMD_SUCCESS;
-    }
-
-    return ret;
-}
-
-
-/* Getter for atom forces in QMMM mode
- *
- * handle: pointer to wrapper struct with top-level data structures
- * qm_f_x: x-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
- * qm_f_y: y-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
- * qm_f_z: z-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
- * mm_f_x: x-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
- * mm_f_y: y-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
- * mm_f_z: z-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
- *
- * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
- */
-int get_atom_forces_qmmm_( const void * const handle, double * const qm_f_x,
-        double * const qm_f_y, double * const qm_f_z, double * const mm_f_x,
-        double * const mm_f_y, double * const mm_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_qm; ++i )
-        {
-            qm_f_x[i] = spmd_handle->system->atoms[i].f[0];
-            qm_f_y[i] = spmd_handle->system->atoms[i].f[1];
-            qm_f_z[i] = spmd_handle->system->atoms[i].f[2];
-        }
-
-        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
-        {
-            mm_f_x[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].f[0];
-            mm_f_y[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].f[1];
-            mm_f_z[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].f[2];
-        }
-
-        ret = SPUREMD_SUCCESS;
-    }
-
-    return ret;
-}
-
-
-/* Getter for atom charges in QMMM mode
- *
- * handle: pointer to wrapper struct with top-level data structures
- * qm_q: QM atom charges, in Coulombs (allocated by caller)
- * mm_q: MM atom charges, in Coulombs (allocated by caller)
- *
- * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
- */
-int get_atom_charges_qmmm_( const void * const handle, double * const qm_q,
-        double * const mm_q )
-{
-    int i, ret;
-    spuremd_handle *spmd_handle;
-
-    ret = SPUREMD_FAILURE;
-
-    if ( handle != NULL )
-    {
-        spmd_handle = (spuremd_handle*) handle;
-
-        for ( i = 0; i < spmd_handle->system->N_qm; ++i )
-        {
-            qm_q[i] = spmd_handle->system->atoms[i].q;
-        }
-
-        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
-        {
-            mm_q[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].q;
-        }
-
-        ret = SPUREMD_SUCCESS;
-    }
-
-    return ret;
-}
-#endif
-
-
-/* Getter for atom positions
- *
- * handle: pointer to wrapper struct with top-level data structures
- * 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 )
-{
-    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 )
+        for ( i = 0; i < spmd_handle->system->N; ++i )
         {
             pos_x[i] = spmd_handle->system->atoms[i].x[0];
             pos_y[i] = spmd_handle->system->atoms[i].x[1];
@@ -1188,3 +724,751 @@ int set_control_parameter( const void * const handle, const char * const keyword
 
     return ret;
 }
+
+
+#if defined(QMMM)
+/* Allocate top-level data structures and parse input files
+ * for the first simulation
+ *
+ * qm_num_atoms: num. atoms in the QM region
+ * qm_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_info: 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_info, 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 )
+    {
+        spmd_handle->lists[i] = smalloc( sizeof(reax_list),
+                "Setup::spmd_handle->lists[i]" );
+        spmd_handle->lists[i]->allocated = FALSE;
+    }
+    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 = qm_num_atoms;
+    spmd_handle->system->N_mm = mm_num_atoms;
+    spmd_handle->system->N = spmd_handle->system->N_qm + spmd_handle->system->N_mm;
+
+    PreAllocate_Space( spmd_handle->system, spmd_handle->control,
+            spmd_handle->workspace, spmd_handle->system->N );
+
+    Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2],
+            sim_box_info[3], sim_box_info[4], sim_box_info[5],
+            &spmd_handle->system->box );
+
+    for ( i = 0; i < spmd_handle->system->N_qm; ++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;
+        spmd_handle->system->atoms[i].q_init = 0.0;
+
+        spmd_handle->system->atoms[i].qmmm_mask = TRUE;
+    }
+
+    for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
+    {
+        x[0] = mm_pos_x[i - spmd_handle->system->N_qm];
+        x[1] = mm_pos_y[i - spmd_handle->system->N_qm];
+        x[2] = mm_pos_z[i - spmd_handle->system->N_qm];
+
+        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 - spmd_handle->system->N_qm];
+//        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 - spmd_handle->system->N_qm];
+        spmd_handle->system->atoms[i].q_init = mm_q[i - spmd_handle->system->N_qm];
+
+        spmd_handle->system->atoms[i].qmmm_mask = FALSE;
+    }
+
+    Read_Input_Files( NULL, ffield_file, control_file,
+            spmd_handle->system, spmd_handle->control,
+            spmd_handle->data, spmd_handle->workspace,
+            spmd_handle->out_control );
+
+    spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N );
+
+    return (void *) spmd_handle;
+}
+
+
+/* Reset for the next simulation by parsing input files and triggering
+ * reallocation if more space is needed
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_num_atoms: num. atoms in the QM region
+ * qm_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_info: 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_info,
+        const char * const ffield_file, const char * const control_file )
+{
+    int i, ret;
+    rvec x;
+    spuremd_handle *spmd_handle;
+
+    ret = SPUREMD_FAILURE;
+
+    if ( handle != NULL )
+    {
+        spmd_handle = (spuremd_handle*) handle;
+
+        /* close files used in previous simulation */
+        if ( spmd_handle->output_enabled == TRUE )
+        {
+            Finalize_Out_Controls( spmd_handle->system, spmd_handle->control,
+                    spmd_handle->workspace, spmd_handle->out_control );
+        }
+
+        spmd_handle->realloc = FALSE;
+        spmd_handle->data->sim_id++;
+
+        spmd_handle->system->N_qm = qm_num_atoms;
+        spmd_handle->system->N_mm = mm_num_atoms;
+        spmd_handle->system->N = spmd_handle->system->N_qm + spmd_handle->system->N_mm;
+
+        PreAllocate_Space( spmd_handle->system, spmd_handle->control,
+                spmd_handle->workspace, spmd_handle->system->N );
+
+        Setup_Box( sim_box_info[0], sim_box_info[1], sim_box_info[2],
+                sim_box_info[3], sim_box_info[4], sim_box_info[5],
+                &spmd_handle->system->box );
+
+        for ( i = 0; i < spmd_handle->system->N_qm; ++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;
+
+            spmd_handle->system->atoms[i].qmmm_mask = TRUE;
+        }
+
+        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
+        {
+            x[0] = mm_pos_x[i - spmd_handle->system->N_qm];
+            x[1] = mm_pos_y[i - spmd_handle->system->N_qm];
+            x[2] = mm_pos_z[i - spmd_handle->system->N_qm];
+
+            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 - spmd_handle->system->N_qm];
+//            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 - spmd_handle->system->N_qm];
+
+            spmd_handle->system->atoms[i].qmmm_mask = FALSE;
+        }
+
+        Read_Input_Files( NULL, ffield_file, control_file,
+                spmd_handle->system, spmd_handle->control,
+                spmd_handle->data, spmd_handle->workspace,
+                spmd_handle->out_control );
+
+        if ( spmd_handle->system->N > spmd_handle->system->N_max )
+        {
+            /* deallocate everything which needs more space
+             * (i.e., structures whose space is a function of the number of atoms),
+             * except for data structures allocated while parsing input files */
+            Finalize( spmd_handle->system, spmd_handle->control, spmd_handle->data,
+                    spmd_handle->workspace, spmd_handle->lists, spmd_handle->out_control,
+                    spmd_handle->output_enabled, TRUE );
+
+            spmd_handle->system->N_max = (int) CEIL( SAFE_ZONE * spmd_handle->system->N );
+            spmd_handle->realloc = TRUE;
+        }
+
+        ret = SPUREMD_SUCCESS;
+    }
+
+    return ret;
+}
+
+
+/* Getter for atom positions in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_pos_x: x-coordinate of QM atom positions, in Angstroms (allocated by caller)
+ * qm_pos_y: y-coordinate of QM atom positions, in Angstroms (allocated by caller)
+ * qm_pos_z: z-coordinate of QM atom positions, in Angstroms (allocated by caller)
+ * mm_pos_x: x-coordinate of MM atom positions, in Angstroms (allocated by caller)
+ * mm_pos_y: y-coordinate of MM atom positions, in Angstroms (allocated by caller)
+ * mm_pos_z: z-coordinate of MM atom positions, in Angstroms (allocated by caller)
+ *
+ * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
+ */
+int get_atom_positions_qmmm( const void * const handle, double * const qm_pos_x,
+        double * const qm_pos_y, double * const qm_pos_z, double * const mm_pos_x,
+        double * const mm_pos_y, double * const mm_pos_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_qm; ++i )
+        {
+            qm_pos_x[i] = spmd_handle->system->atoms[i].x[0];
+            qm_pos_y[i] = spmd_handle->system->atoms[i].x[1];
+            qm_pos_z[i] = spmd_handle->system->atoms[i].x[2];
+        }
+
+        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
+        {
+            mm_pos_x[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].x[0];
+            mm_pos_y[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].x[1];
+            mm_pos_z[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].x[2];
+        }
+
+        ret = SPUREMD_SUCCESS;
+    }
+
+    return ret;
+}
+
+
+/* Getter for atom velocities in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_vel_x: x-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
+ * qm_vel_y: y-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
+ * qm_vel_z: z-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
+ * mm_vel_x: x-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
+ * mm_vel_y: y-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
+ * mm_vel_z: z-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
+ *
+ * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
+ */
+int get_atom_velocities_qmmm( const void * const handle, double * const qm_vel_x,
+        double * const qm_vel_y, double * const qm_vel_z, double * const mm_vel_x,
+        double * const mm_vel_y, double * const mm_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_qm; ++i )
+        {
+            qm_vel_x[i] = spmd_handle->system->atoms[i].v[0];
+            qm_vel_y[i] = spmd_handle->system->atoms[i].v[1];
+            qm_vel_z[i] = spmd_handle->system->atoms[i].v[2];
+        }
+
+        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
+        {
+            mm_vel_x[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].v[0];
+            mm_vel_y[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].v[1];
+            mm_vel_z[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].v[2];
+        }
+
+        ret = SPUREMD_SUCCESS;
+    }
+
+    return ret;
+}
+
+
+/* Getter for atom forces in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_f_x: x-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * qm_f_y: y-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * qm_f_z: z-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * mm_f_x: x-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * mm_f_y: y-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * mm_f_z: z-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ *
+ * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
+ */
+int get_atom_forces_qmmm( const void * const handle, double * const qm_f_x,
+        double * const qm_f_y, double * const qm_f_z, double * const mm_f_x,
+        double * const mm_f_y, double * const mm_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_qm; ++i )
+        {
+            qm_f_x[i] = spmd_handle->system->atoms[i].f[0];
+            qm_f_y[i] = spmd_handle->system->atoms[i].f[1];
+            qm_f_z[i] = spmd_handle->system->atoms[i].f[2];
+        }
+
+        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
+        {
+            mm_f_x[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].f[0];
+            mm_f_y[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].f[1];
+            mm_f_z[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].f[2];
+        }
+
+        ret = SPUREMD_SUCCESS;
+    }
+
+    return ret;
+}
+
+
+/* Getter for atom charges in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_q: QM atom charges, in Coulombs (allocated by caller)
+ * mm_q: MM atom charges, in Coulombs (allocated by caller)
+ *
+ * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
+ */
+int get_atom_charges_qmmm( const void * const handle, double * const qm_q,
+        double * const mm_q )
+{
+    int i, ret;
+    spuremd_handle *spmd_handle;
+
+    ret = SPUREMD_FAILURE;
+
+    if ( handle != NULL )
+    {
+        spmd_handle = (spuremd_handle*) handle;
+
+        for ( i = 0; i < spmd_handle->system->N_qm; ++i )
+        {
+            qm_q[i] = spmd_handle->system->atoms[i].q;
+        }
+
+        for ( i = spmd_handle->system->N_qm; i < spmd_handle->system->N; ++i )
+        {
+            mm_q[i - spmd_handle->system->N_qm] = spmd_handle->system->atoms[i].q;
+        }
+
+        ret = SPUREMD_SUCCESS;
+    }
+
+    return ret;
+}
+#endif
+
+
+#if defined(QMMM_FORTRAN)
+/* Allocate top-level data structures and parse input files
+ * for the first simulation
+ *
+ * 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_info: 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_( void * handle, const int * const 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, const int * const 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_info, const char * const ffield_file,
+        const char * const control_file )
+{
+    handle = setup_qmmm( *qm_num_atoms, qm_types, qm_pos_x, qm_pos_y, qm_pos_z,
+            *mm_num_atoms, mm_types, mm_pos_x, mm_pos_y, mm_pos_z, mm_q,
+            sim_box_info, ffield_file, control_file );
+}
+
+
+/* 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_info: 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 reset_qmmm_( const void * const handle,
+        const int * const 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,
+        const int * const 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_info,
+        const char * const ffield_file, const char * const control_file )
+{
+    int ret;
+
+    ret = reset_qmmm( handle, *qm_num_atoms, qm_types, qm_pos_x, qm_pos_y, qm_pos_z,
+            *mm_num_atoms, mm_types, mm_pos_x, mm_pos_y, mm_pos_z, mm_q,
+            sim_box_info, ffield_file, control_file );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* Run the simulation according to the prescribed parameters
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ */
+void simulate_( const void * const handle )
+{
+    int ret;
+
+    ret = simulate( handle );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* Deallocate all data structures post-simulation
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ */
+void cleanup_( const void * const handle )
+{
+    int ret;
+
+    ret = cleanup( handle );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* 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
+ */
+void set_output_enabled_( const void * const handle, const int enabled )
+{
+    int ret;
+
+    ret = set_output_enabled( handle, enabled );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* 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
+ */
+void set_control_parameter_( const void * const handle, const char * const keyword,
+       const char ** const values )
+{
+    int ret;
+
+    ret = set_control_parameter( handle, keyword, values );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* Getter for atom positions in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_pos_x: x-coordinate of QM atom positions, in Angstroms (allocated by caller)
+ * qm_pos_y: y-coordinate of QM atom positions, in Angstroms (allocated by caller)
+ * qm_pos_z: z-coordinate of QM atom positions, in Angstroms (allocated by caller)
+ * mm_pos_x: x-coordinate of MM atom positions, in Angstroms (allocated by caller)
+ * mm_pos_y: y-coordinate of MM atom positions, in Angstroms (allocated by caller)
+ * mm_pos_z: z-coordinate of MM atom positions, in Angstroms (allocated by caller)
+ */
+void get_atom_positions_qmmm_( const void * const handle, double * const qm_pos_x,
+        double * const qm_pos_y, double * const qm_pos_z, double * const mm_pos_x,
+        double * const mm_pos_y, double * const mm_pos_z )
+{
+    int ret;
+
+    ret = get_atom_positions_qmmm( handle, qm_pos_x, qm_pos_y, qm_pos_z,
+            mm_pos_x, mm_pos_y, mm_pos_z );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* Getter for atom velocities in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_vel_x: x-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
+ * qm_vel_y: y-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
+ * qm_vel_z: z-coordinate of QM atom velocities, in Angstroms / ps (allocated by caller)
+ * mm_vel_x: x-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
+ * mm_vel_y: y-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
+ * mm_vel_z: z-coordinate of MM atom velocities, in Angstroms / ps (allocated by caller)
+ */
+void get_atom_velocities_qmmm_( const void * const handle, double * const qm_vel_x,
+        double * const qm_vel_y, double * const qm_vel_z, double * const mm_vel_x,
+        double * const mm_vel_y, double * const mm_vel_z )
+{
+    int ret;
+
+    ret = get_atom_velocities_qmmm( handle, qm_vel_x, qm_vel_y, qm_vel_z,
+            mm_vel_x, mm_vel_y, mm_vel_z );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* Getter for atom forces in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_f_x: x-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * qm_f_y: y-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * qm_f_z: z-coordinate of QM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * mm_f_x: x-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * mm_f_y: y-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ * mm_f_z: z-coordinate of MM atom forces, in Angstroms * Daltons / ps^2 (allocated by caller)
+ */
+void get_atom_forces_qmmm_( const void * const handle, double * const qm_f_x,
+        double * const qm_f_y, double * const qm_f_z, double * const mm_f_x,
+        double * const mm_f_y, double * const mm_f_z )
+{
+    int ret;
+
+    ret = get_atom_forces_qmmm( handle, qm_f_x, qm_f_y, qm_f_z,
+            mm_f_x, mm_f_y, mm_f_z );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* Getter for atom charges in QMMM mode
+ *
+ * handle: pointer to wrapper struct with top-level data structures
+ * qm_q: QM atom charges, in Coulombs (allocated by caller)
+ * mm_q: MM atom charges, in Coulombs (allocated by caller)
+ *
+ * returns: SPUREMD_SUCCESS upon success, SPUREMD_FAILURE otherwise
+ */
+void get_atom_charges_qmmm_( const void * const handle, double * const qm_q,
+        double * const mm_q )
+{
+    int ret;
+
+    ret = get_atom_charges_qmmm( handle, qm_q, mm_q );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+
+
+/* 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)
+ */
+void 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;
+
+    ret = get_system_info( handle, e_pot, e_kin, e_tot, temp, vol, pres );
+
+    if ( ret != SPUREMD_SUCCESS )
+    {
+        /* TODO: pass errors via another mechanism */
+        ;
+    }
+}
+#endif
diff --git a/sPuReMD/src/spuremd.h b/sPuReMD/src/spuremd.h
index ea021f8a771bec2ef6f21bcfafb49aca17ae4535..30251c44f4a2eaf60b111514312efdcf8318d682 100644
--- a/sPuReMD/src/spuremd.h
+++ b/sPuReMD/src/spuremd.h
@@ -33,16 +33,6 @@
 extern "C"  {
 #endif
 
-#if defined(QMMM)
-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 );
-#endif
-
 void * setup( const char * const, const char * const,
         const char * const );
 
@@ -52,55 +42,106 @@ int simulate( const void * const );
 
 int cleanup( const void * 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(QMMM)
-int reset_qmmm_( const void * const, int,
-        const int * 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 );
-#endif
 
-int reset( const void * const, const char * 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 );
 
-#if defined(QMMM)
-int get_atom_positions_qmmm_( const void * const, double * const,
+int get_atom_positions_qmmm( const void * const, double * const,
         double * const, double * const, double * const,
         double * const, double * const );
 
-int get_atom_velocities_qmmm_( const void * const, double * const,
+int get_atom_velocities_qmmm( const void * const, double * const,
         double * const, double * const, double * const,
         double * const, double * const );
 
-int get_atom_forces_qmmm_( const void * const, double * const,
+int get_atom_forces_qmmm( const void * const, double * const,
         double * const, double * const, double * const,
         double * const, double * const );
 
-int get_atom_charges_qmmm_( const void * const, double * const, double * const );
+int get_atom_charges_qmmm( const void * const, double * const, double * const );
 #endif
 
-int get_atom_positions( const void * const, double * const,
-        double * const, double * const );
+#if defined(QMMM_FORTRAN)
+void setup_qmmm_( void *, const int * const, const int * const,
+        const double * const, const double * const,
+        const double * const, const int * const, 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 get_atom_velocities( const void * const, double * const,
-        double * const, double * const );
+void reset_qmmm_( const void * const, const int * const, const int * const,
+        const double * const, const double * const,
+        const double * const, const int * const, 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 get_atom_forces( const void * const, double * const,
+void simulate_( const void * const );
+
+void cleanup_( const void * const );
+
+void set_output_enabled_( const void * const, const int );
+
+void set_control_parameter_( const void * const, const char * const,
+       const char ** const );
+
+void get_atom_positions_qmmm_( const void * const, double * const,
+        double * const, double * const, double * const,
         double * const, double * const );
 
-int get_atom_charges( const void * const, double * const );
+void get_atom_velocities_qmmm_( const void * const, double * const,
+        double * const, double * const, double * const,
+        double * const, double * const );
 
-int get_system_info( const void * const, double * const,
+void get_atom_forces_qmmm_( const void * const, double * const,
         double * const, double * const, double * const,
         double * const, double * const );
 
-int set_output_enabled( const void * const, const int );
+void get_atom_charges_qmmm_( const void * const, double * const, double * const );
 
-int set_control_parameter( const void * const, const char * const,
-       const char ** const );
+void get_system_info_( const void * const, double * const,
+        double * const, double * const, double * const,
+        double * const, double * const );
+#endif
 
 #if defined(__cplusplus)
 }