diff --git a/lib/netcdf/Makefile.lammps b/lib/netcdf/Makefile.lammps
new file mode 100644
index 0000000000000000000000000000000000000000..3da0bebea4a30cf43d490e3264055749f32ec445
--- /dev/null
+++ b/lib/netcdf/Makefile.lammps
@@ -0,0 +1,19 @@
+# Settings that the LAMMPS build will import when a package using the
+# netCDF library is installed. This tries to automate configuration
+# via the nc-config tool, which is part of the netCDF installation.
+
+ifeq ($(shell nc-config --has-pnetcdf),no)
+
+netcdf_SYSINC = $(shell nc-config --cflags)
+netcdf_SYSLIB = $(shell nc-config --libs)
+netcdf_SYSPATH =
+
+endif
+
+ifeq ($(shell nc-config --has-pnetcdf),yes)
+
+netcdf_SYSINC = -DLMP_HAS_PNETCDF $(nc-config --cflags)
+netcdf_SYSLIB = $(shell nc-config --libs)
+netcdf_SYSPATH =
+
+endif
diff --git a/src/Makefile b/src/Makefile
index 12466e01fa58b9bec6b7032cd64e103eb8be5f33..1e9d3dc86d4ad8c0e16135bbbeee804a114c40c6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -57,7 +57,7 @@ PACKUSER = user-atc user-awpmd user-cg-cmm user-colvars \
 
 PACKLIB = compress gpu kim kokkos meam mpiio poems python reax voronoi \
 	  user-atc user-awpmd user-colvars user-h5md user-lb user-molfile \
-	  user-qmmm user-quip user-vtk
+	  user-nc-dump user-qmmm user-quip user-vtk
 
 PACKALL = $(PACKAGE) $(PACKUSER)
 
