diff --git a/doc/src/dump_modify.txt b/doc/src/dump_modify.txt
index b5daa6416e91912ab30eef406dec4d4078deb419..2ea1da3db3b6295531b913bc9e25665a9c4c7ba7 100644
--- a/doc/src/dump_modify.txt
+++ b/doc/src/dump_modify.txt
@@ -16,7 +16,8 @@ dump-ID = ID of dump to modify :ulb,l
 one or more keyword/value pairs may be appended :l
 these keywords apply to various dump styles :l
 keyword = {append} or {buffer} or {element} or {every} or {fileper} or {first} or {flush} or {format} or {image} or {label} or {nfile} or {pad} or {precision} or {region} or {scale} or {sort} or {thresh} or {unwrap} :l
-  {append} arg = {yes} or {no}
+  {append} arg = {yes} or {no} or {at} N
+    N = index of frame written upon first dump
   {buffer} arg = {yes} or {no}
   {element} args = E1 E2 ... EN, where N = # of atom types
     E1,...,EN = element name, e.g. C or Fe or Ga
@@ -41,6 +42,7 @@ keyword = {append} or {buffer} or {element} or {every} or {fileper} or {first} o
   {region} arg = region-ID or "none"
   {scale} arg = {yes} or {no}
   {sfactor} arg = coordinate scaling factor (> 0.0)
+  {thermo} arg = {yes} or {no}
   {tfactor} arg = time scaling factor (> 0.0)
   {sort} arg = {off} or {id} or N or -N
      off = no sorting of per-atom lines within a snapshot
@@ -139,12 +141,13 @@ and {dcd}.  It also applies only to text output files, not to binary
 or gzipped or image/movie files.  If specified as {yes}, then dump
 snapshots are appended to the end of an existing dump file.  If
 specified as {no}, then a new dump file will be created which will
-overwrite an existing file with the same name.  This keyword can only
-take effect if the dump_modify command is used after the
-"dump"_dump.html command, but before the first command that causes
-dump snapshots to be output, e.g. a "run"_run.html or
-"minimize"_minimize.html command.  Once the dump file has been opened,
-this keyword has no further effect.
+overwrite an existing file with the same name.  If the {at} option is present
+({netcdf} only), then the frame to append to can be specified.  Negative values
+are counted from the end of the file.  This keyword can only take effect if the
+dump_modify command is used after the "dump"_dump.html command, but before the
+first command that causes dump snapshots to be output, e.g. a "run"_run.html or
+"minimize"_minimize.html command.  Once the dump file has been opened, this
+keyword has no further effect.
 
 :line
 
@@ -413,6 +416,13 @@ most effective when the typical magnitude of position data is between
 
 :line
 
+The {thermo} keyword ({netcdf} only) triggers writing of "thermo"_thermo.html
+information to the dump file alongside per-atom data. The data included in the
+dump file is identical to the data specified by
+"thermo_style"_thermo_style.html.
+
+:line
+
 The {region} keyword only applies to the dump {custom}, {cfg},
 {image}, and {movie} styles.  If specified, only atoms in the region
 will be written to the dump file or included in the image/movie.  Only
diff --git a/doc/src/dump_netcdf.txt b/doc/src/dump_netcdf.txt
index 4e82656698a61860a9b376e2eac19e11f05ec1c8..63568137a65ec5d6891db69a9d7cf33d1be1a098 100644
--- a/doc/src/dump_netcdf.txt
+++ b/doc/src/dump_netcdf.txt
@@ -24,7 +24,7 @@ args = list of atom attributes, same as for "dump_style custom"_dump.html :l,ule
 [Examples:]
 
 dump 1 all netcdf 100 traj.nc type x y z vx vy vz
-dump_modify 1 append yes at -1 global c_thermo_pe c_thermo_temp c_thermo_press
+dump_modify 1 append yes at -1 thermo yes
 dump 1 all netcdf/mpiio 1000 traj.nc id type x y z :pre
 
 [Description:]
@@ -44,7 +44,7 @@ rank.
 NetCDF files can be directly visualized via the following tools:
 
 Ovito (http://www.ovito.org/). Ovito supports the AMBER convention and
-all of the above extensions. :ule,b
+all extensions of this dump style. :ule,b
 
 VMD (http://www.ks.uiuc.edu/Research/vmd/). :l
 
@@ -52,15 +52,9 @@ AtomEye (http://www.libatoms.org/). The libAtoms version of AtomEye
 contains a NetCDF reader that is not present in the standard
 distribution of AtomEye. :l,ule
 
-In addition to per-atom data, global data can be included in the dump
-file, which are the kinds of values output by the
-"thermo_style"_thermo_style.html command .  See "Section howto
-6.15"_Section_howto.html#howto_15 for an explanation of per-atom
-versus global data.  The global output written into the dump file can
-be from computes, fixes, or variables, by prefixing the compute/fix ID
-or variable name with "c_" or "f_" or "v_" respectively, as in the
-example above.  These global values are specified via the "dump_modify
-global"_dump_modify.html command.
+In addition to per-atom data, "thermo"_thermo.html data can be included in the
+dump file. The data included in the dump file is identical to the data specified
+by "thermo_style"_thermo_style.html.
 
 :link(netcdf-home,http://www.unidata.ucar.edu/software/netcdf/)
 :link(pnetcdf-home,http://trac.mcs.anl.gov/projects/parallel-netcdf/)
diff --git a/src/USER-NETCDF/README b/src/USER-NETCDF/README
index 57dec5e4c835fd41b4b5ac7a62ac8e96e75913e0..7d7874e5acaefc5bc0b785d5304252f5e7320ba4 100644
--- a/src/USER-NETCDF/README
+++ b/src/USER-NETCDF/README
@@ -1,9 +1,9 @@
 USER-NETCDF
 ============
 
-This package provides the netcf and netcdf/mpiio dump styles.
-See the doc page for dump nc or dump nc/mpiio command for how to use them.
-Compiling these dump styles requires having the netCDF library installed
+This package provides the netcdf and netcdf/mpiio dump styles.
+See the doc page for dump netcdf or dump netcdf/mpiio command for how to use
+them. Compiling these dump styles requires having the netCDF library installed
 on your system. See lib/netcdf/README for additional details.
 
 PACKAGE DESCRIPTION
@@ -29,11 +29,11 @@ NetCDF files can be directly visualized with the following tools:
   a NetCDF reader that is not present in the standard distribution of AtomEye.
 
 The person who created these files is Lars Pastewka at
-Karlsruhe Institute of Technology (lars.pastewka@kit.edu).
+the University of Freiburg (lars.pastewka@imtek.uni-freiburg.de).
 Contact him directly if you have questions.
 
 Lars Pastewka
-Institute for Applied Materials (IAM)
-Karlsruhe Institute of Technology (KIT)
-Kaiserstrasse 12, 76131 Karlsruhe
-e-mail: lars.pastewka@kit.edu
+University of Freiburg
+Department of Microsystems Engineering
+Georges-Köhler-Allee 103, 79110 Freiburg, Germany
+e-mail: lars.pastewka@imtek.uni-freiburg.de
diff --git a/src/USER-NETCDF/dump_netcdf.cpp b/src/USER-NETCDF/dump_netcdf.cpp
index bad90bdef3d1affe541a93c27e69856a66c3f700..b45794126d8175e876d9764738f2d582bd0f3ae0 100644
--- a/src/USER-NETCDF/dump_netcdf.cpp
+++ b/src/USER-NETCDF/dump_netcdf.cpp
@@ -1,25 +1,3 @@
-/* ======================================================================
-   LAMMPS NetCDF dump style
-   https://github.com/pastewka/lammps-netcdf
-   Lars Pastewka, lars.pastewka@kit.edu
-
-   Copyright (2011-2013) Fraunhofer IWM
-   Copyright (2014) Karlsruhe Institute of Technology
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-   ====================================================================== */
-
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
@@ -33,6 +11,10 @@
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
+/* ----------------------------------------------------------------------
+   Contributing author: Lars Pastewka (University of Freiburg)
+------------------------------------------------------------------------- */
+
 #if defined(LMP_HAS_NETCDF)
 
 #include <unistd.h>
@@ -55,11 +37,13 @@
 #include "universe.h"
 #include "variable.h"
 #include "force.h"
+#include "output.h"
+#include "thermo.h"
 
 using namespace LAMMPS_NS;
 using namespace MathConst;
 
-enum{INT,DOUBLE};  // same as in dump_custom.cpp
+enum{INT,FLOAT,BIGINT}; // same as in thermo.cpp
 
 const char NC_FRAME_STR[]         = "frame";
 const char NC_SPATIAL_STR[]       = "spatial";
@@ -208,15 +192,15 @@ DumpNetCDF::DumpNetCDF(LAMMPS *lmp, int narg, char **arg) :
     perat[inc].field[idim] = i;
   }
 
-  n_perframe = 0;
-  perframe = NULL;
-
   n_buffer = 0;
   int_buffer = NULL;
   double_buffer = NULL;
 
   double_precision = false;
 
+  thermo = false;
+  thermovar = NULL;
+
   framei = 0;
 }
 
@@ -227,8 +211,7 @@ DumpNetCDF::~DumpNetCDF()
   closefile();
 
   delete [] perat;
-  if (n_perframe > 0)
-    delete [] perframe;
+  if (thermovar)  delete [] thermovar;
 
   if (int_buffer) memory->sfree(int_buffer);
   if (double_buffer) memory->sfree(double_buffer);
@@ -238,6 +221,11 @@ DumpNetCDF::~DumpNetCDF()
 
 void DumpNetCDF::openfile()
 {
+  if (thermo && !singlefile_opened) {
+    if (thermovar)  delete [] thermovar;
+    thermovar = new int[output->thermo->nfield];
+  }
+
   // now the computes and fixes have been initialized, so we can query
   // for the size of vector quantities
   for (int i = 0; i < n_perat; i++) {
@@ -289,30 +277,30 @@ void DumpNetCDF::openfile()
       // dimensions
       NCERRX( nc_inq_dimid(ncid, NC_FRAME_STR, &frame_dim), NC_FRAME_STR );
       NCERRX( nc_inq_dimid(ncid, NC_SPATIAL_STR, &spatial_dim),
-	      NC_SPATIAL_STR );
+          NC_SPATIAL_STR );
       NCERRX( nc_inq_dimid(ncid, NC_VOIGT_STR, &Voigt_dim), NC_VOIGT_STR );
       NCERRX( nc_inq_dimid(ncid, NC_ATOM_STR, &atom_dim), NC_ATOM_STR );
       NCERRX( nc_inq_dimid(ncid, NC_CELL_SPATIAL_STR, &cell_spatial_dim),
-	      NC_CELL_SPATIAL_STR );
+          NC_CELL_SPATIAL_STR );
       NCERRX( nc_inq_dimid(ncid, NC_CELL_ANGULAR_STR, &cell_angular_dim),
-	      NC_CELL_ANGULAR_STR );
+          NC_CELL_ANGULAR_STR );
       NCERRX( nc_inq_dimid(ncid, NC_LABEL_STR, &label_dim), NC_LABEL_STR );
 
       // default variables
       NCERRX( nc_inq_varid(ncid, NC_SPATIAL_STR, &spatial_var),
-	      NC_SPATIAL_STR );
+          NC_SPATIAL_STR );
       NCERRX( nc_inq_varid(ncid, NC_CELL_SPATIAL_STR, &cell_spatial_var),
-	      NC_CELL_SPATIAL_STR);
+          NC_CELL_SPATIAL_STR);
       NCERRX( nc_inq_varid(ncid, NC_CELL_ANGULAR_STR, &cell_angular_var),
-	      NC_CELL_ANGULAR_STR);
+          NC_CELL_ANGULAR_STR);
 
       NCERRX( nc_inq_varid(ncid, NC_TIME_STR, &time_var), NC_TIME_STR );
       NCERRX( nc_inq_varid(ncid, NC_CELL_ORIGIN_STR, &cell_origin_var),
-	      NC_CELL_ORIGIN_STR );
+          NC_CELL_ORIGIN_STR );
       NCERRX( nc_inq_varid(ncid, NC_CELL_LENGTHS_STR, &cell_lengths_var),
-	      NC_CELL_LENGTHS_STR);
+          NC_CELL_LENGTHS_STR);
       NCERRX( nc_inq_varid(ncid, NC_CELL_ANGLES_STR, &cell_angles_var),
-	      NC_CELL_ANGLES_STR);
+          NC_CELL_ANGLES_STR);
 
       // variables specified in the input file
       for (int i = 0; i < n_perat; i++) {
@@ -334,9 +322,12 @@ void DumpNetCDF::openfile()
       }
 
       // perframe variables
-      for (int i = 0; i < n_perframe; i++) {
-        NCERRX( nc_inq_varid(ncid, perframe[i].name, &perframe[i].var),
-                perframe[i].name );
+      if (thermo) {
+        Thermo *th = output->thermo;
+        for (int i = 0; i < th->nfield; i++) {
+          NCERRX( nc_inq_varid(ncid, th->keyword[i], &thermovar[i]),
+                  th->keyword[i] );
+        }
       }
 
       size_t nframes;
@@ -354,49 +345,49 @@ void DumpNetCDF::openfile()
       if (singlefile_opened) return;
       singlefile_opened = 1;
 
-      NCERRX( nc_create(filename, NC_64BIT_OFFSET, &ncid),
-	      filename );
+      NCERRX( nc_create(filename, NC_64BIT_DATA, &ncid),
+          filename );
 
       // dimensions
       NCERRX( nc_def_dim(ncid, NC_FRAME_STR, NC_UNLIMITED, &frame_dim),
-	      NC_FRAME_STR );
+          NC_FRAME_STR );
       NCERRX( nc_def_dim(ncid, NC_SPATIAL_STR, 3, &spatial_dim),
-	      NC_SPATIAL_STR );
+          NC_SPATIAL_STR );
       NCERRX( nc_def_dim(ncid, NC_VOIGT_STR, 6, &Voigt_dim),
-	      NC_VOIGT_STR );
+          NC_VOIGT_STR );
       NCERRX( nc_def_dim(ncid, NC_ATOM_STR, ntotalgr, &atom_dim),
-	      NC_ATOM_STR );
+          NC_ATOM_STR );
       NCERRX( nc_def_dim(ncid, NC_CELL_SPATIAL_STR, 3, &cell_spatial_dim),
-	      NC_CELL_SPATIAL_STR );
+          NC_CELL_SPATIAL_STR );
       NCERRX( nc_def_dim(ncid, NC_CELL_ANGULAR_STR, 3, &cell_angular_dim),
-	      NC_CELL_ANGULAR_STR );
+          NC_CELL_ANGULAR_STR );
       NCERRX( nc_def_dim(ncid, NC_LABEL_STR, 10, &label_dim),
-	      NC_LABEL_STR );
+          NC_LABEL_STR );
 
       // default variables
       dims[0] = spatial_dim;
       NCERRX( nc_def_var(ncid, NC_SPATIAL_STR, NC_CHAR, 1, dims, &spatial_var),
-	      NC_SPATIAL_STR );
+          NC_SPATIAL_STR );
       NCERRX( nc_def_var(ncid, NC_CELL_SPATIAL_STR, NC_CHAR, 1, dims,
-			 &cell_spatial_var), NC_CELL_SPATIAL_STR );
+             &cell_spatial_var), NC_CELL_SPATIAL_STR );
       dims[0] = spatial_dim;
       dims[1] = label_dim;
       NCERRX( nc_def_var(ncid, NC_CELL_ANGULAR_STR, NC_CHAR, 2, dims,
-			 &cell_angular_var), NC_CELL_ANGULAR_STR );
+             &cell_angular_var), NC_CELL_ANGULAR_STR );
 
       dims[0] = frame_dim;
       NCERRX( nc_def_var(ncid, NC_TIME_STR, NC_DOUBLE, 1, dims, &time_var),
-	      NC_TIME_STR);
+          NC_TIME_STR);
       dims[0] = frame_dim;
       dims[1] = cell_spatial_dim;
       NCERRX( nc_def_var(ncid, NC_CELL_ORIGIN_STR, NC_DOUBLE, 2, dims,
-			 &cell_origin_var), NC_CELL_ORIGIN_STR );
+             &cell_origin_var), NC_CELL_ORIGIN_STR );
       NCERRX( nc_def_var(ncid, NC_CELL_LENGTHS_STR, NC_DOUBLE, 2, dims,
-			 &cell_lengths_var), NC_CELL_LENGTHS_STR );
+             &cell_lengths_var), NC_CELL_LENGTHS_STR );
       dims[0] = frame_dim;
       dims[1] = cell_angular_dim;
       NCERRX( nc_def_var(ncid, NC_CELL_ANGLES_STR, NC_DOUBLE, 2, dims,
-			 &cell_angles_var), NC_CELL_ANGLES_STR );
+             &cell_angles_var), NC_CELL_ANGLES_STR );
 
       // variables specified in the input file
       dims[0] = frame_dim;
@@ -423,17 +414,17 @@ void DumpNetCDF::openfile()
             // this is a tensor in Voigt notation
             dims[2] = Voigt_dim;
             NCERRX( nc_def_var(ncid, perat[i].name, xtype, 2, dims+1,
-			       &perat[i].var), perat[i].name );
+                   &perat[i].var), perat[i].name );
           }
           else if (perat[i].dims == 3) {
             // this is a vector, we need to store x-, y- and z-coordinates
             dims[2] = spatial_dim;
             NCERRX( nc_def_var(ncid, perat[i].name, xtype, 2, dims+1,
-			       &perat[i].var), perat[i].name );
+                   &perat[i].var), perat[i].name );
           }
           else if (perat[i].dims == 1) {
             NCERRX( nc_def_var(ncid, perat[i].name, xtype, 1, dims+1,
-			       &perat[i].var), perat[i].name );
+                   &perat[i].var), perat[i].name );
           }
           else {
             char errstr[1024];
@@ -448,17 +439,17 @@ void DumpNetCDF::openfile()
             // this is a tensor in Voigt notation
             dims[2] = Voigt_dim;
             NCERRX( nc_def_var(ncid, perat[i].name, xtype, 3, dims,
-			       &perat[i].var), perat[i].name );
+                   &perat[i].var), perat[i].name );
           }
           else if (perat[i].dims == 3) {
             // this is a vector, we need to store x-, y- and z-coordinates
             dims[2] = spatial_dim;
             NCERRX( nc_def_var(ncid, perat[i].name, xtype, 3, dims,
-			       &perat[i].var), perat[i].name );
+                   &perat[i].var), perat[i].name );
           }
           else if (perat[i].dims == 1) {
             NCERRX( nc_def_var(ncid, perat[i].name, xtype, 2, dims,
-			       &perat[i].var), perat[i].name );
+                   &perat[i].var), perat[i].name );
           }
           else {
             char errstr[1024];
@@ -471,14 +462,21 @@ void DumpNetCDF::openfile()
       }
 
       // perframe variables
