diff --git a/Common/Context.h b/Common/Context.h
index 66efa9498caf4533f4afa83a9785d2cf0752098c..dd512fd8e4e260f0dc4557628b769752412b5a80 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -223,7 +223,7 @@ class CTX {
     std::string socketName;
     std::string name[5], executable[5], remoteLogin[5];
     int autoSaveDatabase, autoArchiveOutputFiles, autoMesh, autoMergeFile;
-    int autoHideNewViews, autoShowLastStep;
+    int autoHideNewViews, autoShowLastStep, autoCheck;
   }solver;
   // print options
   struct{
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 71c5af3ed63072ca334f7bd0b10c5c205be8c4a2..268f1e0fef6f176e4c4fb55e2ea6cdea85e4489c 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1108,6 +1108,8 @@ StringXNumber SolverOptions_Number[] = {
     "Always listen to incoming connection requests?" },
   { F|O, "AutoArchiveOutputFiles" , opt_solver_auto_archive_output_files , 0. ,
     "Automatically archive output files after each computation" },
+  { F|O, "AutoCheck" , opt_solver_auto_check , 1. ,
+    "Automatically check model every time a parameter is changed" },
   { F|O, "AutoSaveDatabase" , opt_solver_auto_save_database , 1. ,
     "Automatically save database after each computation" },
   { F|O, "AutoMesh" , opt_solver_auto_mesh , 1. ,
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 895d8c5c227a15c1fafb4dacb05b84d4836acf9f..2e0c89481d62ff03df0dba3d977baa01b38308dd 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -5739,6 +5739,13 @@ double opt_solver_auto_archive_output_files(OPT_ARGS_NUM)
   return CTX::instance()->solver.autoArchiveOutputFiles;
 }
 
+double opt_solver_auto_check(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->solver.autoCheck = (int)val;
+  return CTX::instance()->solver.autoCheck;
+}
+
 double opt_solver_auto_mesh(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
diff --git a/Common/Options.h b/Common/Options.h
index 07372c2c6ef7632335137079d49b4f225d2eadf9..7ae91f9465bb672eea62fb54e9a3872206642ba5 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -470,6 +470,7 @@ double opt_solver_timeout(OPT_ARGS_NUM);
 double opt_solver_plugins(OPT_ARGS_NUM);
 double opt_solver_auto_save_database(OPT_ARGS_NUM);
 double opt_solver_auto_archive_output_files(OPT_ARGS_NUM);
+double opt_solver_auto_check(OPT_ARGS_NUM);
 double opt_solver_auto_mesh(OPT_ARGS_NUM);
 double opt_solver_auto_merge_file(OPT_ARGS_NUM);
 double opt_solver_auto_hide_new_views(OPT_ARGS_NUM);
diff --git a/Common/onelab.h b/Common/onelab.h
index ee5460052ce38d383dde2aafdd4ecce3af9571e6..98d24da4609543a6faa92c4954123e0ca521f4e9 100644
--- a/Common/onelab.h
+++ b/Common/onelab.h
@@ -383,9 +383,10 @@ namespace onelab{
   // The string class. A string has a mutable "kind": we do not derive
   // specialized classes, because the kind should be changeable at runtime
   // (e.g. from a client-dependent mathematical expression to a table of
-  // values). Kinds currently recognized by Gmsh are: "file". Possible kinds
-  // could be "complex", "matrix m n", "hostname", client-dependent mathematical
-  // expression, onelab mathematical expression (through mathex?), ...
+  // values). Kinds currently recognized by Gmsh are: "file", "macro". Possible
+  // kinds could be "complex", "matrix m n", "hostname", client-dependent
+  // mathematical expression, onelab mathematical expression (through mathex?),
+  // ...
   class string : public parameter{
   private:
     std::string _value, _kind;
diff --git a/Fltk/onelabWindow.cpp b/Fltk/onelabWindow.cpp
index ff1b71cdfe9c4751b719f7f6ac35770b9c8123bc..62863ca0d8a492c3fe2cf5504e5a36fbe9131377 100644
--- a/Fltk/onelabWindow.cpp
+++ b/Fltk/onelabWindow.cpp
@@ -600,7 +600,6 @@ void onelab_cb(Fl_Widget *w, void *data)
   if(action != "initialize") FlGui::instance()->onelab->show();
 }
 
-
 void onelab_option_cb(Fl_Widget *w, void *data)
 {
   if(!data) return;
@@ -610,6 +609,10 @@ void onelab_option_cb(Fl_Widget *w, void *data)
     CTX::instance()->solver.autoSaveDatabase = val;
   else if(what == "archive")
     CTX::instance()->solver.autoArchiveOutputFiles = val;
+  else if(what == "check"){
+    CTX::instance()->solver.autoCheck = val;
+    FlGui::instance()->onelab->setButtonVisibility();
+  }
   else if(what == "mesh")
     CTX::instance()->solver.autoMesh = val;
   else if(what == "merge")
@@ -737,6 +740,8 @@ onelabWindow::onelabWindow(int deltaFontSize)
              FL_MENU_TOGGLE);
   _gear->add("Archive output files automatically", 0, onelab_option_cb, (void*)"archive",
              FL_MENU_TOGGLE);
+  _gear->add("Check model after each change", 0, onelab_option_cb, (void*)"check",
+             FL_MENU_TOGGLE);
   _gear->add("Remesh automatically", 0, onelab_option_cb, (void*)"mesh",
              FL_MENU_TOGGLE);
   _gear->add("Merge results automatically", 0, onelab_option_cb, (void*)"merge",
@@ -758,6 +763,8 @@ onelabWindow::onelabWindow(int deltaFontSize)
     (CTX::instance()->solverPosition[0], CTX::instance()->solverPosition[1]);
   _win->end();
 
+  setButtonVisibility();
+
   FL_NORMAL_SIZE += _deltaFontSize;
 }
 
@@ -778,6 +785,15 @@ static bool getFlColor(const std::string &str, Fl_Color &c)
   return false;
 }
 
+template<class T>
+static void autoCheck(const T &pold, const T &pnew, bool force=false)
+{
+  if(!CTX::instance()->solver.autoCheck && pnew.getAttribute("AutoCheck") != "1")
+    return;
+  if(force || pold.getValue() != pnew.getValue())
+    onelab_cb(0, (void*)"check");
+}
+
 template<class T>
 void onelabWindow::_addParameter(T &p)
 {
@@ -802,8 +818,10 @@ static void onelab_number_check_button_cb(Fl_Widget *w, void *data)
   onelab::server::instance()->get(numbers, name);
   if(numbers.size()){
     Fl_Check_Button *o = (Fl_Check_Button*)w;
+    onelab::number old = numbers[0];
     numbers[0].setValue(o->value());
     onelab::server::instance()->set(numbers[0]);
+    autoCheck(old, numbers[0]);
   }
 }
 
@@ -816,8 +834,10 @@ static void onelab_number_choice_cb(Fl_Widget *w, void *data)
   if(numbers.size()){
     Fl_Choice *o = (Fl_Choice*)w;
     std::vector<double> choices = numbers[0].getChoices();
+    onelab::number old = numbers[0];
     if(o->value() < (int)choices.size()) numbers[0].setValue(choices[o->value()]);
     onelab::server::instance()->set(numbers[0]);
+    autoCheck(old, numbers[0]);
   }
 }
 
@@ -829,6 +849,7 @@ static void onelab_number_input_range_cb(Fl_Widget *w, void *data)
   onelab::server::instance()->get(numbers, name);
   if(numbers.size()){
     inputRange *o = (inputRange*)w;
+    onelab::number old = numbers[0];
     if(o->doCallbackOnValues()){
       numbers[0].setValue(o->value());
       numbers[0].setMin(o->minimum());
@@ -841,6 +862,7 @@ static void onelab_number_input_range_cb(Fl_Widget *w, void *data)
     numbers[0].setAttribute("Graph", o->graph());
     onelab::server::instance()->set(numbers[0]);
     updateGraphs();
+    autoCheck(old, numbers[0]);
   }
 }
 
@@ -913,6 +935,18 @@ Fl_Widget *onelabWindow::_addParameterWidget(onelab::number &p, Fl_Tree_Item *n,
   return but;
 }
 
+static void onelab_string_button_cb(Fl_Widget *w, void *data)
+{
+  if(!data) return;
+  std::string name = FlGui::instance()->onelab->getPath((Fl_Tree_Item*)data);
+  std::vector<onelab::string> strings;
+  onelab::server::instance()->get(strings, name);
+  if(strings.size()){
+    MergeFile(strings[0].getValue());
+    autoCheck(strings[0], strings[0], true);
+  }
+}
+
 static void onelab_string_input_choice_cb(Fl_Widget *w, void *data)
 {
   if(!data) return;
@@ -921,8 +955,10 @@ static void onelab_string_input_choice_cb(Fl_Widget *w, void *data)
   onelab::server::instance()->get(strings, name);
   if(strings.size()){
     Fl_Input_Choice *o = (Fl_Input_Choice*)w;
+    onelab::string old = strings[0];
     strings[0].setValue(o->value());
     onelab::server::instance()->set(strings[0]);
+    autoCheck(old, strings[0]);
   }
 }
 
@@ -954,6 +990,15 @@ static void onelab_input_choice_file_merge_cb(Fl_Widget *w, void *data)
 Fl_Widget *onelabWindow::_addParameterWidget(onelab::string &p, Fl_Tree_Item *n,
                                              bool highlight, Fl_Color c)
 {
+  // macro button
+  if(p.getKind() == "macro"){
+    Fl_Button *but = new Fl_Button(1, 1, _itemWidth, 1);
+    but->align(FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
+    but->callback(onelab_string_button_cb, (void*)n);
+    if(highlight) but->color(c);
+    return but;
+  }
+
   // non-editable value
   if(p.getReadOnly()){
     Fl_Output *but = new Fl_Output(1, 1, _itemWidth, 1);
@@ -1003,8 +1048,10 @@ static void onelab_region_input_cb(Fl_Widget *w, void *data)
   onelab::server::instance()->get(regions, name);
   if(regions.size()){
     inputRegion *o = (inputRegion*)w;
+    onelab::region old = regions[0];
     regions[0].setValue(o->value());
     onelab::server::instance()->set(regions[0]);
+    autoCheck(old, regions[0]);
   }
 }
 
@@ -1132,6 +1179,23 @@ void onelabWindow::checkForErrors(const std::string &client)
   }
 }
 
+void onelabWindow::setButtonVisibility()
+{
+  if(_butt[0]->visible() && CTX::instance()->solver.autoCheck){
+    _butt[0]->hide();
+    _gear->position(_gear->x() + _butt[0]->w() + WB, _gear->y());
+    _win->init_sizes();
+    _win->redraw();
+  }
+
+  if(!_butt[0]->visible() && !CTX::instance()->solver.autoCheck){
+    _butt[0]->show();
+    _gear->position(_gear->x() - _butt[0]->w() - WB, _gear->y());
+    _win->init_sizes();
+    _win->redraw();
+  }
+}
+
 void onelabWindow::setButtonMode(const std::string &butt0, const std::string &butt1)
 {
   if(butt0 == "check"){
@@ -1186,13 +1250,14 @@ void onelabWindow::rebuildSolverList()
   // update OneLab window title and gear menu
   _title = "OneLab";
   Fl_Menu_Item* menu = (Fl_Menu_Item*)_gear->menu();
-  int values[6] = {CTX::instance()->solver.autoSaveDatabase,
+  int values[7] = {CTX::instance()->solver.autoSaveDatabase,
                    CTX::instance()->solver.autoArchiveOutputFiles,
+                   CTX::instance()->solver.autoCheck,
                    CTX::instance()->solver.autoMesh,
                    CTX::instance()->solver.autoMergeFile,
                    CTX::instance()->solver.autoHideNewViews,
                    CTX::instance()->solver.autoShowLastStep};
-  for(int i = 0; i < 6; i++){
+  for(int i = 0; i < 7; i++){
     int idx = _gearOptionsStart - 1 + i;
     if(values[i])
       menu[idx].set();
diff --git a/Fltk/onelabWindow.h b/Fltk/onelabWindow.h
index 58fcb7f04c4675214df9c48ef5610e5dcf21cbaf..57ecc25e9a985d219087b5aa7f22be3a9d307b60 100644
--- a/Fltk/onelabWindow.h
+++ b/Fltk/onelabWindow.h
@@ -48,6 +48,7 @@ class onelabWindow{
   int h(){ return _win->h(); }
   void rebuildSolverList();
   void rebuildTree();
+  void setButtonVisibility();
   void setButtonMode(const std::string &butt0, const std::string &butt1);
   bool isBusy();
   void show(){ _win->show(); }
diff --git a/demos/indheat.geo b/demos/indheat.geo
index d1163445cec1b8415c06b46031727f6d293d151d..399a36c067f8f540f875d27df86db2ade1961495 100644
--- a/demos/indheat.geo
+++ b/demos/indheat.geo
@@ -10,10 +10,14 @@ DefineConstant
  ht = {0.4, Label "Tube height"},
  rt1 = {0.075, Label "Tube internal radius"},
  rt2 = {0.092, Label "Tube external radius"},
- lb = {1, Label "Infinite box width"}
+ lb = {1, Label "Infinite box width"},
  left = {1, Choices{0,1}, Label "Terminals on the left?"}
+ // macro = {"aa.pos", Label "Run my macro!", Kind "macro", Path "Actions"},
+ // showLines = {1, Choices {0,1}, Label "Show lines?"}
 ];
 
+//Geometry.Lines = showLines;
+
 // inductor
 p = newp;
 Point(p)={0, -r, -hc/2, lc};
@@ -32,8 +36,8 @@ s = news;
 Plane Surface(s) = {ll};
 tmp[] = {s};
 vol_coil[] = {};
-For j In {1:4*turns+(left?2:0)}
-  tmp[] = Extrude { {0,0,hc/turns/4}, {0,0,1} , {0,0,0} , Pi/2}
+For j In {1:4*Floor(turns)+(left?2:0)}
+  tmp[] = Extrude { {0,0,hc/Floor(turns)/4}, {0,0,1} , {0,0,0} , Pi/2}
                   { Surface {tmp[0]}; /*Layers {nn / 4};*/ };
   vol_coil[] += tmp[1];
 EndFor
@@ -143,5 +147,5 @@ Physical Surface(IN) = in;
 Physical Surface(OUT) = out;
 Physical Surface(INF) = {s:s+5};
 
-Homology(2) {{COIL,TUBE},{SKIN_COIL, SKIN_TUBE}};
-Cohomology(1) {{AIR},{}};
+//Homology(2) {{COIL,TUBE},{SKIN_COIL, SKIN_TUBE}};
+//Cohomology(1) {{AIR},{}};