diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp
index e7235ae57d5744aa7ef07da982fd0dde3ce7dcd4..8576ac0275e91435562a9cd0a82dce8398fdf7e6 100644
--- a/Common/CreateFile.cpp
+++ b/Common/CreateFile.cpp
@@ -303,7 +303,8 @@ void CreateOutputFile(const std::string &fileName, int format, bool redraw)
 
   case FORMAT_INP:
     GModel::current()->writeINP
-      (name, CTX::instance()->mesh.saveAll, CTX::instance()->mesh.scalingFactor);
+      (name, CTX::instance()->mesh.saveAll, CTX::instance()->mesh.saveGroupsOfNodes,
+       CTX::instance()->mesh.scalingFactor);
     break;
 
   case FORMAT_P3D:
diff --git a/Fltk/fileDialogs.cpp b/Fltk/fileDialogs.cpp
index f8545b0bbd8c6d7cd98af697b3b2d69935eb9059..9d5a29e743110bb411475bb18bbcdb2adb90cc1a 100644
--- a/Fltk/fileDialogs.cpp
+++ b/Fltk/fileDialogs.cpp
@@ -894,9 +894,9 @@ int mshFileDialog(const char *name)
   return 0;
 }
 
-// unv mesh dialog
+// unv/inp mesh dialog
 