-      for (int i = 0; i < n_perframe; i++) {
-        if (perframe[i].type == THIS_IS_A_BIGINT) {
-          NCERRX( nc_def_var(ncid, perframe[i].name, NC_LONG, 1, dims,
-			     &perframe[i].var), perframe[i].name );
-        }
-        else {
-          NCERRX( nc_def_var(ncid, perframe[i].name, NC_DOUBLE, 1, dims,
-			     &perframe[i].var), perframe[i].name );
+      if (thermo) {
+        Thermo *th = output->thermo;
+        for (int i = 0; i < th->nfield; i++) {
+          if (th->vtype[i] == FLOAT) {
+            NCERRX( nc_def_var(ncid, th->keyword[i], NC_DOUBLE, 1, dims,
+                               &thermovar[i]), th->keyword[i] );
+          }
+          else if (th->vtype[i] == INT) {
+            NCERRX( nc_def_var(ncid, th->keyword[i], NC_INT, 1, dims,
+                               &thermovar[i]), th->keyword[i] );
+          }
+          else if (th->vtype[i] == BIGINT) {
+            NCERRX( nc_def_var(ncid, th->keyword[i], NC_LONG, 1, dims,
+                               &thermovar[i]), th->keyword[i] );
+          }
         }
       }
 
@@ -622,46 +620,30 @@ void DumpNetCDF::write()
   start[0] = framei-1;
   start[1] = 0;
 
-  for (int i = 0; i < n_perframe; i++) {
-
-    if (perframe[i].type == THIS_IS_A_BIGINT) {
-      bigint data;
-      (this->*perframe[i].compute)((void*) &data);
-
-      if (filewriter)
+  if (thermo) {
+    Thermo *th = output->thermo;
+    for (int i = 0; i < th->nfield; i++) {
+      th->call_vfunc(i);
+      if (filewriter) {
+        if (th->vtype[i] == FLOAT) {
+          NCERRX( nc_put_var1_double(ncid, thermovar[i], start,
+                                     &th->dvalue),
+                  th->keyword[i] );
+        }
+        else if (th->vtype[i] == INT) {
+          NCERRX( nc_put_var1_int(ncid, thermovar[i], start, &th->ivalue),
+                  th->keyword[i] );
+        }
+        else if (th->vtype[i] == BIGINT) {
 #if defined(LAMMPS_SMALLBIG) || defined(LAMMPS_BIGBIG)
-        NCERR( nc_put_var1_long(ncid, perframe[i].var, start, &data) );
+          NCERRX( nc_put_var1_long(ncid, thermovar[i], start, &th->bivalue),
+                  th->keyword[i] );
 #else
-        NCERR( nc_put_var1_int(ncid, perframe[i].var, start, &data) );
+          NCERRX( nc_put_var1_int(ncid, thermovar[i], start, &th->bivalue),
+                  th->keyword[i] );
 #endif
-    }
-    else {
-      double data;
-      int j = perframe[i].index;
-      int idim = perframe[i].dim;
-
-      if (perframe[i].type == THIS_IS_A_COMPUTE) {
-        if (idim >= 0) {
-          modify->compute[j]->compute_vector();
-          data = modify->compute[j]->vector[idim];
-        }
-        else
-          data = modify->compute[j]->compute_scalar();
-      }
-      else if (perframe[i].type == THIS_IS_A_FIX) {
-        if (idim >= 0) {
-          data = modify->fix[j]->compute_vector(idim);
         }
-        else
-          data = modify->fix[j]->compute_scalar();
       }
-      else if (perframe[i].type == THIS_IS_A_VARIABLE) {
-        j = input->variable->find(perframe[i].id);
-        data = input->variable->compute_equal(j);
-      }
-
-      if (filewriter)
-        NCERR( nc_put_var1_double(ncid, perframe[i].var, start, &data) );
     }
   }
 
@@ -908,126 +890,19 @@ int DumpNetCDF::modify_param(int narg, char **arg)
     iarg++;
     return 2;
   }
-  else if (strcmp(arg[iarg],"global") == 0) {
-    // "perframe" quantities, i.e. not per-atom stuff
-
+  else if (strcmp(arg[iarg],"thermo") == 0) {
     iarg++;
-
-    n_perframe = narg-iarg;
-    perframe = new nc_perframe_t[n_perframe];
-
-    for (int i = 0; iarg < narg; iarg++, i++) {
-      int n;
-      char *suffix=NULL;
-
-      if (!strcmp(arg[iarg],"step")) {
-        perframe[i].type = THIS_IS_A_BIGINT;
-        perframe[i].compute = &DumpNetCDF::compute_step;
-        strcpy(perframe[i].name, arg[iarg]);
-      }
-      else if (!strcmp(arg[iarg],"elapsed")) {
-        perframe[i].type = THIS_IS_A_BIGINT;
-        perframe[i].compute = &DumpNetCDF::compute_elapsed;
-        strcpy(perframe[i].name, arg[iarg]);
-      }
-      else if (!strcmp(arg[iarg],"elaplong")) {
-        perframe[i].type = THIS_IS_A_BIGINT;
-        perframe[i].compute = &DumpNetCDF::compute_elapsed_long;
-        strcpy(perframe[i].name, arg[iarg]);
-      }
-      else {
-
-        n = strlen(arg[iarg]);
-
-        if (n > 2) {
-          suffix = new char[n-1];
-          strcpy(suffix, arg[iarg]+2);
-        }
-        else {
-          char errstr[1024];
-          sprintf(errstr, "perframe quantity '%s' must thermo quantity or "
-                  "compute, fix or variable", arg[iarg]);
-          error->all(FLERR,errstr);
-        }
-
-        if (!strncmp(arg[iarg], "c_", 2)) {
-          int idim = -1;
-          char *ptr = strchr(suffix, '[');
-
-          if (ptr) {
-            if (suffix[strlen(suffix)-1] != ']')
-              error->all(FLERR,"Missing ']' in dump modify command");
-            *ptr = '\0';
-            idim = ptr[1] - '1';
-          }
-
-          n = modify->find_compute(suffix);
-          if (n < 0)
-            error->all(FLERR,"Could not find dump modify compute ID");
-          if (modify->compute[n]->peratom_flag != 0)
-            error->all(FLERR,"Dump modify compute ID computes per-atom info");
-          if (idim >= 0 && modify->compute[n]->vector_flag == 0)
-            error->all(FLERR,"Dump modify compute ID does not compute vector");
-          if (idim < 0 && modify->compute[n]->scalar_flag == 0)
-            error->all(FLERR,"Dump modify compute ID does not compute scalar");
-
-          perframe[i].type = THIS_IS_A_COMPUTE;
-          perframe[i].dim = idim;
-          perframe[i].index = n;
-          strcpy(perframe[i].name, arg[iarg]);
-        }
-        else if (!strncmp(arg[iarg], "f_", 2)) {
-          int idim = -1;
-          char *ptr = strchr(suffix, '[');
-
-          if (ptr) {
-            if (suffix[strlen(suffix)-1] != ']')
-              error->all(FLERR,"Missing ']' in dump modify command");
-            *ptr = '\0';
-            idim = ptr[1] - '1';
-          }
-
-          n = modify->find_fix(suffix);
-          if (n < 0)
-            error->all(FLERR,"Could not find dump modify fix ID");
-          if (modify->fix[n]->peratom_flag != 0)
-            error->all(FLERR,"Dump modify fix ID computes per-atom info");
-          if (idim >= 0 && modify->fix[n]->vector_flag == 0)
-            error->all(FLERR,"Dump modify fix ID does not compute vector");
-          if (idim < 0 && modify->fix[n]->scalar_flag == 0)
-            error->all(FLERR,"Dump modify fix ID does not compute vector");
-
-          perframe[i].type = THIS_IS_A_FIX;
-          perframe[i].dim = idim;
-          perframe[i].index = n;
-          strcpy(perframe[i].name, arg[iarg]);
-        }
-        else if (!strncmp(arg[iarg], "v_", 2)) {
-          n = input->variable->find(suffix);
-          if (n < 0)
-            error->all(FLERR,"Could not find dump modify variable ID");
-          if (!input->variable->equalstyle(n))
-            error->all(FLERR,"Dump modify variable must be of style equal");
-
-          perframe[i].type = THIS_IS_A_VARIABLE;
-          perframe[i].dim = 1;
-          perframe[i].index = n;
-          strcpy(perframe[i].name, arg[iarg]);
-          strcpy(perframe[i].id, suffix);
-        }
-        else {
-          char errstr[1024];
-          sprintf(errstr, "perframe quantity '%s' must be compute, fix or "
-                  "variable", arg[iarg]);
-          error->all(FLERR,errstr);
-        }
-
-        delete [] suffix;
-
-      }
+    if (iarg >= narg)
+      error->all(FLERR,"expected 'yes' or 'no' after 'thermo' keyword.");
+    if (strcmp(arg[iarg],"yes") == 0) {
+      thermo = true;
     }
-
-    return narg;
+    else if (strcmp(arg[iarg],"no") == 0) {
+      thermo = false;
+    }
+    else error->all(FLERR,"expected 'yes' or 'no' after 'thermo' keyword.");
+    iarg++;
+    return 2;
   } else return 0;
 }
 
@@ -1101,41 +976,14 @@ void DumpNetCDF::ncerr(int err, const char *descr, int line)
     char errstr[1024];
     if (descr) {
       sprintf(errstr, "NetCDF failed with error '%s' (while accessing '%s') "
-	      " in line %i of %s.", nc_strerror(err), descr, line, __FILE__);
+          " in line %i of %s.", nc_strerror(err), descr, line, __FILE__);
     }
     else {
       sprintf(errstr, "NetCDF failed with error '%s' in line %i of %s.",
-	      nc_strerror(err), line, __FILE__);
+          nc_strerror(err), line, __FILE__);
     }
     error->one(FLERR,errstr);
   }
 }
 
-/* ----------------------------------------------------------------------
-   one method for every keyword thermo can output
-   called by compute() or evaluate_keyword()
-   compute will have already been called
-   set ivalue/dvalue/bivalue if value is int/double/bigint
-   customize a new keyword by adding a method
-------------------------------------------------------------------------- */
-
-void DumpNetCDF::compute_step(void *r)
-{
-  *((bigint *) r) = update->ntimestep;
-}
-
-/* ---------------------------------------------------------------------- */
-
-void DumpNetCDF::compute_elapsed(void *r)
-{
-  *((bigint *) r) = update->ntimestep - update->firststep;
-}
-
-/* ---------------------------------------------------------------------- */
-
-void DumpNetCDF::compute_elapsed_long(void *r)
-{
-  *((bigint *) r) = update->ntimestep - update->beginstep;
-}
-
 #endif /* defined(LMP_HAS_NETCDF) */
diff --git a/src/USER-NETCDF/dump_netcdf.h b/src/USER-NETCDF/dump_netcdf.h
index daf4e9d0de2d94151c6f0bad6b9e348171e48b82..036df3f058398a53c9f55df4f1fab79f7a477b8e 100644
--- a/src/USER-NETCDF/dump_netcdf.h
+++ b/src/USER-NETCDF/dump_netcdf.h
@@ -1,25 +1,3 @@
-/* ======================================================================
-   LAMMPS NetCDF dump style
-   https://github.com/pastewka/lammps-netcdf
-   Lars Pastewka, lars.pastewka@kit.edu
-
-   Copyright (2011-2013) Fraunhofer IWM
-   Copyright (2014) Karlsruhe Institute of Technology
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-   ====================================================================== */
-
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
@@ -33,6 +11,10 @@
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
+/* ----------------------------------------------------------------------
+   Contributing author: Lars Pastewka (University of Freiburg)
+------------------------------------------------------------------------- */
+
 #if defined(LMP_HAS_NETCDF)
 
 #ifdef DUMP_CLASS
@@ -69,22 +51,6 @@ class DumpNetCDF : public DumpCustom {
     int ndumped;                  // number of enties written for this prop.
   };
 
-  typedef void (DumpNetCDF::*funcptr_t)(void *);
-
-  // per-frame quantities (variables, fixes or computes)
-  struct nc_perframe_t {
-    char name[NC_FIELD_NAME_MAX]; // field name
-    int var;                      // NetCDF variable
-    int type;                     // variable, fix, compute or callback
-    int index;                    // index in fix/compute list
-    funcptr_t compute;            // compute function
-    int dim;                      // dimension
-    char id[NC_FIELD_NAME_MAX];   // variable id
-
-    bigint bigint_data;           // actual data
-    double double_data;           // actual data
-  };
-
   int framei;                  // current frame index
   int blocki;                  // current block index
   int ndata;                   // number of data blocks to expect
@@ -94,10 +60,10 @@ class DumpNetCDF : public DumpCustom {
   int n_perat;                 // # of netcdf per-atom properties
   nc_perat_t *perat;           // per-atom properties
 
-  int n_perframe;              // # of global netcdf (not per-atom) fix props
-  nc_perframe_t *perframe;     // global properties
+  int *thermovar;              // NetCDF variables for thermo output
 
   bool double_precision;       // write everything as double precision
+  bool thermo;                 // write thermo output to netcdf file
 
   bigint n_buffer;             // size of buffer
   int *int_buffer;             // buffer for passing data to netcdf
@@ -131,10 +97,6 @@ class DumpNetCDF : public DumpCustom {
   virtual int modify_param(int, char **);
 
   void ncerr(int, const char *, int);
-
-  void compute_step(void *);
-  void compute_elapsed(void *);
-  void compute_elapsed_long(void *);
 };
 
 }
diff --git a/src/USER-NETCDF/dump_netcdf_mpiio.cpp b/src/USER-NETCDF/dump_netcdf_mpiio.cpp
index 2e9ec274a5e07cc04bddb7644aa87d54353b09c6..c5b87b178e2a58bf2b195a81365ec4352f168613 100644
--- a/src/USER-NETCDF/dump_netcdf_mpiio.cpp
+++ b/src/USER-NETCDF/dump_netcdf_mpiio.cpp
@@ -1,25 +1,3 @@
-/* ======================================================================
-   LAMMPS NetCDF dump style
-   https://github.com/pastewka/lammps-netcdf
-   Lars Pastewka, lars.pastewka@kit.edu
-
-   Copyright (2011-2013) Fraunhofer IWM
-   Copyright (2014) Karlsruhe Institute of Technology
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-   ====================================================================== */
-
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
@@ -33,6 +11,10 @@
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
+/* ----------------------------------------------------------------------
+   Contributing author: Lars Pastewka (University of Freiburg)
+------------------------------------------------------------------------- */
+
 #if defined(LMP_HAS_PNETCDF)
 
 #include <unistd.h>
@@ -55,11 +37,13 @@
 #include "universe.h"
 #include "variable.h"
 #include "force.h"
+#include "output.h"
+#include "thermo.h"
 
 using namespace LAMMPS_NS;
 using namespace MathConst;
 
-enum{INT,DOUBLE};  // same as in dump_custom.cpp
+enum{INT,FLOAT,BIGINT}; // same as in thermo.cpp
 
 const char NC_FRAME_STR[]         = "frame";
 const char NC_SPATIAL_STR[]       = "spatial";
@@ -201,15 +185,15 @@ DumpNetCDFMPIIO::DumpNetCDFMPIIO(LAMMPS *lmp, int narg, char **arg) :
     perat[inc].field[idim] = i;
   }
 
-  n_perframe = 0;
-  perframe = NULL;
-
   n_buffer = 0;
   int_buffer = NULL;
   double_buffer = NULL;
 
   double_precision = false;
 
+  thermo = false;
+  thermovar = NULL;
+
   framei = 0;
 }
 