diff --git a/src/USER-NC-DUMP/Install.sh b/src/USER-NC-DUMP/Install.sh
new file mode 100644
index 0000000000000000000000000000000000000000..37ebd0a0a5b5abda1dfe33545f899e5c46a5afaf
--- /dev/null
+++ b/src/USER-NC-DUMP/Install.sh
@@ -0,0 +1,63 @@
+# Install/unInstall package files in LAMMPS
+# mode = 0/1/2 for uninstall/install/update
+
+mode=$1
+
+# enforce using portable C locale
+LC_ALL=C
+export LC_ALL
+
+# arg1 = file, arg2 = file it depends on
+
+action () {
+  if (test $mode = 0) then
+    rm -f ../$1
+  elif (! cmp -s $1 ../$1) then
+    if (test -z "$2" || test -e ../$2) then
+      cp $1 ..
+      if (test $mode = 2) then
+        echo "  updating src/$1"
+      fi
+    fi
+  elif (test -n "$2") then
+    if (test ! -e ../$2) then
+      rm -f ../$1
+    fi
+  fi
+}
+
+for file in *.cpp *.h; do
+  action $file
+done
+
+# edit 2 Makefile.package files to include/exclude package info
+
+if (test $1 = 1) then
+
+  if (test -e ../Makefile.package) then
+    sed -i -e 's/[^ \t]*netcdf[^ \t]* //g' ../Makefile.package
+    sed -i -e 's|^PKG_SYSINC =[ \t]*|&$(netcdf_SYSINC) |' ../Makefile.package
+    sed -i -e 's|^PKG_SYSLIB =[ \t]*|&$(netcdf_SYSLIB) |' ../Makefile.package
+    sed -i -e 's|^PKG_SYSPATH =[ \t]*|&$(netcdf_SYSPATH) |' ../Makefile.package
+  fi
+
+  if (test -e ../Makefile.package.settings) then
+    sed -i -e '/^include.*netcdf.*$/d' ../Makefile.package.settings
+    # multiline form needed for BSD sed on Macs
+    sed -i -e '4 i \
+include ..\/..\/lib\/netcdf\/Makefile.lammps
+' ../Makefile.package.settings
+
+  fi
+
+elif (test $1 = 0) then
+
+  if (test -e ../Makefile.package) then
+    sed -i -e 's/[^ \t]*netcdf[^ \t]* //g' ../Makefile.package
+  fi
+
+  if (test -e ../Makefile.package.settings) then
+    sed -i -e '/^include.*netcdf.*$/d' ../Makefile.package.settings
+  fi
+
+fi
diff --git a/src/USER-NC-DUMP/README b/src/USER-NC-DUMP/README
new file mode 100644
index 0000000000000000000000000000000000000000..fc7c8df121fad3551106c83980d114171d56e74c
--- /dev/null
+++ b/src/USER-NC-DUMP/README
@@ -0,0 +1,37 @@
+USER-NC-DUMP
+============
+
+This package provides the nc and (optionally) the nc/mpiio dump styles.
+
+PACKAGE DESCRIPTION
+-------------------
+
+This is a LAMMPS (http://lammps.sandia.gov/) dump style for output into a NetCDF
+database. The database format follows the AMBER NetCDF trajectory convention
+(http://ambermd.org/netcdf/nctraj.xhtml), but includes extensions to this
+convention. These extension are:
+* A variable "cell_origin" (of dimension "frame", "cell_spatial") that contains
+  the bottom left corner of the simulation cell.
+* Any number of additional variables corresponding to per atom scalar, vector
+  or tensor quantities available within LAMMPS. Tensor quantities are written in
+  Voigt notation. An additional dimension "Voigt" of length 6 is created for
+  this purpose.
+* Possibility to output to an HDF5 database.
+
+NetCDF files can be directly visualized with the following tools:
+* Ovito (http://www.ovito.org/). Ovito supports the AMBER convention and all of
+  the above extensions.
+* VMD (http://www.ks.uiuc.edu/Research/vmd/).
+* AtomEye (http://www.libatoms.org/). The libAtoms version of AtomEye contains
+  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).
+Contact him directly if you have questions.
+
+Lars Pastewka  
+Institute for Applied Materials (IAM)  
+Karlsruhe Institute of Technology (KIT)  
+Kaiserstraße 12, 76131 Karlsruhe  
+e-mail: lars.pastewka@kit.edu
+
diff --git a/src/USER-NC-DUMP/dump_nc.cpp b/src/USER-NC-DUMP/dump_nc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5dd483660cd847c1ec1f87b1758ef89ebdec1dbb
--- /dev/null
+++ b/src/USER-NC-DUMP/dump_nc.cpp
@@ -0,0 +1,1144 @@
+/* ======================================================================
+   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
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under 
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#include <unistd.h>
+
+#include <netcdf.h>
+
+#include "atom.h"
+#include "comm.h"
+#include "compute.h"
+#include "domain.h"
+#include "error.h"
+#include "fix.h"
+#include "group.h"
+#include "input.h"
+#include "math_const.h"
+#include "memory.h"
+#include "modify.h"
+#include "stdlib.h"
+#include "string.h"
+#include "update.h"
+#include "universe.h"
+#include "variable.h"
+#include "force.h"
+
+#include "dump_nc.h"
+
+using namespace LAMMPS_NS;
+using namespace MathConst;
+
+enum{INT,DOUBLE};  // same as in dump_custom.cpp
+
+const char NC_FRAME_STR[]         = "frame";
+const char NC_SPATIAL_STR[]       = "spatial";
+const char NC_VOIGT_STR[]         = "Voigt";
+const char NC_ATOM_STR[]          = "atom";
+const char NC_CELL_SPATIAL_STR[]  = "cell_spatial";
+const char NC_CELL_ANGULAR_STR[]  = "cell_angular";
+const char NC_LABEL_STR[]         = "label";
+
+const char NC_TIME_STR[]          = "time";
+const char NC_CELL_ORIGIN_STR[]   = "cell_origin";
+const char NC_CELL_LENGTHS_STR[]  = "cell_lengths";
+const char NC_CELL_ANGLES_STR[]   = "cell_angles";
+
+const char NC_UNITS_STR[]         = "units";
+const char NC_SCALE_FACTOR_STR[]  = "scale_factor";
+
+const int THIS_IS_A_FIX      = -1;
+const int THIS_IS_A_COMPUTE  = -2;
+const int THIS_IS_A_VARIABLE = -3;
+const int THIS_IS_A_BIGINT   = -4;
+
+/* ---------------------------------------------------------------------- */
+
+#define NCERR(x) ncerr(x, NULL, __LINE__)
+#define NCERRX(x, descr) ncerr(x, descr, __LINE__)
+
+/* ---------------------------------------------------------------------- */
+
+DumpNC::DumpNC(LAMMPS *lmp, int narg, char **arg) :
+  DumpCustom(lmp, narg, arg)
+{
+  // arrays for data rearrangement
+
+  sort_flag = 1;
+  sortcol = 0;
+  binary = 1;
+  flush_flag = 0;
+
+  if (multiproc)
+    error->all(FLERR,"Multi-processor writes are not supported.");
+  if (multifile)
+    error->all(FLERR,"Multiple files are not supported.");
+
+  perat = new nc_perat_t[nfield];
+
+  for (int i = 0; i < nfield; i++) {
+    perat[i].dims = 0;
+  }
+
+  n_perat = 0;
+  for (int iarg = 5; iarg < narg; iarg++) {
+    int i = iarg-5;
+    int idim = 0;
+    int ndims = 1;
+    char mangled[1024];
+    bool constant = false;
+
+    strcpy(mangled, arg[iarg]);
+
+    // name mangling
+    // in the AMBER specification
+    if (!strcmp(mangled, "x") || !strcmp(mangled, "y") ||
+        !strcmp(mangled, "z")) {
+      idim = mangled[0] - 'x';
+      ndims = 3;
+      strcpy(mangled, "coordinates");
+    }
+    else if (!strcmp(mangled, "vx") || !strcmp(mangled, "vy") ||
+             !strcmp(mangled, "vz")) {
+      idim = mangled[1] - 'x';
+      ndims = 3;
+      strcpy(mangled, "velocities");
+    }
+    // extensions to the AMBER specification
+    else if (!strcmp(mangled, "type")) {
+      strcpy(mangled, "atom_types");
+    }
+    else if (!strcmp(mangled, "xs") || !strcmp(mangled, "ys") ||
+             !strcmp(mangled, "zs")) {
+      idim = mangled[0] - 'x';
+      ndims = 3;
+      strcpy(mangled, "scaled_coordinates");
+    }
+    else if (!strcmp(mangled, "xu") || !strcmp(mangled, "yu") ||
+             !strcmp(mangled, "zu")) {
+      idim = mangled[0] - 'x';
+      ndims = 3;
+      strcpy(mangled, "unwrapped_coordinates");
+    }
+    else if (!strcmp(mangled, "fx") || !strcmp(mangled, "fy") ||
+             !strcmp(mangled, "fz")) {
+      idim = mangled[1] - 'x';
+      ndims = 3;
+      strcpy(mangled, "forces");
+    }
+    else if (!strcmp(mangled, "mux") || !strcmp(mangled, "muy") ||
+             !strcmp(mangled, "muz")) {
+      idim = mangled[2] - 'x';
+      ndims = 3;
+      strcpy(mangled, "mu");
+    }
+    else if (!strncmp(mangled, "c_", 2)) {
+      char *ptr = strchr(mangled, '[');
+      if (ptr) {
+        if (mangled[strlen(mangled)-1] != ']')
+          error->all(FLERR,"Missing ']' in dump command");
+        *ptr = '\0';
+        idim = ptr[1] - '1';
+        ndims = THIS_IS_A_COMPUTE;
+      }
+    }
+    else if (!strncmp(mangled, "f_", 2)) {
+      char *ptr = strchr(mangled, '[');
+      if (ptr) {
+        if (mangled[strlen(mangled)-1] != ']')
+          error->all(FLERR,"Missing ']' in dump command");
+        *ptr = '\0';
+        idim = ptr[1] - '1';
+        ndims = THIS_IS_A_FIX;
+      }
+    }
+
+    // find mangled name
+    int inc = -1;
+    for (int j = 0; j < n_perat && inc < 0; j++) {
+      if (!strcmp(perat[j].name, mangled)) {
+        inc = j;
+      }
+    }
+
+    if (inc < 0) {
+      // this has not yet been defined
+      inc = n_perat;
+      perat[inc].dims = ndims;
+      if (ndims < 0) ndims = DUMP_NC_MAX_DIMS;
+      for (int j = 0; j < DUMP_NC_MAX_DIMS; j++) {
+        perat[inc].field[j] = -1;
+      }
+      strcpy(perat[inc].name, mangled);
+      n_perat++;
+    }
+
+    perat[inc].constant = constant;
+    perat[inc].ndumped = 0;
+    perat[inc].field[idim] = i;
+  }
+
+  n_perframe = 0;
+  perframe = NULL;
+
+  n_buffer = 0;
+  int_buffer = NULL;
+  double_buffer = NULL;
+
+  double_precision = false;
+
+  framei = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+DumpNC::~DumpNC()
+{
+  closefile();
+
+  delete [] perat;
+  if (n_perframe > 0)
+    delete [] perframe;
+
+  if (int_buffer) memory->sfree(int_buffer);
+  if (double_buffer) memory->sfree(double_buffer);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::openfile()
+{
+  // 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++) {
+    if (perat[i].dims == THIS_IS_A_COMPUTE) {
+      int j = -1;
+      for (int k = 0; k < DUMP_NC_MAX_DIMS; k++) {
+        if (perat[i].field[k] >= 0) {
+          j = field2index[perat[i].field[0]];
+        }
+      }
+      if (j < 0)
+        error->all(FLERR,"Internal error.");
+      if (!compute[j]->peratom_flag)
+        error->all(FLERR,"compute does not provide per atom data");
+      perat[i].dims = compute[j]->size_peratom_cols;
+      if (perat[i].dims > DUMP_NC_MAX_DIMS)
+        error->all(FLERR,"perat[i].dims > DUMP_NC_MAX_DIMS");
+    }
+    else if (perat[i].dims == THIS_IS_A_FIX) {
+      int j = -1;
+      for (int k = 0; k < DUMP_NC_MAX_DIMS; k++) {
+        if (perat[i].field[k] >= 0) {
+          j = field2index[perat[i].field[0]];
+        }
+      }
+      if (j < 0)
+        error->all(FLERR,"Internal error.");
+      if (!fix[j]->peratom_flag)
+        error->all(FLERR,"fix does not provide per atom data");
+      perat[i].dims = fix[j]->size_peratom_cols;
+      if (perat[i].dims > DUMP_NC_MAX_DIMS)
+        error->all(FLERR,"perat[i].dims > DUMP_NC_MAX_DIMS");
+    }
+  }
+
+  // get total number of atoms
+  ntotalgr = group->count(igroup);
+
+  if (filewriter) {
+    if (append_flag && access(filename, F_OK) != -1) {
+      // Fixme! Perform checks if dimensions and variables conform with
+      // data structure standard.
+
+      size_t index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
+      double d[1];
+
+      if (singlefile_opened) return;
+      singlefile_opened = 1;
+
+      NCERRX( nc_open(filename, NC_WRITE, &ncid), filename );
+    
+      // 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 );
+      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 );
+      NCERRX( nc_inq_dimid(ncid, NC_CELL_ANGULAR_STR, &cell_angular_dim),
+	      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 );
+      NCERRX( nc_inq_varid(ncid, NC_CELL_SPATIAL_STR, &cell_spatial_var),
+	      NC_CELL_SPATIAL_STR);
+      NCERRX( nc_inq_varid(ncid, NC_CELL_ANGULAR_STR, &cell_angular_var),
+	      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 );
+      NCERRX( nc_inq_varid(ncid, NC_CELL_LENGTHS_STR, &cell_lengths_var),
+	      NC_CELL_LENGTHS_STR);
+      NCERRX( nc_inq_varid(ncid, NC_CELL_ANGLES_STR, &cell_angles_var),
+	      NC_CELL_ANGLES_STR);
+
+      // variables specified in the input file
+      for (int i = 0; i < n_perat; i++) {
+        nc_type xtype;
+
+        // Type mangling
+        if (vtype[perat[i].field[0]] == INT) {
+          xtype = NC_INT;
+        }
+        else {
+          if (double_precision)
+            xtype = NC_DOUBLE;
+          else
+            xtype = NC_FLOAT;
+        }
+    
+        NCERRX( nc_inq_varid(ncid, perat[i].name, &perat[i].var),
+                perat[i].name );
+      }
+
+      // perframe variables
+      for (int i = 0; i < n_perframe; i++) {
+        NCERRX( nc_inq_varid(ncid, perframe[i].name, &perframe[i].var),
+                perframe[i].name );
+      }
+    
+      size_t nframes;
+      NCERR( nc_inq_dimlen(ncid, frame_dim, &nframes) );
+      // framei == -1 means append to file, == -2 means override last frame
+      // Note that in the input file this translates to 'yes', '-1', etc.
+      if (framei < 0 || (append_flag && framei == 0))  framei = nframes+framei+1;
+      if (framei < 1)  framei = 1;
+    }
+    else {
+      int dims[NC_MAX_VAR_DIMS];
+      size_t index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
+      double d[1];
+
+      if (singlefile_opened) return;
+      singlefile_opened = 1;
+
+      NCERRX( nc_create(filename, NC_64BIT_OFFSET, &ncid),
+	      filename );
+    
+      // dimensions
+      NCERRX( nc_def_dim(ncid, NC_FRAME_STR, NC_UNLIMITED, &frame_dim),
+	      NC_FRAME_STR );
+      NCERRX( nc_def_dim(ncid, NC_SPATIAL_STR, 3, &spatial_dim),
+	      NC_SPATIAL_STR );
+      NCERRX( nc_def_dim(ncid, NC_VOIGT_STR, 6, &Voigt_dim),
+	      NC_VOIGT_STR );
+      NCERRX( nc_def_dim(ncid, NC_ATOM_STR, ntotalgr, &atom_dim),
+	      NC_ATOM_STR );
+      NCERRX( nc_def_dim(ncid, NC_CELL_SPATIAL_STR, 3, &cell_spatial_dim),
+	      NC_CELL_SPATIAL_STR );
+      NCERRX( nc_def_dim(ncid, NC_CELL_ANGULAR_STR, 3, &cell_angular_dim),
+	      NC_CELL_ANGULAR_STR );
+      NCERRX( nc_def_dim(ncid, NC_LABEL_STR, 10, &label_dim),
+	      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 );
+      NCERRX( nc_def_var(ncid, NC_CELL_SPATIAL_STR, NC_CHAR, 1, dims,
+			 &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 );
+      
+      dims[0] = frame_dim;
+      NCERRX( nc_def_var(ncid, NC_TIME_STR, NC_DOUBLE, 1, dims, &time_var),
+	      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 );
+      NCERRX( nc_def_var(ncid, NC_CELL_LENGTHS_STR, NC_DOUBLE, 2, dims,
+			 &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 );
+
+      // variables specified in the input file
+      dims[0] = frame_dim;
+      dims[1] = atom_dim;
+      dims[2] = spatial_dim;
+
+      for (int i = 0; i < n_perat; i++) {
+        nc_type xtype;
+
+        // Type mangling
+        if (vtype[perat[i].field[0]] == INT) {
+          xtype = NC_INT;
+        }
+        else {
+          if (double_precision)
+            xtype = NC_DOUBLE;
+          else
+            xtype = NC_FLOAT;
+        }
+    
+        if (perat[i].constant) {
+          // this quantity will only be written once
+          if (perat[i].dims == 6) {
+            // 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 );
+          }
+          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 );
+          }
+          else if (perat[i].dims == 1) {
+            NCERRX( nc_def_var(ncid, perat[i].name, xtype, 1, dims+1,
+			       &perat[i].var), perat[i].name );
+          }
+          else {
+            char errstr[1024];
+            sprintf(errstr, "%i dimensions for '%s'. Not sure how to write "
+                    "this to the NetCDF trajectory file.", perat[i].dims,
+                    perat[i].name);
+            error->all(FLERR,errstr);
+          }
+        }
+        else {
+          if (perat[i].dims == 6) {
+            // 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 );
+          }
+          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 );
+          }
+          else if (perat[i].dims == 1) {
+            NCERRX( nc_def_var(ncid, perat[i].name, xtype, 2, dims,
+			       &perat[i].var), perat[i].name );
+          }
+          else {
+            char errstr[1024];
+            sprintf(errstr, "%i dimensions for '%s'. Not sure how to write "
+                    "this to the NetCDF trajectory file.", perat[i].dims,
+                    perat[i].name);
+            error->all(FLERR,errstr);
+          }
+        }
+      }
+
+      // 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 );
+        }
+      }
+
+      // attributes
+      NCERR( nc_put_att_text(ncid, NC_GLOBAL, "Conventions",
+                 5, "AMBER") );
+      NCERR( nc_put_att_text(ncid, NC_GLOBAL, "ConventionVersion",
+                 3, "1.0") );
+      
+      NCERR( nc_put_att_text(ncid, NC_GLOBAL, "program",
+                 6, "LAMMPS") );
+      NCERR( nc_put_att_text(ncid, NC_GLOBAL, "programVersion",
+                 strlen(universe->version), universe->version) );
+
+      // units
+      if (!strcmp(update->unit_style, "lj")) {
+        NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR,
+                               2, "lj") );
+        NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                               2, "lj") );
+        NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                               2, "lj") );
+      }
+      else if (!strcmp(update->unit_style, "real")) {
+        NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR,
+                               11, "femtosecond") );
+        NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                               8, "Angstrom") );
+        NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                               8, "Angstrom") );
+      }
+      else if (!strcmp(update->unit_style, "metal")) {
+        NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR,
+                               10, "picosecond") );
+        NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                               8, "Angstrom") );
+        NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                               8, "Angstrom") );
+      }
+      else if (!strcmp(update->unit_style, "si")) {
+        NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR,
+                               6, "second") );
+        NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                               5, "meter") );
+        NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                               5, "meter") );
+      }
+      else if (!strcmp(update->unit_style, "cgs")) {
+        NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR,
+                               6, "second") );
+        NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                               10, "centimeter") );
+        NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                               10, "centimeter") );
+      }
+      else if (!strcmp(update->unit_style, "electron")) {
+        NCERR( nc_put_att_text(ncid, time_var, NC_UNITS_STR,
+                               11, "femtosecond") );
+        NCERR( nc_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                               4, "Bohr") );
+        NCERR( nc_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                               4, "Bohr") );
+      }
+      else {
+        char errstr[1024];
+        sprintf(errstr, "Unsupported unit style '%s'", update->unit_style);
+        error->all(FLERR,errstr);
+      }
+      
+      NCERR( nc_put_att_text(ncid, cell_angles_var, NC_UNITS_STR,
+                             6, "degree") );
+
+      d[0] = update->dt;
+      NCERR( nc_put_att_double(ncid, time_var, NC_SCALE_FACTOR_STR,
+                               NC_DOUBLE, 1, d) );
+      d[0] = 1.0;
+      NCERR( nc_put_att_double(ncid, cell_origin_var, NC_SCALE_FACTOR_STR,
+                               NC_DOUBLE, 1, d) );
+      d[0] = 1.0;
+      NCERR( nc_put_att_double(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR,
+                               NC_DOUBLE, 1, d) );
+      
+      /*
+       * Finished with definition
+       */
+      
+      NCERR( nc_enddef(ncid) );
+
+      /*
+       * Write label variables
+       */
+      
+      NCERR( nc_put_var_text(ncid, spatial_var, "xyz") );
+      NCERR( nc_put_var_text(ncid, cell_spatial_var, "abc") );
+      index[0] = 0;
+      index[1] = 0;
+      count[0] = 1;
+      count[1] = 5;
+      NCERR( nc_put_vara_text(ncid, cell_angular_var, index, count, "alpha") );
+      index[0] = 1;
+      count[1] = 4;
+      NCERR( nc_put_vara_text(ncid, cell_angular_var, index, count, "beta") );
+      index[0] = 2;
+      count[1] = 5;
+      NCERR( nc_put_vara_text(ncid, cell_angular_var, index, count, "gamma") );
+    
+      framei = 1;
+    }
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::closefile()
+{
+  if (filewriter && singlefile_opened) {
+    NCERR( nc_close(ncid) );
+    singlefile_opened = 0;
+    // append next time DumpNC::openfile is called
+    append_flag = 1;
+    // write to next frame upon next open
+    framei++;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::write()
+{
+  // open file
+
+  openfile();
+
+  // need to write per-frame (global) properties here since they may come
+  // from computes. write_header below is only called from the writing
+  // processes, but modify->compute[j]->compute_* must be called from all
+  // processes.
+
+  size_t start[2];
+
+  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 defined(LAMMPS_SMALLBIG) || defined(LAMMPS_BIGBIG)
+        NCERR( nc_put_var1_long(ncid, perframe[i].var, start, &data) );
+#else
+        NCERR( nc_put_var1_int(ncid, perframe[i].var, start, &data) );
+#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) );
+    }
+  }
+
+  // call write of superclass
+
+  Dump::write();
+
+  // close file. this ensures data is flushed and mimized data corruption
+
+  closefile();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::write_header(bigint n)
+{
+  size_t start[2];
+
+  start[0] = framei-1;
+  start[1] = 0;
+
+  if (filewriter) {
+    size_t count[2];
+    double time, cell_origin[3], cell_lengths[3], cell_angles[3];
+
+    time = update->ntimestep;
+    if (domain->triclinic == 0) {
+      cell_origin[0] = domain->boxlo[0];
+      cell_origin[1] = domain->boxlo[1];
+      cell_origin[2] = domain->boxlo[2];
+
+      cell_lengths[0] = domain->xprd;
+      cell_lengths[1] = domain->yprd;
+      cell_lengths[2] = domain->zprd;
+
+      cell_angles[0] = 90;
+      cell_angles[1] = 90;
+      cell_angles[2] = 90;
+    }
+    else {
+      double cosalpha, cosbeta, cosgamma;
+      double *h = domain->h;
+
+      cell_origin[0] = domain->boxlo[0];
+      cell_origin[1] = domain->boxlo[1];
+      cell_origin[2] = domain->boxlo[2];
+
+      cell_lengths[0] = domain->xprd;
+      cell_lengths[1] = sqrt(h[1]*h[1]+h[5]*h[5]);
+      cell_lengths[2] = sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]);
+
+      cosalpha = (h[5]*h[4]+h[1]*h[3])/
+          sqrt((h[1]*h[1]+h[5]*h[5])*(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]));
+      cosbeta = h[4]/sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]);
+      cosgamma = h[5]/sqrt(h[1]*h[1]+h[5]*h[5]);
+
+      cell_angles[0] = acos(cosalpha)*180.0/MY_PI;
+      cell_angles[1] = acos(cosbeta)*180.0/MY_PI;
+      cell_angles[2] = acos(cosgamma)*180.0/MY_PI;
+    }
+
+    // Recent AMBER conventions say that nonperiodic boundaries should have
+    // 'cell_lengths' set to zero.
+    for (int dim = 0; dim < 3; dim++) {
+        if (!domain->periodicity[dim])
+            cell_lengths[dim] = 0.0;
+    }
+
+    count[0] = 1;
+    count[1] = 3;
+    NCERR( nc_put_var1_double(ncid, time_var, start, &time) );
+    NCERR( nc_put_vara_double(ncid, cell_origin_var, start, count,
+                              cell_origin) );
+    NCERR( nc_put_vara_double(ncid, cell_lengths_var, start, count,
+                              cell_lengths) );
+    NCERR( nc_put_vara_double(ncid, cell_angles_var, start, count,
+                              cell_angles) );
+  }
+
+  ndata = n;
+  blocki = 0;
+}
+
+
+/* ----------------------------------------------------------------------
+   write data lines to file in a block-by-block style
+   write head of block (mass & element name) only if has atoms of the type
+------------------------------------------------------------------------- */
+
+void DumpNC::write_data(int n, double *mybuf)
+{
+  size_t start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
+  ptrdiff_t stride[NC_MAX_VAR_DIMS];
+
+  if (!int_buffer) {
+    n_buffer = n;
+    int_buffer = (int *)
+      memory->smalloc(n*sizeof(int), "DumpNC::int_buffer");
+    double_buffer = (double *)
+      memory->smalloc(n*sizeof(double), "DumpNC::double_buffer");
+  }
+
+  if (n > n_buffer) {
+    n_buffer = n;
+    int_buffer = (int *)
+      memory->srealloc(int_buffer, n*sizeof(int), "DumpNC::int_buffer");
+    double_buffer = (double *)
+      memory->srealloc(double_buffer, n*sizeof(double),
+                       "DumpNC::double_buffer");
+  }
+
+  start[0] = framei-1;
+  start[1] = blocki;
+  start[2] = 0;
+
+  count[0] = 1;
+  count[1] = n;
+  count[2] = 1;
+
+  stride[0] = 1;
+  stride[1] = 1;
+  stride[2] = 3;
+
+  for (int i = 0; i < n_perat; i++) {
+    int iaux = perat[i].field[0];
+
+    if (vtype[iaux] == INT) {
+      // integers
+      if (perat[i].dims > 1) {
+
+        for (int idim = 0; idim < perat[i].dims; idim++) {
+          iaux = perat[i].field[idim];
+
+          if (iaux >= 0) {
+            for (int j = 0; j < n; j++, iaux+=size_one) {
+              int_buffer[j] = mybuf[iaux];
+            }
+      
+            start[2] = idim;
+
+            if (perat[i].constant) {
+              if (perat[i].ndumped < ntotalgr) {
+                NCERR( nc_put_vars_int(ncid, perat[i].var,
+                                       start+1, count+1, stride+1,
+                                       int_buffer) );
+                perat[i].ndumped += n;
+              }
+            }
+            else
+              NCERR( nc_put_vars_int(ncid, perat[i].var, start, count, stride,
+                                     int_buffer) );
+          }
+        }
+      }
+      else {
+        for (int j = 0; j < n; j++, iaux+=size_one) {
+            int_buffer[j] = mybuf[iaux];
+        }
+
+        if (perat[i].constant) {
+          if (perat[i].ndumped < ntotalgr) {
+            NCERR( nc_put_vara_int(ncid, perat[i].var, start+1, count+1,
+                                   int_buffer) );
+            perat[i].ndumped += n;
+          }
+        }
+        else
+          NCERR( nc_put_vara_int(ncid, perat[i].var, start, count,
+                                 int_buffer) );
+      }
+    }
+    else {
+      // doubles
+      if (perat[i].dims > 1) {
+
+        for (int idim = 0; idim < perat[i].dims; idim++) {
+          iaux = perat[i].field[idim];
+
+          if (iaux >= 0) {
+            for (int j = 0; j < n; j++, iaux+=size_one) {
+                double_buffer[j] = mybuf[iaux];
+            }
+      
+            start[2] = idim;
+
+            if (perat[i].constant) {
+              if (perat[i].ndumped < ntotalgr) {
+                  NCERR( nc_put_vars_double(ncid, perat[i].var,
+                                            start+1, count+1, stride+1,
+                                            double_buffer) );
+                  perat[i].ndumped += n;
+              }
+            }
+            else
+              NCERR( nc_put_vars_double(ncid, perat[i].var, start, count,
+                                        stride, double_buffer) );
+          }
+        }
+      }
+      else {
+        for (int j = 0; j < n; j++, iaux+=size_one) {
+            double_buffer[j] = mybuf[iaux];
+        }
+
+        if (perat[i].constant) {
+          if (perat[i].ndumped < ntotalgr) {
+            NCERR( nc_put_vara_double(ncid, perat[i].var, start+1, count+1,
+                                      double_buffer) );
+            perat[i].ndumped += n;
+          }
+        }
+        else
+          NCERR( nc_put_vara_double(ncid, perat[i].var, start, count,
+                                    double_buffer) );
+      }
+    }
+  }
+
+  blocki += n;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int DumpNC::modify_param(int narg, char **arg)
+{
+  int iarg = 0;
+  if (strcmp(arg[iarg],"double") == 0) {
+    iarg++;
+    if (iarg >= narg)
+      error->all(FLERR,"expected 'yes' or 'no' after 'double' keyword.");
+    if (strcmp(arg[iarg],"yes") == 0) {
+      double_precision = true;
+    }
+    else if (strcmp(arg[iarg],"no") == 0) {
+      double_precision = false;
+    }
+    else error->all(FLERR,"expected 'yes' or 'no' after 'double' keyword.");
+    iarg++;
+    return 2;
+  }
+  else if (strcmp(arg[iarg],"at") == 0) {
+    iarg++;
+    framei = force->inumeric(FLERR,arg[iarg]);
+    if (framei < 0)  framei--;
+    iarg++;
+    return 2;
+  }
+  else if (strcmp(arg[iarg],"global") == 0) {
+    // "perframe" quantities, i.e. not per-atom stuff
+
+    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 = &DumpNC::compute_step;
+        strcpy(perframe[i].name, arg[iarg]);
+      }
+      else if (!strcmp(arg[iarg],"elapsed")) {
+        perframe[i].type = THIS_IS_A_BIGINT;
+        perframe[i].compute = &DumpNC::compute_elapsed;
+        strcpy(perframe[i].name, arg[iarg]);
+      }
+      else if (!strcmp(arg[iarg],"elaplong")) {
+        perframe[i].type = THIS_IS_A_BIGINT;
+        perframe[i].compute = &DumpNC::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;
+    
+      }
+    }
+
+    return narg;
+  } else return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::write_prmtop()
+{
+  char fn[1024];
+  char tmp[81];
+  FILE *f;
+
+  strcpy(fn, filename);
+  strcat(fn, ".prmtop");
+
+  f = fopen(fn, "w");
+  fprintf(f, "%%VERSION  LAMMPS\n");
+  fprintf(f, "%%FLAG TITLE\n");
+  fprintf(f, "%%FORMAT(20a4)\n");
+  memset(tmp, ' ', 76);
+  tmp[76] = '\0';
+  fprintf(f, "NASN%s\n", tmp);
+
+  fprintf(f, "%%FLAG POINTERS\n");
+  fprintf(f, "%%FORMAT(10I8)\n");
+#if defined(LAMMPS_SMALLBIG) || defined(LAMMPS_BIGBIG)
+  fprintf(f, "%8li", ntotalgr);
+#else
+  fprintf(f, "%8i", ntotalgr);
+#endif
+  for (int i = 0; i < 11; i++)
+    fprintf(f, "%8i", 0);
+  fprintf(f, "\n");
+  for (int i = 0; i < 12; i++)
+    fprintf(f, "%8i", 0);
+  fprintf(f, "\n");
+  for (int i = 0; i < 6; i++)
+    fprintf(f, "%8i", 0);
+  fprintf(f, "\n");
+
+  fprintf(f, "%%FLAG ATOM_NAME\n");
+  fprintf(f, "%%FORMAT(20a4)\n");
+  for (int i = 0; i < ntotalgr; i++) {
+    fprintf(f, "%4s", "He");
+    if ((i+1) % 20 == 0)
+      fprintf(f, "\n");
+  }
+
+  fprintf(f, "%%FLAG CHARGE\n");
+  fprintf(f, "%%FORMAT(5E16.5)\n");
+  for (int i = 0; i < ntotalgr; i++) {
+    fprintf(f, "%16.5e", 0.0);
+    if ((i+1) % 5 == 0)
+      fprintf(f, "\n");
+  }
+
+  fprintf(f, "%%FLAG MASS\n");
+  fprintf(f, "%%FORMAT(5E16.5)\n");
+  for (int i = 0; i < ntotalgr; i++) {
+    fprintf(f, "%16.5e", 1.0);
+    if ((i+1) % 5 == 0)
+        fprintf(f, "\n");
+  }
+  fclose(f);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::ncerr(int err, const char *descr, int line)
+{
+  if (err != NC_NOERR) {
+    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__);
+    }
+    else {
+      sprintf(errstr, "NetCDF failed with error '%s' in line %i of %s.",
+	      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 DumpNC::compute_step(void *r)
+{
+  *((bigint *) r) = update->ntimestep;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::compute_elapsed(void *r)
+{
+  *((bigint *) r) = update->ntimestep - update->firststep;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNC::compute_elapsed_long(void *r)
+{
+  *((bigint *) r) = update->ntimestep - update->beginstep;
+}
diff --git a/src/USER-NC-DUMP/dump_nc.h b/src/USER-NC-DUMP/dump_nc.h
new file mode 100644
index 0000000000000000000000000000000000000000..75236c15a12f9d5ff1d539142fbc383e7417aea1
--- /dev/null
+++ b/src/USER-NC-DUMP/dump_nc.h
@@ -0,0 +1,141 @@
+/* ======================================================================
+   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
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under 
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef DUMP_CLASS
+
+DumpStyle(nc,DumpNC)
+
+#else
+
+#ifndef LMP_DUMP_NC_H
+#define LMP_DUMP_NC_H
+
+#include "dump_custom.h"
+
+namespace LAMMPS_NS {
+
+const int NC_FIELD_NAME_MAX = 100;
+const int DUMP_NC_MAX_DIMS  = 100;
+
+class DumpNC : public DumpCustom {
+ public:
+  DumpNC(class LAMMPS *, int, char **);
+  virtual ~DumpNC();
+  virtual void write();
+
+ private:
+  // per-atoms quantities (positions, velocities, etc.)
+  struct nc_perat_t {
+    int dims;                     // number of dimensions
+    int field[DUMP_NC_MAX_DIMS];  // field indices corresponding to the dim.
+    char name[NC_FIELD_NAME_MAX]; // field name
+    int var;                      // NetCDF variable
+
+    bool constant;                // is this property per file (not per frame)
+    int ndumped;                  // number of enties written for this prop.
+  };
+
+  typedef void (DumpNC::*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
+
+  bigint ntotalgr;             // # of atoms
+
+  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
+
+  bool double_precision;       // write everything as double precision
+
+  bigint n_buffer;             // size of buffer
+  int *int_buffer;             // buffer for passing data to netcdf
+  double *double_buffer;       // buffer for passing data to netcdf
+
+  int ncid;
+
+  int frame_dim;
+  int spatial_dim;
+  int Voigt_dim;
+  int atom_dim;
+  int cell_spatial_dim;
+  int cell_angular_dim;
+  int label_dim;
+
+  int spatial_var;
+  int cell_spatial_var;
+  int cell_angular_var;
+
+  int time_var;
+  int cell_origin_var;
+  int cell_lengths_var;
+  int cell_angles_var;
+
+  virtual void openfile();
+  void closefile();
+  virtual void write_header(bigint);
+  virtual void write_data(int, double *);
+  void write_prmtop();
+
+  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 *);
+};
+
+}
+
+#endif
+#endif
diff --git a/src/USER-NC-DUMP/dump_nc_mpiio.cpp b/src/USER-NC-DUMP/dump_nc_mpiio.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f8960e6901105e3dff9f873c0c22fa863985f3c0
--- /dev/null
+++ b/src/USER-NC-DUMP/dump_nc_mpiio.cpp
@@ -0,0 +1,1077 @@
+/* ======================================================================
+   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
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under 
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+#if defined(LMP_HAS_PNETCDF)
+
+#include <unistd.h>
+
+#include <pnetcdf.h>
+
+#include "atom.h"
+#include "comm.h"
+#include "compute.h"
+#include "domain.h"
+#include "error.h"
+#include "fix.h"
+#include "group.h"
+#include "input.h"
+#include "math_const.h"
+#include "memory.h"
+#include "modify.h"
+#include "stdlib.h"
+#include "string.h"
+#include "update.h"
+#include "universe.h"
+#include "variable.h"
+#include "force.h"
+
+#include "dump_nc_mpiio.h"
+
+using namespace LAMMPS_NS;
+using namespace MathConst;
+
+enum{INT,DOUBLE};  // same as in dump_custom.cpp
+
+const char NC_FRAME_STR[]         = "frame";
+const char NC_SPATIAL_STR[]       = "spatial";
+const char NC_VOIGT_STR[]         = "Voigt";
+const char NC_ATOM_STR[]          = "atom";
+const char NC_CELL_SPATIAL_STR[]  = "cell_spatial";
+const char NC_CELL_ANGULAR_STR[]  = "cell_angular";
+const char NC_LABEL_STR[]         = "label";
+
+const char NC_TIME_STR[]          = "time";
+const char NC_CELL_ORIGIN_STR[]   = "cell_origin";
+const char NC_CELL_LENGTHS_STR[]  = "cell_lengths";
+const char NC_CELL_ANGLES_STR[]   = "cell_angles";
+
+const char NC_UNITS_STR[]         = "units";
+const char NC_SCALE_FACTOR_STR[]  = "scale_factor";
+
+const int THIS_IS_A_FIX      = -1;
+const int THIS_IS_A_COMPUTE  = -2;
+const int THIS_IS_A_VARIABLE = -3;
+const int THIS_IS_A_BIGINT   = -4;
+
+/* ---------------------------------------------------------------------- */
+
+#define NCERR(x) ncerr(x, NULL, __LINE__)
+#define NCERRX(x, descr) ncerr(x, descr, __LINE__)
+
+/* ---------------------------------------------------------------------- */
+
+DumpNCMPIIO::DumpNCMPIIO(LAMMPS *lmp, int narg, char **arg) :
+  DumpCustom(lmp, narg, arg)
+{
+  // arrays for data rearrangement
+
+  sort_flag = 1;
+  sortcol = 0;
+  binary = 1;
+  flush_flag = 0;
+
+  if (multiproc)
+    error->all(FLERR,"Multi-processor writes are not supported.");
+  if (multifile)
+    error->all(FLERR,"Multiple files are not supported.");
+
+  perat = new nc_perat_t[nfield];
+
+  for (int i = 0; i < nfield; i++) {
+    perat[i].dims = 0;
+  }
+
+  n_perat = 0;
+  for (int iarg = 5; iarg < narg; iarg++) {
+    int i = iarg-5;
+    int idim = 0;
+    int ndims = 1;
+    char mangled[1024];
+
+    strcpy(mangled, arg[iarg]);
+
+    // name mangling
+    // in the AMBER specification
+    if (!strcmp(mangled, "x") || !strcmp(mangled, "y") ||
+        !strcmp(mangled, "z")) {
+      idim = mangled[0] - 'x';
+      ndims = 3;
+      strcpy(mangled, "coordinates");
+    }
+    else if (!strcmp(mangled, "vx") || !strcmp(mangled, "vy") ||
+             !strcmp(mangled, "vz")) {
+      idim = mangled[1] - 'x';
+      ndims = 3;
+      strcpy(mangled, "velocities");
+    }
+    else if (!strcmp(mangled, "xs") || !strcmp(mangled, "ys") ||
+             !strcmp(mangled, "zs")) {
+      idim = mangled[0] - 'x';
+      ndims = 3;
+      strcpy(mangled, "scaled_coordinates");
+    }
+    else if (!strcmp(mangled, "xu") || !strcmp(mangled, "yu") ||
+             !strcmp(mangled, "zu")) {
+      idim = mangled[0] - 'x';
+      ndims = 3;
+      strcpy(mangled, "unwrapped_coordinates");
+    }
+    else if (!strcmp(mangled, "fx") || !strcmp(mangled, "fy") ||
+             !strcmp(mangled, "fz")) {
+      idim = mangled[1] - 'x';
+      ndims = 3;
+      strcpy(mangled, "forces");
+    }
+    else if (!strcmp(mangled, "mux") || !strcmp(mangled, "muy") ||
+             !strcmp(mangled, "muz")) {
+      idim = mangled[2] - 'x';
+      ndims = 3;
+      strcpy(mangled, "mu");
+    }
+    else if (!strncmp(mangled, "c_", 2)) {
+      char *ptr = strchr(mangled, '[');
+      if (ptr) {
+        if (mangled[strlen(mangled)-1] != ']')
+          error->all(FLERR,"Missing ']' in dump command");
+        *ptr = '\0';
+        idim = ptr[1] - '1';
+        ndims = THIS_IS_A_COMPUTE;
+      }
+    }
+    else if (!strncmp(mangled, "f_", 2)) {
+      char *ptr = strchr(mangled, '[');
+      if (ptr) {
+        if (mangled[strlen(mangled)-1] != ']')
+          error->all(FLERR,"Missing ']' in dump command");
+        *ptr = '\0';
+        idim = ptr[1] - '1';
+        ndims = THIS_IS_A_FIX;
+      }
+    }
+
+    // find mangled name
+    int inc = -1;
+    for (int j = 0; j < n_perat && inc < 0; j++) {
+      if (!strcmp(perat[j].name, mangled)) {
+        inc = j;
+      }
+    }
+
+    if (inc < 0) {
+      // this has not yet been defined
+      inc = n_perat;
+      perat[inc].dims = ndims;
+      if (ndims < 0) ndims = DUMP_NC_MPIIO_MAX_DIMS;
+      for (int j = 0; j < DUMP_NC_MPIIO_MAX_DIMS; j++) {
+        perat[inc].field[j] = -1;
+      }
+      strcpy(perat[inc].name, mangled);
+      n_perat++;
+    }
+
+    perat[inc].field[idim] = i;
+  }
+
+  n_perframe = 0;
+  perframe = NULL;
+
+  n_buffer = 0;
+  int_buffer = NULL;
+  double_buffer = NULL;
+
+  double_precision = false;
+
+  framei = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+DumpNCMPIIO::~DumpNCMPIIO()
+{
+  closefile();
+
+  delete [] perat;
+  if (n_perframe > 0)
+    delete [] perframe;
+
+  if (int_buffer) memory->sfree(int_buffer);
+  if (double_buffer) memory->sfree(double_buffer);
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNCMPIIO::openfile()
+{
+  // 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++) {
+    if (perat[i].dims == THIS_IS_A_COMPUTE) {
+      int j = -1;
+      for (int k = 0; k < DUMP_NC_MPIIO_MAX_DIMS; k++) {
+        if (perat[i].field[k] >= 0) {
+          j = field2index[perat[i].field[0]];
+        }
+      }
+      if (j < 0)
+        error->all(FLERR,"Internal error.");
+      if (!compute[j]->peratom_flag)
+        error->all(FLERR,"compute does not provide per atom data");
+      perat[i].dims = compute[j]->size_peratom_cols;
+      if (perat[i].dims > DUMP_NC_MPIIO_MAX_DIMS)
+        error->all(FLERR,"perat[i].dims > DUMP_NC_MPIIO_MAX_DIMS");
+    }
+    else if (perat[i].dims == THIS_IS_A_FIX) {
+      int j = -1;
+      for (int k = 0; k < DUMP_NC_MPIIO_MAX_DIMS; k++) {
+        if (perat[i].field[k] >= 0) {
+          j = field2index[perat[i].field[0]];
+        }
+      }
+      if (j < 0)
+        error->all(FLERR,"Internal error.");
+      if (!fix[j]->peratom_flag)
+        error->all(FLERR,"fix does not provide per atom data");
+      perat[i].dims = fix[j]->size_peratom_cols;
+      if (perat[i].dims > DUMP_NC_MPIIO_MAX_DIMS)
+        error->all(FLERR,"perat[i].dims > DUMP_NC_MPIIO_MAX_DIMS");
+    }
+  }
+
+  // get total number of atoms
+  ntotalgr = group->count(igroup);
+
+  if (append_flag && access(filename, F_OK) != -1) {
+    // Fixme! Perform checks if dimensions and variables conform with
+    // data structure standard.
+
+    MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
+    double d[1];
+
+    if (singlefile_opened) return;
+    singlefile_opened = 1;
+
+    NCERRX( ncmpi_open(MPI_COMM_WORLD, filename, NC_WRITE, MPI_INFO_NULL,
+                       &ncid), filename );
+    
+    // dimensions
+    NCERRX( ncmpi_inq_dimid(ncid, NC_FRAME_STR, &frame_dim), NC_FRAME_STR );
+    NCERRX( ncmpi_inq_dimid(ncid, NC_SPATIAL_STR, &spatial_dim),
+            NC_SPATIAL_STR );
+    NCERRX( ncmpi_inq_dimid(ncid, NC_VOIGT_STR, &Voigt_dim), NC_VOIGT_STR );
+    NCERRX( ncmpi_inq_dimid(ncid, NC_ATOM_STR, &atom_dim), NC_ATOM_STR );
+    NCERRX( ncmpi_inq_dimid(ncid, NC_CELL_SPATIAL_STR, &cell_spatial_dim),
+            NC_CELL_SPATIAL_STR );
+    NCERRX( ncmpi_inq_dimid(ncid, NC_CELL_ANGULAR_STR, &cell_angular_dim),
+            NC_CELL_ANGULAR_STR );
+    NCERRX( ncmpi_inq_dimid(ncid, NC_LABEL_STR, &label_dim), NC_LABEL_STR );
+
+    // default variables
+    NCERRX( ncmpi_inq_varid(ncid, NC_SPATIAL_STR, &spatial_var),
+            NC_SPATIAL_STR );
+    NCERRX( ncmpi_inq_varid(ncid, NC_CELL_SPATIAL_STR, &cell_spatial_var),
+            NC_CELL_SPATIAL_STR);
+    NCERRX( ncmpi_inq_varid(ncid, NC_CELL_ANGULAR_STR, &cell_angular_var),
+            NC_CELL_ANGULAR_STR);
+      
+    NCERRX( ncmpi_inq_varid(ncid, NC_TIME_STR, &time_var), NC_TIME_STR );
+    NCERRX( ncmpi_inq_varid(ncid, NC_CELL_ORIGIN_STR, &cell_origin_var),
+            NC_CELL_ORIGIN_STR );
+    NCERRX( ncmpi_inq_varid(ncid, NC_CELL_LENGTHS_STR, &cell_lengths_var),
+            NC_CELL_LENGTHS_STR);
+    NCERRX( ncmpi_inq_varid(ncid, NC_CELL_ANGLES_STR, &cell_angles_var),
+            NC_CELL_ANGLES_STR);
+
+    // variables specified in the input file
+    for (int i = 0; i < n_perat; i++) {
+      nc_type xtype;
+
+      // Type mangling
+      if (vtype[perat[i].field[0]] == INT) {
+        xtype = NC_INT;
+      }
+      else {
+        if (double_precision)
+          xtype = NC_DOUBLE;
+        else
+          xtype = NC_FLOAT;
+      }
+    
+      NCERRX( ncmpi_inq_varid(ncid, perat[i].name, &perat[i].var),
+              perat[i].name );
+    }
+
+    // perframe variables
+    for (int i = 0; i < n_perframe; i++) {
+      NCERRX( ncmpi_inq_varid(ncid, perframe[i].name, &perframe[i].var),
+              perframe[i].name );
+    }
+    
+    MPI_Offset nframes;
+    NCERR( ncmpi_inq_dimlen(ncid, frame_dim, &nframes) );
+    // framei == -1 means append to file, == -2 means override last frame
+    // Note that in the input file this translates to 'yes', '-1', etc.
+    if (framei < 0 || (append_flag && framei == 0))  framei = nframes+framei+1;
+    if (framei < 1)  framei = 1;
+  }
+  else {
+    int dims[NC_MAX_VAR_DIMS];
+    MPI_Offset index[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
+    double d[1];
+
+    if (singlefile_opened) return;
+    singlefile_opened = 1;
+
+    NCERRX( ncmpi_create(MPI_COMM_WORLD, filename, NC_64BIT_OFFSET,
+                         MPI_INFO_NULL, &ncid), filename );
+    
+    // dimensions
+    NCERRX( ncmpi_def_dim(ncid, NC_FRAME_STR, NC_UNLIMITED, &frame_dim),
+            NC_FRAME_STR );
+    NCERRX( ncmpi_def_dim(ncid, NC_SPATIAL_STR, 3, &spatial_dim),
+            NC_SPATIAL_STR );
+    NCERRX( ncmpi_def_dim(ncid, NC_VOIGT_STR, 6, &Voigt_dim),
+            NC_VOIGT_STR );
+    NCERRX( ncmpi_def_dim(ncid, NC_ATOM_STR, ntotalgr, &atom_dim),
+            NC_ATOM_STR );
+    NCERRX( ncmpi_def_dim(ncid, NC_CELL_SPATIAL_STR, 3, &cell_spatial_dim),
+            NC_CELL_SPATIAL_STR );
+    NCERRX( ncmpi_def_dim(ncid, NC_CELL_ANGULAR_STR, 3, &cell_angular_dim),
+            NC_CELL_ANGULAR_STR );
+    NCERRX( ncmpi_def_dim(ncid, NC_LABEL_STR, 10, &label_dim),
+            NC_LABEL_STR );
+
+    // default variables
+    dims[0] = spatial_dim;
+    NCERRX( ncmpi_def_var(ncid, NC_SPATIAL_STR, NC_CHAR, 1, dims, &spatial_var),
+            NC_SPATIAL_STR );
+    NCERRX( ncmpi_def_var(ncid, NC_CELL_SPATIAL_STR, NC_CHAR, 1, dims,
+                          &cell_spatial_var), NC_CELL_SPATIAL_STR );
+    dims[0] = spatial_dim;
+    dims[1] = label_dim;
+    NCERRX( ncmpi_def_var(ncid, NC_CELL_ANGULAR_STR, NC_CHAR, 2, dims,
+                          &cell_angular_var), NC_CELL_ANGULAR_STR );
+    
+    dims[0] = frame_dim;
+    NCERRX( ncmpi_def_var(ncid, NC_TIME_STR, NC_DOUBLE, 1, dims, &time_var),
+            NC_TIME_STR);
+    dims[0] = frame_dim;
+    dims[1] = cell_spatial_dim;
+    NCERRX( ncmpi_def_var(ncid, NC_CELL_ORIGIN_STR, NC_DOUBLE, 2, dims,
+                          &cell_origin_var), NC_CELL_ORIGIN_STR );
+    NCERRX( ncmpi_def_var(ncid, NC_CELL_LENGTHS_STR, NC_DOUBLE, 2, dims,
+                          &cell_lengths_var), NC_CELL_LENGTHS_STR );
+    dims[0] = frame_dim;
+    dims[1] = cell_angular_dim;
+    NCERRX( ncmpi_def_var(ncid, NC_CELL_ANGLES_STR, NC_DOUBLE, 2, dims,
+                          &cell_angles_var), NC_CELL_ANGLES_STR );
+
+    // variables specified in the input file
+    dims[0] = frame_dim;
+    dims[1] = atom_dim;
+    dims[2] = spatial_dim;
+
+    for (int i = 0; i < n_perat; i++) {
+      nc_type xtype;
+
+      // Type mangling
+      if (vtype[perat[i].field[0]] == INT) {
+        xtype = NC_INT;
+      }
+      else {
+        if (double_precision)
+          xtype = NC_DOUBLE;
+        else
+          xtype = NC_FLOAT;
+      }
+      
+      if (perat[i].dims == 6) {
+        // this is a tensor in Voigt notation
+        dims[2] = Voigt_dim;
+        NCERRX( ncmpi_def_var(ncid, perat[i].name, xtype, 3, dims,
+                                &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( ncmpi_def_var(ncid, perat[i].name, xtype, 3, dims,
+                              &perat[i].var), perat[i].name );
+      }
+      else if (perat[i].dims == 1) {
+        NCERRX( ncmpi_def_var(ncid, perat[i].name, xtype, 2, dims,
+                              &perat[i].var), perat[i].name );
+      }
+      else {
+        char errstr[1024];
+        sprintf(errstr, "%i dimensions for '%s'. Not sure how to write "
+                "this to the NetCDF trajectory file.", perat[i].dims,
+                perat[i].name);
+        error->all(FLERR,errstr);
+      }
+    }
+
+    // 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 );
+      }
+    }
+
+    // attributes
+    NCERR( ncmpi_put_att_text(ncid, NC_GLOBAL, "Conventions",
+                              5, "AMBER") );
+    NCERR( ncmpi_put_att_text(ncid, NC_GLOBAL, "ConventionVersion",
+                              3, "1.0") );
+    
+    NCERR( ncmpi_put_att_text(ncid, NC_GLOBAL, "program",
+                              6, "LAMMPS") );
+    NCERR( ncmpi_put_att_text(ncid, NC_GLOBAL, "programVersion",
+                              strlen(universe->version), universe->version) );
+    
+    // units
+    if (!strcmp(update->unit_style, "lj")) {
+      NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR,
+                                2, "lj") );
+      NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                                2, "lj") );
+      NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                                2, "lj") );
+    }
+    else if (!strcmp(update->unit_style, "real")) {
+      NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR,
+                                11, "femtosecond") );
+      NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                                8, "Angstrom") );
+      NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                                8, "Angstrom") );
+    }
+    else if (!strcmp(update->unit_style, "metal")) {
+      NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR,
+                                10, "picosecond") );
+      NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                                8, "Angstrom") );
+      NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                                8, "Angstrom") );
+    }
+    else if (!strcmp(update->unit_style, "si")) {
+      NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR,
+                                6, "second") );
+      NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                                5, "meter") );
+      NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                                5, "meter") );
+    }
+    else if (!strcmp(update->unit_style, "cgs")) {
+      NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR,
+                                6, "second") );
+      NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                                10, "centimeter") );
+      NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                                10, "centimeter") );
+    }
+    else if (!strcmp(update->unit_style, "electron")) {
+      NCERR( ncmpi_put_att_text(ncid, time_var, NC_UNITS_STR,
+                                11, "femtosecond") );
+      NCERR( ncmpi_put_att_text(ncid, cell_origin_var, NC_UNITS_STR,
+                                4, "Bohr") );
+      NCERR( ncmpi_put_att_text(ncid, cell_lengths_var, NC_UNITS_STR,
+                                4, "Bohr") );
+    }
+    else {
+      char errstr[1024];
+      sprintf(errstr, "Unsupported unit style '%s'", update->unit_style);
+      error->all(FLERR,errstr);
+    }
+      
+    NCERR( ncmpi_put_att_text(ncid, cell_angles_var, NC_UNITS_STR,
+                              6, "degree") );
+    
+    d[0] = update->dt;
+    NCERR( ncmpi_put_att_double(ncid, time_var, NC_SCALE_FACTOR_STR,
+                                NC_DOUBLE, 1, d) );
+    d[0] = 1.0;
+    NCERR( ncmpi_put_att_double(ncid, cell_origin_var, NC_SCALE_FACTOR_STR,
+                                NC_DOUBLE, 1, d) );
+    d[0] = 1.0;
+    NCERR( ncmpi_put_att_double(ncid, cell_lengths_var, NC_SCALE_FACTOR_STR,
+                                NC_DOUBLE, 1, d) );
+    
+    /*
+     * Finished with definition
+     */
+    
+    NCERR( ncmpi_enddef(ncid) );
+
+    /*
+     * Write label variables
+     */
+    
+    NCERR( ncmpi_begin_indep_data(ncid) );
+
+    if (filewriter) {
+      NCERR( ncmpi_put_var_text(ncid, spatial_var, "xyz") );
+      NCERR( ncmpi_put_var_text(ncid, cell_spatial_var, "abc") );
+      index[0] = 0;
+      index[1] = 0;
+      count[0] = 1;
+      count[1] = 5;
+      NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count,
+                                 "alpha") );
+      index[0] = 1;
+      count[1] = 4;
+      NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count,
+                                 "beta") );
+      index[0] = 2;
+      count[1] = 5;
+      NCERR( ncmpi_put_vara_text(ncid, cell_angular_var, index, count,
+                                 "gamma") );
+    }
+
+    NCERR( ncmpi_end_indep_data(ncid) );
+
+    framei = 1;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNCMPIIO::closefile()
+{
+  if (singlefile_opened) {
+    NCERR( ncmpi_close(ncid) );
+    singlefile_opened = 0;
+    // append next time DumpNCMPIIO::openfile is called
+    append_flag = 1;
+    // write to next frame upon next open
+    framei++;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNCMPIIO::write()
+{
+  // open file
+
+  openfile();
+
+  // need to write per-frame (global) properties here since they may come
+  // from computes. write_header below is only called from the writing
+  // processes, but modify->compute[j]->compute_* must be called from all
+  // processes.
+
+  MPI_Offset start[2];
+
+  start[0] = framei-1;
+  start[1] = 0;
+
+  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 defined(LAMMPS_SMALLBIG) || defined(LAMMPS_BIGBIG)
+        NCERR( ncmpi_put_var1_long(ncid, perframe[i].var, start, &data) );
+#else
+        NCERR( ncmpi_put_var1_int(ncid, perframe[i].var, start, &data) );
+#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_time_and_cell();
+
+  NCERR( ncmpi_end_indep_data(ncid) );
+
+  // nme = # of dump lines this proc contributes to dump
+
+  nme = count();
+  int *block_sizes = new int[comm->nprocs];
+  MPI_Allgather(&nme, 1, MPI_INT, block_sizes, 1, MPI_INT, MPI_COMM_WORLD);
+  blocki = 0;
+  for (int i = 0; i < comm->me; i++)  blocki += block_sizes[i];
+  delete [] block_sizes;
+
+  // insure buf is sized for packing and communicating
+  // use nme to insure filewriter proc can receive info from others
+  // limit nme*size_one to int since used as arg in MPI calls
+
+  if (nme > maxbuf) {
+    if ((bigint) nme * size_one > MAXSMALLINT)
+      error->all(FLERR,"Too much per-proc info for dump");
+    maxbuf = nme;
+    memory->destroy(buf);
+    memory->create(buf,maxbuf*size_one,"dump:buf");
+  }
+
+  // pack my data into buf
+
+  pack(NULL);
+
+  // each process writes its data
+
+  write_data(nme, buf);
+
+  // close file. this ensures data is flushed and minimizes data corruption
+
+  closefile();
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNCMPIIO::write_time_and_cell()
+{
+  MPI_Offset start[2];
+
+  start[0] = framei-1;
+  start[1] = 0;
+
+  MPI_Offset count[2];
+  double time, cell_origin[3], cell_lengths[3], cell_angles[3];
+
+  time = update->ntimestep;
+  if (domain->triclinic == 0) {
+    cell_origin[0] = domain->boxlo[0];
+    cell_origin[1] = domain->boxlo[1];
+    cell_origin[2] = domain->boxlo[2];
+
+    cell_lengths[0] = domain->xprd;
+    cell_lengths[1] = domain->yprd;
+    cell_lengths[2] = domain->zprd;
+
+    cell_angles[0] = 90;
+    cell_angles[1] = 90;
+    cell_angles[2] = 90;
+  }
+  else {
+    double cosalpha, cosbeta, cosgamma;
+    double *h = domain->h;
+
+    cell_origin[0] = domain->boxlo[0];
+    cell_origin[1] = domain->boxlo[1];
+    cell_origin[2] = domain->boxlo[2];
+
+    cell_lengths[0] = domain->xprd;
+    cell_lengths[1] = sqrt(h[1]*h[1]+h[5]*h[5]);
+    cell_lengths[2] = sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]);
+
+    cosalpha = (h[5]*h[4]+h[1]*h[3])/
+      sqrt((h[1]*h[1]+h[5]*h[5])*(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]));
+    cosbeta = h[4]/sqrt(h[2]*h[2]+h[3]*h[3]+h[4]*h[4]);
+    cosgamma = h[5]/sqrt(h[1]*h[1]+h[5]*h[5]);
+
+    cell_angles[0] = acos(cosalpha)*180.0/MY_PI;
+    cell_angles[1] = acos(cosbeta)*180.0/MY_PI;
+    cell_angles[2] = acos(cosgamma)*180.0/MY_PI;
+  }
+
+  // Recent AMBER conventions say that nonperiodic boundaries should have
+  // 'cell_lengths' set to zero.
+  for (int dim = 0; dim < 3; dim++) {
+    if (!domain->periodicity[dim])
+      cell_lengths[dim] = 0.0;
+  }
+
+  count[0] = 1;
+  count[1] = 3;
+  if (filewriter) {
+    NCERR( ncmpi_put_var1_double(ncid, time_var, start, &time) );
+    NCERR( ncmpi_put_vara_double(ncid, cell_origin_var, start, count,
+                                 cell_origin) );
+    NCERR( ncmpi_put_vara_double(ncid, cell_lengths_var, start, count,
+                                 cell_lengths) );
+    NCERR( ncmpi_put_vara_double(ncid, cell_angles_var, start, count,
+                                 cell_angles) );
+  }
+}
+
+
+/* ----------------------------------------------------------------------
+   write data lines to file in a block-by-block style
+   write head of block (mass & element name) only if has atoms of the type
+------------------------------------------------------------------------- */
+
+void DumpNCMPIIO::write_data(int n, double *mybuf)
+{
+  MPI_Offset start[NC_MAX_VAR_DIMS], count[NC_MAX_VAR_DIMS];
+  MPI_Offset stride[NC_MAX_VAR_DIMS];
+
+  if (!int_buffer) {
+    n_buffer = std::max(1, n);
+    int_buffer = (int *)
+      memory->smalloc(n_buffer*sizeof(int), "DumpNCMPIIO::int_buffer");
+    double_buffer = (double *)
+      memory->smalloc(n_buffer*sizeof(double), "DumpNCMPIIO::double_buffer");
+  }
+
+  if (n > n_buffer) {
+    n_buffer = std::max(1, n);
+    int_buffer = (int *)
+      memory->srealloc(int_buffer, n_buffer*sizeof(int),
+                       "DumpNCMPIIO::int_buffer");
+    double_buffer = (double *)
+      memory->srealloc(double_buffer, n_buffer*sizeof(double),
+                       "DumpNCMPIIO::double_buffer");
+  }
+
+  start[0] = framei-1;
+  start[1] = blocki;
+  start[2] = 0;
+
+  if (n == 0) {
+    /* If there is no data, we need to make sure the start values don't exceed
+       dimension bounds. Just set them to zero. */
+    start[1] = 0;
+  }
+
+  count[0] = 1;
+  count[1] = n;
+  count[2] = 1;
+
+  stride[0] = 1;
+  stride[1] = 1;
+  stride[2] = 3;
+
+  for (int i = 0; i < n_perat; i++) {
+    int iaux = perat[i].field[0];
+    if (iaux < 0 || iaux >= size_one) {
+      char errmsg[1024];
+      sprintf(errmsg, "Internal error: name = %s, iaux = %i, "
+              "size_one = %i", perat[i].name, iaux, size_one);
+      error->one(FLERR,errmsg);
+    }
+
+    if (vtype[iaux] == INT) {
+      // integers
+      if (perat[i].dims > 1) {
+
+        for (int idim = 0; idim < perat[i].dims; idim++) {
+          iaux = perat[i].field[idim];
+
+          if (iaux >= 0) {
+            if (iaux >= size_one) {
+              char errmsg[1024];
+              sprintf(errmsg, "Internal error: name = %s, iaux = %i, "
+                      "size_one = %i", perat[i].name, iaux, size_one);
+              error->one(FLERR,errmsg);
+            }
+
+            for (int j = 0; j < n; j++, iaux+=size_one) {
+              int_buffer[j] = mybuf[iaux];
+            }
+      
+            start[2] = idim;
+            NCERRX( ncmpi_put_vars_int_all(ncid, perat[i].var, start, count,
+                                           stride, int_buffer), perat[i].name );
+          }
+        }
+      }
+      else {
+        for (int j = 0; j < n; j++, iaux+=size_one) {
+            int_buffer[j] = mybuf[iaux];
+        }
+
+        NCERRX( ncmpi_put_vara_int_all(ncid, perat[i].var, start, count,
+                                       int_buffer), perat[i].name );
+      }
+    }
+    else {
+      // doubles
+      if (perat[i].dims > 1) {
+
+        for (int idim = 0; idim < perat[i].dims; idim++) {
+          iaux = perat[i].field[idim];
+
+          if (iaux >= 0) {
+            if (iaux >= size_one) {
+              char errmsg[1024];
+              sprintf(errmsg, "Internal error: name = %s, iaux = %i, "
+                      "size_one = %i", perat[i].name, iaux, size_one);
+              error->one(FLERR,errmsg);
+            }
+
+            for (int j = 0; j < n; j++, iaux+=size_one) {
+                double_buffer[j] = mybuf[iaux];
+            }
+      
+            start[2] = idim;
+            NCERRX( ncmpi_put_vars_double_all(ncid, perat[i].var, start, count,
+                                              stride, double_buffer), perat[i].name );
+          }
+        }
+      }
+      else {
+        for (int j = 0; j < n; j++, iaux+=size_one) {
+            double_buffer[j] = mybuf[iaux];
+        }
+
+        NCERRX( ncmpi_put_vara_double_all(ncid, perat[i].var, start, count,
+                                          double_buffer), perat[i].name );
+      }
+    }
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+int DumpNCMPIIO::modify_param(int narg, char **arg)
+{
+  int iarg = 0;
+  if (strcmp(arg[iarg],"double") == 0) {
+    iarg++;
+    if (iarg >= narg)
+      error->all(FLERR,"expected 'yes' or 'no' after 'double' keyword.");
+    if (strcmp(arg[iarg],"yes") == 0) {
+      double_precision = true;
+    }
+    else if (strcmp(arg[iarg],"no") == 0) {
+      double_precision = false;
+    }
+    else error->all(FLERR,"expected 'yes' or 'no' after 'double' keyword.");
+    iarg++;
+    return 2;
+  }
+  else if (strcmp(arg[iarg],"at") == 0) {
+    iarg++;
+    framei = force->inumeric(FLERR,arg[iarg]);
+    if (framei < 0)  framei--;
+    iarg++;
+    return 2;
+  }
+  else if (strcmp(arg[iarg],"global") == 0) {
+    // "perframe" quantities, i.e. not per-atom stuff
+
+    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 = &DumpNCMPIIO::compute_step;
+        strcpy(perframe[i].name, arg[iarg]);
+      }
+      else if (!strcmp(arg[iarg],"elapsed")) {
+        perframe[i].type = THIS_IS_A_BIGINT;
+        perframe[i].compute = &DumpNCMPIIO::compute_elapsed;
+        strcpy(perframe[i].name, arg[iarg]);
+      }
+      else if (!strcmp(arg[iarg],"elaplong")) {
+        perframe[i].type = THIS_IS_A_BIGINT;
+        perframe[i].compute = &DumpNCMPIIO::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;
+    
+      }
+    }
+
+    return narg;
+  } else return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNCMPIIO::ncerr(int err, const char *descr, int line)
+{
+  if (err != NC_NOERR) {
+    char errstr[1024];
+    if (descr) {
+      sprintf(errstr, "NetCDF failed with error '%s' (while accessing '%s') "
+              " in line %i of %s.", ncmpi_strerror(err), descr, line, __FILE__);
+    }
+    else {
+      sprintf(errstr, "NetCDF failed with error '%s' in line %i of %s.",
+              ncmpi_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 DumpNCMPIIO::compute_step(void *r)
+{
+  *((bigint *) r) = update->ntimestep;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNCMPIIO::compute_elapsed(void *r)
+{
+  *((bigint *) r) = update->ntimestep - update->firststep;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void DumpNCMPIIO::compute_elapsed_long(void *r)
+{
+  *((bigint *) r) = update->ntimestep - update->beginstep;
+}
+
+#endif /* defined(LMP_HAS_PNETCDF) */
diff --git a/src/USER-NC-DUMP/dump_nc_mpiio.h b/src/USER-NC-DUMP/dump_nc_mpiio.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7f85b4bfcf367972242566eee67536ff37fc904
--- /dev/null
+++ b/src/USER-NC-DUMP/dump_nc_mpiio.h
@@ -0,0 +1,140 @@
+/* ======================================================================
+   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
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under 
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+#if defined(LMP_HAS_PNETCDF)
+
+#ifdef DUMP_CLASS
+
+DumpStyle(nc/mpiio,DumpNCMPIIO)
+
+#else
+
+#ifndef LMP_DUMP_NC_MPIIO_H
+#define LMP_DUMP_NC_MPIIO_H
+
+#include "dump_custom.h"
+
+namespace LAMMPS_NS {
+
+const int NC_MPIIO_FIELD_NAME_MAX = 100;
+const int DUMP_NC_MPIIO_MAX_DIMS  = 100;
+
+class DumpNCMPIIO : public DumpCustom {
+ public:
+  DumpNCMPIIO(class LAMMPS *, int, char **);
+  virtual ~DumpNCMPIIO();
+  virtual void write();
+
+ private:
+  // per-atoms quantities (positions, velocities, etc.)
+  struct nc_perat_t {
+    int dims;                           // number of dimensions
+    int field[DUMP_NC_MPIIO_MAX_DIMS];  // field indices corresponding to the dim.
+    char name[NC_MPIIO_FIELD_NAME_MAX]; // field name
+    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
+  };
+
+  int framei;                           // current frame index
+  int blocki;                           // current block index
+  int ndata;                            // number of data blocks to expect
+
+  bigint ntotalgr;                      // # of atoms
+
+  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
+
+  bool double_precision;                // write everything as double precision
+
+  bigint n_buffer;                      // size of buffer
+  int *int_buffer;                      // buffer for passing data to netcdf
+  double *double_buffer;                // buffer for passing data to netcdf
+
+  int ncid;
+
+  int frame_dim;
+  int spatial_dim;
+  int Voigt_dim;
+  int atom_dim;
+  int cell_spatial_dim;
+  int cell_angular_dim;
+  int label_dim;
+
+  int spatial_var;
+  int cell_spatial_var;
+  int cell_angular_var;
+
+  int time_var;
+  int cell_origin_var;
+  int cell_lengths_var;
+  int cell_angles_var;
+
+  virtual void openfile();
+  void closefile();
+  void write_time_and_cell();
+  virtual void write_data(int, double *);
+  void write_prmtop();
+
+  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 *);
+};
+
+}
+
+#endif
+#endif
+#endif /* defined(LMP_HAS_PNETCDF) */