-int unvFileDialog(const char *name)
+int unvinpFileDialog(const char *name, const char *title, int format)
 {
   struct _unvFileDialog{
     Fl_Window *window;
@@ -910,7 +910,7 @@ int unvFileDialog(const char *name)
   if(!dialog){
     dialog = new _unvFileDialog;
     int h = 3 * WB + 3 * BH, w = 2 * BBB + 3 * WB, y = WB;
-    dialog->window = new Fl_Double_Window(w, h, "UNV Options");
+    dialog->window = new Fl_Double_Window(w, h, title);
     dialog->window->box(GMSH_WINDOW_BOX);
     dialog->window->set_modal();
     dialog->b[0] = new Fl_Check_Button
@@ -938,7 +938,7 @@ int unvFileDialog(const char *name)
         opt_mesh_save_all(0, GMSH_SET | GMSH_GUI, dialog->b[0]->value() ? 1 : 0);
         opt_mesh_save_groups_of_nodes(0, GMSH_SET | GMSH_GUI,
                                       dialog->b[1]->value() ? 1 : 0);
-        CreateOutputFile(name, FORMAT_UNV);
+        CreateOutputFile(name, format);
         dialog->window->hide();
         return 1;
       }
diff --git a/Fltk/fileDialogs.h b/Fltk/fileDialogs.h
index 9b1b929f5d8841480e6664c6077f77f277a48313..155171781d8449c1797872c872168b2abef15357 100644
--- a/Fltk/fileDialogs.h
+++ b/Fltk/fileDialogs.h
@@ -33,7 +33,7 @@ int gl2psFileDialog(const char *filename, const char *title, int format);
 int optionsFileDialog(const char *filename);
 int meshStatFileDialog(const char *filename);
 int mshFileDialog(const char *filename);
-int unvFileDialog(const char *filename);
+int unvinpFileDialog(const char *filename, const char *title, int format);
 int bdfFileDialog(const char *filename);
 int latexFileDialog(const char *filename);
 int cgnsFileDialog(const char *filename);
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 82772aa0040e96dac1f5e6a42606a88e3c571e8a..20361bd24a51ae235971b6b0066f79abcc7fd248 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -255,13 +255,14 @@ static int _save_geo(const char *name){ return geoFileDialog(name); }
 static int _save_brep(const char *name){ CreateOutputFile(name, FORMAT_BREP); return 1; }
 static int _save_step(const char *name){ CreateOutputFile(name, FORMAT_STEP); return 1; }
 static int _save_cgns(const char *name){ return cgnsFileDialog(name); }
-static int _save_unv(const char *name){ return unvFileDialog(name); }
+static int _save_unv(const char *name){ return unvinpFileDialog
+    (name, "UNV Options", FORMAT_UNV); }
 static int _save_vtk(const char *name){ return genericMeshFileDialog
     (name, "VTK Options", FORMAT_VTK, true, false); }
 static int _save_diff(const char *name){ return genericMeshFileDialog
     (name, "Diffpack Options", FORMAT_DIFF, true, false); }
-static int _save_inp(const char *name){ return genericMeshFileDialog
-    (name, "Abaqus INP Options", FORMAT_INP, false, false); }
+static int _save_inp(const char *name){ return unvinpFileDialog
+    (name, "Abaqus INP Options", FORMAT_INP); }
 static int _save_med(const char *name){ return genericMeshFileDialog
     (name, "MED Options", FORMAT_MED, false, false); }
 static int _save_mesh(const char *name){ return genericMeshFileDialog
diff --git a/Geo/GModel.h b/Geo/GModel.h
index f39687a46bc24eff2be1ce648be70a650efca7d2..9b6e59444fe6b29e8f9b55bc6aba20e2ed813302 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -659,7 +659,7 @@ class GModel
 
   // Abaqus
   int writeINP(const std::string &name, bool saveAll=false,
-               double scalingFactor=1.0);
+               bool saveGroupsOfNodes=false, double scalingFactor=1.0);
 
   // Geomview mesh
   int readGEOM(const std::string &name);
diff --git a/Geo/GModelIO_INP.cpp b/Geo/GModelIO_INP.cpp
index 57cda32ccd5537cdc1195e6448c8ecb0b27afb72..a1644f4759a760655b42bb570451a1a41369be90 100644
--- a/Geo/GModelIO_INP.cpp
+++ b/Geo/GModelIO_INP.cpp
@@ -23,9 +23,10 @@ static void writeElementsINP(FILE *fp, GEntity *ge, std::vector<T*> &elements,
       int np = (saveAll ? 1 : ge->physicals.size());
       for(int p = 0; p < np; p++){
         int part = (saveAll ? ge->tag() : ge->physicals[p]);
-        const char *str = (ge->dim() == 3) ? "VOLUME" : (ge->dim() == 2) ?
-          "SURFACE" : (ge->dim() == 1) ? "CURVE" : "POINT";
-        fprintf(fp, "*Element, type=%s, ELSET=%s%d\n", typ, str, part);
+        const char *str1 = (saveAll ? "Elementary" : "Physical");
+        const char *str2 = (ge->dim() == 3) ? "Volume" : (ge->dim() == 2) ?
+          "Surface" : (ge->dim() == 1) ? "Line" : "Point";
+        fprintf(fp, "*Element, type=%s, ELSET=%s%s%d\n", typ, str1, str2, part);
         for(unsigned int i = 0; i < elements.size(); i++)
           elements[i]->writeINP(fp, ne++);
       }
@@ -33,7 +34,7 @@ static void writeElementsINP(FILE *fp, GEntity *ge, std::vector<T*> &elements,
   }
 }
 
-int GModel::writeINP(const std::string &name, bool saveAll,
+int GModel::writeINP(const std::string &name, bool saveAll, bool saveGroupsOfNodes,
                      double scalingFactor)
 {
   FILE *fp = fopen(name.c_str(), "w");
@@ -74,6 +75,36 @@ int GModel::writeINP(const std::string &name, bool saveAll,
     writeElementsINP(fp, *it, (*it)->pyramids, saveAll, ne);
   }
 
+  // groups of nodes for physical groups
+  if(saveGroupsOfNodes){
+    std::map<int, std::vector<GEntity*> > groups[4];
+    getPhysicalGroups(groups);
+    for(int dim = 1; dim <= 3; dim++){
+      for(std::map<int, std::vector<GEntity*> >::iterator it = groups[dim].begin();
+          it != groups[dim].end(); it++){
+        std::set<MVertex*> nodes;
+        std::vector<GEntity *> &entities = it->second;
+        for(unsigned int i = 0; i < entities.size(); i++){
+          for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){
+            MElement *e = entities[i]->getMeshElement(j);
+            for (int k = 0; k < e->getNumVertices(); k++)
+              nodes.insert(e->getVertex(k));
+          }
+        }
+        const char *str = (dim == 3) ? "PhysicalVolume" : (dim == 2) ?
+          "PhysicalSurface" : "PhysicalLine";
+        fprintf(fp, "*NSET,NSET=%s%d\n", str, it->first);
+        int n = 0;
+        for(std::set<MVertex*>::iterator it2 = nodes.begin(); it2 != nodes.end(); it2++){
+          if(n && !(n % 10)) fprintf(fp, "\n");
+          fprintf(fp, "%d, ", (*it2)->getIndex());
+          n++;
+        }
+        fprintf(fp, "\n");
+      }
+    }
+  }
+
   fclose(fp);
   return 1;
 }