@@ -220,8 +204,7 @@ DumpNetCDFMPIIO::~DumpNetCDFMPIIO()
   closefile();
 
   delete [] perat;
-  if (n_perframe > 0)
-    delete [] perframe;
+  if (thermovar)  delete [] thermovar;
 
   if (int_buffer) memory->sfree(int_buffer);
   if (double_buffer) memory->sfree(double_buffer);
@@ -231,6 +214,11 @@ DumpNetCDFMPIIO::~DumpNetCDFMPIIO()
 
 void DumpNetCDFMPIIO::openfile()
 {
+  if (thermo && !singlefile_opened) {
+    if (thermovar)  delete [] thermovar;
+    thermovar = new int[output->thermo->nfield];
+  }
+
   // now the computes and fixes have been initialized, so we can query
   // for the size of vector quantities
   for (int i = 0; i < n_perat; i++) {
@@ -330,9 +318,12 @@ void DumpNetCDFMPIIO::openfile()
     }
 
     // perframe variables
-    for (int i = 0; i < n_perframe; i++) {
-      NCERRX( ncmpi_inq_varid(ncid, perframe[i].name, &perframe[i].var),
-              perframe[i].name );
+    if (thermo) {
+      Thermo *th = output->thermo;
+      for (int i = 0; i < th->nfield; i++) {
+        NCERRX( ncmpi_inq_varid(ncid, th->keyword[i], &thermovar[i]),
+                th->keyword[i] );
+      }
     }
 
     MPI_Offset nframes;
@@ -350,7 +341,7 @@ void DumpNetCDFMPIIO::openfile()
     if (singlefile_opened) return;
     singlefile_opened = 1;
 
-    NCERRX( ncmpi_create(MPI_COMM_WORLD, filename, NC_64BIT_OFFSET,
+    NCERRX( ncmpi_create(MPI_COMM_WORLD, filename, NC_64BIT_DATA,
                          MPI_INFO_NULL, &ncid), filename );
 
     // dimensions
@@ -439,14 +430,21 @@ void DumpNetCDFMPIIO::openfile()
     }
 
     // perframe variables
-    for (int i = 0; i < n_perframe; i++) {
-      if (perframe[i].type == THIS_IS_A_BIGINT) {
-        NCERRX( ncmpi_def_var(ncid, perframe[i].name, NC_INT, 1, dims,
-                              &perframe[i].var), perframe[i].name );
-      }
-      else {
-        NCERRX( ncmpi_def_var(ncid, perframe[i].name, NC_DOUBLE, 1, dims,
-                              &perframe[i].var), perframe[i].name );
+    if (thermo) {
+      Thermo *th = output->thermo;
+      for (int i = 0; i < th->nfield; i++) {
+        if (th->vtype[i] == FLOAT) {
+          NCERRX( ncmpi_def_var(ncid, th->keyword[i], NC_DOUBLE, 1, dims,
+                                &thermovar[i]), th->keyword[i] );
+        }
+        else if (th->vtype[i] == INT) {
+          NCERRX( ncmpi_def_var(ncid, th->keyword[i], NC_INT, 1, dims,
+                                &thermovar[i]), th->keyword[i] );
+        }
+        else if (th->vtype[i] == BIGINT) {
+          NCERRX( ncmpi_def_var(ncid, th->keyword[i], NC_LONG, 1, dims,
+                                &thermovar[i]), th->keyword[i] );
+        }
       }
     }
 
@@ -600,50 +598,34 @@ void DumpNetCDFMPIIO::write()
 
   NCERR( ncmpi_begin_indep_data(ncid) );
 
-  for (int i = 0; i < n_perframe; i++) {
-
-    if (perframe[i].type == THIS_IS_A_BIGINT) {
-      bigint data;
-      (this->*perframe[i].compute)((void*) &data);
-
-      if (filewriter)
+  if (thermo) {
+    Thermo *th = output->thermo;
+    for (int i = 0; i < th->nfield; i++) {
+      th->call_vfunc(i);
+      if (filewriter) {
+        if (th->vtype[i] == FLOAT) {
+          NCERRX( ncmpi_put_var1_double(ncid, thermovar[i], start,
+                                        &th->dvalue),
+                  th->keyword[i] );
+        }
+        else if (th->vtype[i] == INT) {
+          NCERRX( ncmpi_put_var1_int(ncid, thermovar[i], start, &th->ivalue),
+                  th->keyword[i] );
+        }
+        else if (th->vtype[i] == BIGINT) {
 #if defined(LAMMPS_SMALLBIG) || defined(LAMMPS_BIGBIG)
-        NCERR( ncmpi_put_var1_long(ncid, perframe[i].var, start, &data) );
+          NCERRX( ncmpi_put_var1_long(ncid, thermovar[i], start, &th->bivalue),
+                  th->keyword[i] );
 #else
-        NCERR( ncmpi_put_var1_int(ncid, perframe[i].var, start, &data) );
+          NCERRX( ncmpi_put_var1_int(ncid, thermovar[i], start, &th->bivalue),
+                  th->keyword[i] );
 #endif
-    }
-    else {
-      double data;
-      int j = perframe[i].index;
-      int idim = perframe[i].dim;
-
-      if (perframe[i].type == THIS_IS_A_COMPUTE) {
-        if (idim >= 0) {
-          modify->compute[j]->compute_vector();
-          data = modify->compute[j]->vector[idim];
-        }
-        else
-          data = modify->compute[j]->compute_scalar();
-      }
-      else if (perframe[i].type == THIS_IS_A_FIX) {
-        if (idim >= 0) {
-          data = modify->fix[j]->compute_vector(idim);
         }
-        else
-          data = modify->fix[j]->compute_scalar();
       }
-      else if (perframe[i].type == THIS_IS_A_VARIABLE) {
-        j = input->variable->find(perframe[i].id);
-        data = input->variable->compute_equal(j);
-      }
-
-      if (filewriter)
-        NCERR( ncmpi_put_var1_double(ncid, perframe[i].var, start, &data) );
     }
   }
 
-  // write timestep header
+ // write timestep header
 
   write_time_and_cell();
 
@@ -903,126 +885,19 @@ int DumpNetCDFMPIIO::modify_param(int narg, char **arg)
     iarg++;
     return 2;
   }
-  else if (strcmp(arg[iarg],"global") == 0) {
-    // "perframe" quantities, i.e. not per-atom stuff
-
+  else if (strcmp(arg[iarg],"thermo") == 0) {
     iarg++;
-
-    n_perframe = narg-iarg;
-    perframe = new nc_perframe_t[n_perframe];
-
-    for (int i = 0; iarg < narg; iarg++, i++) {
-      int n;
-      char *suffix;
-
-      if (!strcmp(arg[iarg],"step")) {
-        perframe[i].type = THIS_IS_A_BIGINT;
-        perframe[i].compute = &DumpNetCDFMPIIO::compute_step;
-        strcpy(perframe[i].name, arg[iarg]);
-      }
-      else if (!strcmp(arg[iarg],"elapsed")) {
-        perframe[i].type = THIS_IS_A_BIGINT;
-        perframe[i].compute = &DumpNetCDFMPIIO::compute_elapsed;
-        strcpy(perframe[i].name, arg[iarg]);
-      }
-      else if (!strcmp(arg[iarg],"elaplong")) {
-        perframe[i].type = THIS_IS_A_BIGINT;
-        perframe[i].compute = &DumpNetCDFMPIIO::compute_elapsed_long;
-        strcpy(perframe[i].name, arg[iarg]);
-      }
-      else {
-
-        n = strlen(arg[iarg]);
-
-        if (n > 2) {
-          suffix = new char[n-1];
-          strcpy(suffix, arg[iarg]+2);
-        }
-        else {
-          char errstr[1024];
-          sprintf(errstr, "perframe quantity '%s' must thermo quantity or "
-                  "compute, fix or variable", arg[iarg]);
-          error->all(FLERR,errstr);
-        }
-
-        if (!strncmp(arg[iarg], "c_", 2)) {
-          int idim = -1;
-          char *ptr = strchr(suffix, '[');
-
-          if (ptr) {
-            if (suffix[strlen(suffix)-1] != ']')
-              error->all(FLERR,"Missing ']' in dump modify command");
-            *ptr = '\0';
-            idim = ptr[1] - '1';
-          }
-
-          n = modify->find_compute(suffix);
-          if (n < 0)
-            error->all(FLERR,"Could not find dump modify compute ID");
-          if (modify->compute[n]->peratom_flag != 0)
-            error->all(FLERR,"Dump modify compute ID computes per-atom info");
-          if (idim >= 0 && modify->compute[n]->vector_flag == 0)
-            error->all(FLERR,"Dump modify compute ID does not compute vector");
-          if (idim < 0 && modify->compute[n]->scalar_flag == 0)
-            error->all(FLERR,"Dump modify compute ID does not compute scalar");
-
-          perframe[i].type = THIS_IS_A_COMPUTE;
-          perframe[i].dim = idim;
-          perframe[i].index = n;
-          strcpy(perframe[i].name, arg[iarg]);
-        }
-        else if (!strncmp(arg[iarg], "f_", 2)) {
-          int idim = -1;
-          char *ptr = strchr(suffix, '[');
-
-          if (ptr) {
-            if (suffix[strlen(suffix)-1] != ']')
-              error->all(FLERR,"Missing ']' in dump modify command");
-            *ptr = '\0';
-            idim = ptr[1] - '1';
-          }
-
-          n = modify->find_fix(suffix);
-          if (n < 0)
-            error->all(FLERR,"Could not find dump modify fix ID");
-          if (modify->fix[n]->peratom_flag != 0)
-            error->all(FLERR,"Dump modify fix ID computes per-atom info");
-          if (idim >= 0 && modify->fix[n]->vector_flag == 0)
-            error->all(FLERR,"Dump modify fix ID does not compute vector");
-          if (idim < 0 && modify->fix[n]->scalar_flag == 0)
-            error->all(FLERR,"Dump modify fix ID does not compute vector");
-
-          perframe[i].type = THIS_IS_A_FIX;
-          perframe[i].dim = idim;
-          perframe[i].index = n;
-          strcpy(perframe[i].name, arg[iarg]);
-        }
-        else if (!strncmp(arg[iarg], "v_", 2)) {
-          n = input->variable->find(suffix);
-          if (n < 0)
-            error->all(FLERR,"Could not find dump modify variable ID");
-          if (!input->variable->equalstyle(n))
-            error->all(FLERR,"Dump modify variable must be of style equal");
-
-          perframe[i].type = THIS_IS_A_VARIABLE;
-          perframe[i].dim = 1;
-          perframe[i].index = n;
-          strcpy(perframe[i].name, arg[iarg]);
-          strcpy(perframe[i].id, suffix);
-        }
-        else {
-          char errstr[1024];
-          sprintf(errstr, "perframe quantity '%s' must be compute, fix or "
-                  "variable", arg[iarg]);
-          error->all(FLERR,errstr);
-        }
-
-        delete [] suffix;
-
-      }
+    if (iarg >= narg)
+      error->all(FLERR,"expected 'yes' or 'no' after 'thermo' keyword.");
+    if (strcmp(arg[iarg],"yes") == 0) {
+      thermo = true;
     }
-
-    return narg;
+    else if (strcmp(arg[iarg],"no") == 0) {
+      thermo = false;
+    }
+    else error->all(FLERR,"expected 'yes' or 'no' after 'thermo' keyword.");
+    iarg++;
+    return 2;
   } else return 0;
 }
 
@@ -1044,31 +919,4 @@ void DumpNetCDFMPIIO::ncerr(int err, const char *descr, int line)
   }
 }
 
-/* ----------------------------------------------------------------------
-   one method for every keyword thermo can output
-   called by compute() or evaluate_keyword()
-   compute will have already been called
-   set ivalue/dvalue/bivalue if value is int/double/bigint
-   customize a new keyword by adding a method
-------------------------------------------------------------------------- */
-
-void DumpNetCDFMPIIO::compute_step(void *r)
-{
-  *((bigint *) r) = update->ntimestep;
-}
-
-/* ---------------------------------------------------------------------- */
-
-void DumpNetCDFMPIIO::compute_elapsed(void *r)
-{
-  *((bigint *) r) = update->ntimestep - update->firststep;
-}
-
-/* ---------------------------------------------------------------------- */
-
-void DumpNetCDFMPIIO::compute_elapsed_long(void *r)
-{
-  *((bigint *) r) = update->ntimestep - update->beginstep;
-}
-
 #endif /* defined(LMP_HAS_PNETCDF) */
diff --git a/src/USER-NETCDF/dump_netcdf_mpiio.h b/src/USER-NETCDF/dump_netcdf_mpiio.h
index 6f5b00b03350f6a08c9c603a01cbae8c49f90e7b..10b0e800d2347d561d42073c1b3c196275fd9ca5 100644
--- a/src/USER-NETCDF/dump_netcdf_mpiio.h
+++ b/src/USER-NETCDF/dump_netcdf_mpiio.h
@@ -1,25 +1,3 @@
-/* ======================================================================
-   LAMMPS NetCDF dump style
-   https://github.com/pastewka/lammps-netcdf
-   Lars Pastewka, lars.pastewka@kit.edu
-
-   Copyright (2011-2013) Fraunhofer IWM
-   Copyright (2014) Karlsruhe Institute of Technology
-
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.
-   ====================================================================== */
-
 /* ----------------------------------------------------------------------
    LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
    http://lammps.sandia.gov, Sandia National Laboratories
@@ -33,6 +11,10 @@
    See the README file in the top-level LAMMPS directory.
 ------------------------------------------------------------------------- */
 
+/* ----------------------------------------------------------------------
+   Contributing author: Lars Pastewka (University of Freiburg)
+------------------------------------------------------------------------- */
+
 #if defined(LMP_HAS_PNETCDF)
 
 #ifdef DUMP_CLASS
@@ -66,21 +48,7 @@ class DumpNetCDFMPIIO : public DumpCustom {
     int var;                            // NetCDF variable
   };
 
-  typedef void (DumpNCMPIIO::*funcptr_t)(void *);
-
-  // per-frame quantities (variables, fixes or computes)
-  struct nc_perframe_t {
-    char name[NC_MPIIO_FIELD_NAME_MAX]; // field name
-    int var;                            // NetCDF variable
-    int type;                           // variable, fix, compute or callback
-    int index;                          // index in fix/compute list
-    funcptr_t compute;                  // compute function
-    int dim;                            // dimension
-    char id[NC_MPIIO_FIELD_NAME_MAX];   // variable id
-
-    bigint bigint_data;                 // actual data
-    double double_data;                 // actual data
-  };
+  typedef void (DumpNetCDFMPIIO::*funcptr_t)(void *);
 
   int framei;                           // current frame index
   int blocki;                           // current block index
@@ -91,10 +59,10 @@ class DumpNetCDFMPIIO : public DumpCustom {
   int n_perat;                          // # of netcdf per-atom properties
   nc_perat_t *perat;                    // per-atom properties
 
-  int n_perframe;                       // # of global netcdf (not per-atom) fix props
-  nc_perframe_t *perframe;              // global properties
+  int *thermovar;                       // NetCDF variables for thermo output
 
   bool double_precision;                // write everything as double precision
+  bool thermo;                          // write thermo output to netcdf file
 
   bigint n_buffer;                      // size of buffer
   int *int_buffer;                      // buffer for passing data to netcdf
@@ -128,10 +96,6 @@ class DumpNetCDFMPIIO : public DumpCustom {
   virtual int modify_param(int, char **);
 
   void ncerr(int, const char *, int);
-
-  void compute_step(void *);
-  void compute_elapsed(void *);
-  void compute_elapsed_long(void *);
 };
 
 }
diff --git a/src/thermo.cpp b/src/thermo.cpp
index 18deecb1a8cb03ff619535f2c53f42dadc4e1d96..d4f7c5cc9e1434e86e8efb45dbcb7c0015ef8a25 100644
--- a/src/thermo.cpp
+++ b/src/thermo.cpp
@@ -402,6 +402,15 @@ void Thermo::compute(int flag)
   firststep = 1;
 }
 
+/* ----------------------------------------------------------------------
+   call function to compute property
+------------------------------------------------------------------------- */
+
+void Thermo::call_vfunc(int ifield)
+{
+  (this->*vfunc[ifield])();
+}
+
 /* ----------------------------------------------------------------------
    check for lost atoms, return current number of atoms
 ------------------------------------------------------------------------- */
diff --git a/src/thermo.h b/src/thermo.h
index d87e8fce3d9e98cb26be277ea9aeeaf5e2f6984f..de2a46dec42f3a87c90c9fd7cac184a178c652ef 100644
--- a/src/thermo.h
+++ b/src/thermo.h
@@ -18,8 +18,13 @@
 
 namespace LAMMPS_NS {
 
+class DumpNetCDF;
+class DumpNetCDFMPIIO;
+
 class Thermo : protected Pointers {
   friend class MinCG;                  // accesses compute_pe
+  friend class DumpNetCDF;             // accesses thermo properties
+  friend class DumpNetCDFMPIIO;        // accesses thermo properties
 
  public:
   char *style;
@@ -112,6 +117,7 @@ class Thermo : protected Pointers {
   typedef void (Thermo::*FnPtr)();
   void addfield(const char *, FnPtr, int);
   FnPtr *vfunc;                // list of ptrs to functions
+  void call_vfunc(int ifield);
 
   void compute_compute();      // functions that compute a single value
   void compute_fix();          // via calls to  Compute,Fix,Variable classes