diff --git a/Common/Context.h b/Common/Context.h
index 1a42a1d810871f7a39d0d853df8800f44467af45..4101c531722201b7cdd6f25f5dc0637357113548 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -186,7 +186,7 @@ public :
       double val = cut_planea * x + cut_planeb * y + cut_planec * z + cut_planed; 
       return val;
     }
-    int save_all, stl_binary, msh_binary, bdf_field_format;
+    int save_all, save_groups_of_nodes, stl_binary, msh_binary, bdf_field_format;
     char *triangle_options;
     int smooth_normals, reverse_all_normals;
     double angle_smooth_normals;
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 745f97f5e03d999534d7c83148a2c7880f347fd1..04db67efb995cf82e3eb5d6531944b9e68f2d949 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1011,6 +1011,8 @@ StringXNumber MeshOptions_Number[] = {
 
   { F,   "SaveAll" , opt_mesh_save_all , 0. , 
     "Ignore Physical definitions and save all elements" },
+  { F,   "SaveGroupsOfNodes" , opt_mesh_save_groups_of_nodes , 0. , 
+    "Save groups of nodes for each physical line and surface (UNV mesh format only)" },
   { F|O, "ScalingFactor" , opt_mesh_scaling_factor , 1.0 ,
     "Global scaling factor applied to the saved mesh" },
   { F|O, "SecondOrderIncomplete" , opt_mesh_second_order_incomplete , 1. ,
diff --git a/Common/Options.cpp b/Common/Options.cpp
index e718141085ffb49d2b9ca45f30413e5040570f84..a7b5077fae567d516fb132f15caca997cd8a1a3a 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.343 2007-05-04 14:27:41 geuzaine Exp $
+// $Id: Options.cpp,v 1.344 2007-05-13 10:37:01 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -5009,6 +5009,13 @@ double opt_mesh_save_all(OPT_ARGS_NUM)
   return CTX.mesh.save_all;
 }
 
+double opt_mesh_save_groups_of_nodes(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX.mesh.save_groups_of_nodes = val ? 1 : 0;
+  return CTX.mesh.save_groups_of_nodes;
+}
+
 double opt_mesh_color_carousel(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET) {
diff --git a/Common/Options.h b/Common/Options.h
index 0cb1ca3a4310c8c38507b787ed5a6f75d5712109..271b7d5422ee7f368916da8224d657afff2cbe23 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -486,6 +486,7 @@ double opt_mesh_cut_planeb(OPT_ARGS_NUM);
 double opt_mesh_cut_planec(OPT_ARGS_NUM);
 double opt_mesh_cut_planed(OPT_ARGS_NUM);
 double opt_mesh_save_all(OPT_ARGS_NUM);
+double opt_mesh_save_groups_of_nodes(OPT_ARGS_NUM);
 double opt_mesh_color_carousel(OPT_ARGS_NUM);
 double opt_mesh_nb_nodes(OPT_ARGS_NUM);
 double opt_mesh_nb_triangles(OPT_ARGS_NUM);
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index dcd65834f642ca0a5e0b663b00d52e393608140a..fdbda4be38ff12eca2d091142e8b5eebb5aefce0 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.529 2007-05-07 08:36:36 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.530 2007-05-13 10:37:01 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -656,7 +656,7 @@ int _save_pos(char *name){ return generic_mesh_dialog(name, "POS Options", FORMA
 int _save_options(char *name){ return options_dialog(name); }
 int _save_geo(char *name){ return geo_dialog(name); }
 int _save_cgns(char *name){ CreateOutputFile(name, FORMAT_CGNS); return 1; }
-int _save_unv(char *name){ return generic_mesh_dialog(name, "UNV Options", FORMAT_UNV); }
+int _save_unv(char *name){ return unv_dialog(name); }
 int _save_med(char *name){ return generic_mesh_dialog(name, "MED Options", FORMAT_MED); }
 int _save_mesh(char *name){ return generic_mesh_dialog(name, "MESH Options", FORMAT_MESH); }
 int _save_bdf(char *name){ return bdf_dialog(name); }
diff --git a/Fltk/GUI_Extras.cpp b/Fltk/GUI_Extras.cpp
index da8a881a73a8f798187604e85054b9c89c9f4fb7..34ba903bea904e63ae258d0120c65691d21eeec2 100644
--- a/Fltk/GUI_Extras.cpp
+++ b/Fltk/GUI_Extras.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI_Extras.cpp,v 1.33 2007-03-18 12:05:16 geuzaine Exp $
+// $Id: GUI_Extras.cpp,v 1.34 2007-05-13 10:37:02 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -769,6 +769,63 @@ int msh_dialog(char *name)
   return 0;
 }
 
+// unv mesh dialog
+
+int unv_dialog(char *name)
+{
+  struct _unv_dialog{
+    Fl_Window *window;
+    Fl_Check_Button *b[2];
+    Fl_Button *ok, *cancel;
+  };
+  static _unv_dialog *dialog = NULL;
+
+  const int BH = 2 * CTX.fontsize + 1;
+  const int BB = 7 * CTX.fontsize + 9;
+  const int WB = 7;
+
+  if(!dialog){
+    dialog = new _unv_dialog;
+    int h = 3 * WB + 3 * BH, w = 2 * BB + 3 * WB, y = WB;
+    // not a "Dialog_Window" since it is modal 
+    dialog->window = new Fl_Double_Window(w, h, "UNV Options");
+    dialog->window->box(GMSH_WINDOW_BOX);
+    dialog->b[0] = new Fl_Check_Button(WB, y, 2 * BB + WB, BH, "Save all (ignore physical groups)"); y += BH;
+    dialog->b[0]->type(FL_TOGGLE_BUTTON);
+    dialog->b[1] = new Fl_Check_Button(WB, y, 2 * BB + WB, BH, "Save groups of nodes"); y += BH;
+    dialog->b[1]->type(FL_TOGGLE_BUTTON);
+    dialog->ok = new Fl_Return_Button(WB, y + WB, BB, BH, "OK");
+    dialog->cancel = new Fl_Button(2 * WB + BB, y + WB, BB, BH, "Cancel");
+    dialog->window->set_modal();
+    dialog->window->end();
+    dialog->window->hotspot(dialog->window);
+  }
+  
+  dialog->b[0]->value(CTX.mesh.save_all ? 1 : 0);
+  dialog->b[1]->value(CTX.mesh.save_groups_of_nodes ? 1 : 0);
+  dialog->window->show();
+
+  while(dialog->window->shown()){
+    Fl::wait();
+    for (;;) {
+      Fl_Widget* o = Fl::readqueue();
+      if (!o) break;
+      if (o == dialog->ok) {
+	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);
+	dialog->window->hide();
+	return 1;
+      }
+      if (o == dialog->window || o == dialog->cancel){
+	dialog->window->hide();
+	return 0;
+      }
+    }
+  }
+  return 0;
+}
+
 // Save bdf dialog
 
 int bdf_dialog(char *name)
diff --git a/Fltk/GUI_Extras.h b/Fltk/GUI_Extras.h
index 584a9af38a57bffb3b0eda183bf78c95834cbdea..4836ab0202305acf3751e8a95d976f69ebbf708a 100644
--- a/Fltk/GUI_Extras.h
+++ b/Fltk/GUI_Extras.h
@@ -37,6 +37,7 @@ int generic_mesh_dialog(char *filename, char *title, int format);
 int gl2ps_dialog(char *filename, char *title, int format);
 int options_dialog(char *filename);
 int msh_dialog(char *filename);
+int unv_dialog(char *filename);
 int bdf_dialog(char *filename);
 int stl_dialog(char *filename);
 
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 2b5072101345969579c5dda7c3b439b8ef044d2c..92d5cf1677c2f98f80bec0413dada1f5079e607e 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -202,8 +202,8 @@ class GModel
 
   // I-deas universal mesh format
   int readUNV(const std::string &name);
-  int writeUNV(const std::string &name, 
-	       bool saveAll=false, double scalingFactor=1.0);
+  int writeUNV(const std::string &name, bool saveAll=false, 
+	       bool saveGroupsOfNodes=false, double scalingFactor=1.0);
 
   // Medit (INRIA) mesh format
   int readMESH(const std::string &name);
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index b4ad68a2925c8b04ed389cedd679139f79fe6866..d79056ab6ca53eb67ed93f61086b9bbe2c22199c 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: GModelIO_Mesh.cpp,v 1.17 2007-05-10 22:08:03 geuzaine Exp $
+// $Id: GModelIO_Mesh.cpp,v 1.18 2007-05-13 10:37:02 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -1317,7 +1317,8 @@ static void writeElementsUNV(FILE *fp, const std::vector<T*> &ele, int saveAll,
 	ele[i]->writeUNV(fp, ++num, elementary, physicals[j]);
 }
 
-int GModel::writeUNV(const std::string &name, bool saveAll, double scalingFactor)
+int GModel::writeUNV(const std::string &name, bool saveAll, bool saveGroupsOfNodes, 
+		     double scalingFactor)
 {
   FILE *fp = fopen(name.c_str(), "w");
   if(!fp){
@@ -1364,13 +1365,13 @@ int GModel::writeUNV(const std::string &name, bool saveAll, double scalingFactor
   }
   fprintf(fp, "%6d\n", -1);
 
-  // save groups of nodes for physical lines and physical surfaces
-  bool saveGroupsOfNodes = false; // add option in CTX+GUI for this
+  // groups of nodes (for physical lines and physical surfaces)
   if(saveGroupsOfNodes){
     fprintf(fp, "%6d\n", -1);
     fprintf(fp, "%6d\n", 2477);
     std::map<int, std::vector<GEntity*> > groups[4];
     getPhysicalGroups(groups);
+    int gr = 1;
     for(int dim = 1; dim <= 2; dim++){
       for(std::map<int, std::vector<GEntity*> >::iterator it = groups[dim].begin();
 	  it != groups[dim].end(); it++){
@@ -1392,10 +1393,19 @@ int GModel::writeUNV(const std::string &name, bool saveAll, double scalingFactor
 		nodes.insert(gf->quadrangles[j]->getVertex(k));
 	  }
 	}
-	// put actual format of dataset in here
-	printf("physical %d : %d nodes\n", it->first, nodes.size());
-	for(std::set<MVertex*>::iterator it2 = nodes.begin(); it2 != nodes.end(); it2++)
-	  printf("node %6d\n", (*it2)->getNum());
+	fprintf(fp, "%10d%10d%10d%10d%10d%10d%10d%10d\n",
+		gr++, 0, 0, 0, 0, 0, 0, nodes.size());
+	fprintf(fp, "PERMANENT GROUP1\n");
+	int row = 0;
+	for(std::set<MVertex*>::iterator it2 = nodes.begin(); it2 != nodes.end(); it2++){
+	  if(row == 2) {
+	    fprintf(fp, "\n");
+	    row = 0;
+	  }
+	  fprintf(fp, "%10d%10d%10d%10d", 7, (*it2)->getNum(), 0, 0);
+	  row++;
+	}
+	fprintf(fp, "\n");
       }
     }
     fprintf(fp, "%6d\n", -1);
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 3b2b42581956611dfb99dbb13e4bfb7aba255b83..7cf90bcdf42e1c7f3e3a7d4cd1f05739352906f1 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -459,7 +459,7 @@ class MTriangleN : public MTriangle {
     if (_order == 5 && _vs.size() == 18) return MSH_TRI_21;
     throw;
   }
-  virtual int getTypeForUNV(){ throw; } // thin shell parabolic triangle
+  virtual int getTypeForUNV(){ throw; } // not available
   virtual const char *getStringForPOS(){ return 0; }
   virtual const char *getStringForBDF(){ return 0; }
   virtual void revert() 
diff --git a/Parser/CreateFile.cpp b/Parser/CreateFile.cpp
index 1f00105eca0d9a99b572f279c40451e51cf18b8a..614b3afbbe62c8c2c0d840f994e6e7890c9e1d3d 100644
--- a/Parser/CreateFile.cpp
+++ b/Parser/CreateFile.cpp
@@ -1,4 +1,4 @@
-// $Id: CreateFile.cpp,v 1.16 2007-03-18 12:05:16 geuzaine Exp $
+// $Id: CreateFile.cpp,v 1.17 2007-05-13 10:37:02 geuzaine Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -162,7 +162,8 @@ void CreateOutputFile(char *filename, int format)
     break;
 
   case FORMAT_UNV:
-    GMODEL->writeUNV(name, CTX.mesh.save_all, CTX.mesh.scaling_factor);
+    GMODEL->writeUNV(name, CTX.mesh.save_all, CTX.mesh.save_groups_of_nodes,
+		     CTX.mesh.scaling_factor);
     break;
 
   case FORMAT_MESH: