Skip to content
Snippets Groups Projects
Select Git revision
  • cf473f274db07e19eec25f8c008243cf25173de8
  • master default protected
  • patches-4.14
  • steplayer
  • bl
  • pluginMeshQuality
  • fixBugsAmaury
  • hierarchical-basis
  • alphashapes
  • relaying
  • new_export_boris
  • oras_vs_osm
  • reassign_partitions
  • distributed_fwi
  • rename-classes
  • fix/fortran-api-example-t4
  • robust_partitions
  • reducing_files
  • fix_overlaps
  • 3115-issue-fix
  • 3023-Fillet2D-Update
  • gmsh_4_14_0
  • gmsh_4_13_1
  • gmsh_4_13_0
  • gmsh_4_12_2
  • gmsh_4_12_1
  • gmsh_4_12_0
  • gmsh_4_11_1
  • gmsh_4_11_0
  • gmsh_4_10_5
  • gmsh_4_10_4
  • gmsh_4_10_3
  • gmsh_4_10_2
  • gmsh_4_10_1
  • gmsh_4_10_0
  • gmsh_4_9_5
  • gmsh_4_9_4
  • gmsh_4_9_3
  • gmsh_4_9_2
  • gmsh_4_9_1
  • gmsh_4_9_0
41 results

Lambda2.h

Blame
  • onelab.h 40.60 KiB
    // ONELAB - Copyright (C) 2011-2016 ULg-UCL
    //
    // Permission is hereby granted, free of charge, to any person
    // obtaining a copy of this software and associated documentation
    // files (the "Software"), to deal in the Software without
    // restriction, including without limitation the rights to use, copy,
    // modify, merge, publish, distribute, and/or sell copies of the
    // Software, and to permit persons to whom the Software is furnished
    // to do so, provided that the above copyright notice(s) and this
    // permission notice appear in all copies of the Software and that
    // both the above copyright notice(s) and this permission notice
    // appear in supporting documentation.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    // NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
    // COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
    // ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
    // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
    // WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
    // ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
    // OF THIS SOFTWARE.
    //
    // Please report all bugs and problems to the public mailing list
    // <gmsh@onelab.info>.
    
    #ifndef _ONELAB_H_
    #define _ONELAB_H_
    
    #include <time.h>
    #include <stdio.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <map>
    #include <iostream>
    #include <sstream>
    #include "GmshSocket.h"
    
    namespace onelab{
    
      // The base parameter class.
      class parameter {
      private:
        // the name of the parameter, including its '/'-separated path in the
        // parameter hierarchy. Parameters or subpaths can start with numbers to
        // force their relative ordering (such numbers are automatically hidden in
        // the interface). All strings in onelab are supposed to be UTF8-encoded.
        std::string _name;
        // the parameter label: if provided it serves as a better way to display the
        // parameter in the interface
        std::string _label;
        // a help string
        std::string _help;
        // map of clients that use this parameter, associated with a "changed" flag
        // (set to false if the client has already been run with the current value of
        // the parameter)
        std::map<std::string, bool> _clients;
        // flag indicating that the "changed" flags of this parameter will always be
        // reset to false when the parameter is updated
        bool _neverChanged;
        // should the parameter be visible in the interface?
        bool _visible;
        // sould the paramete be "read-only" (not settable by the user)
        bool _readOnly;
      protected:
        // optional additional attributes
        std::map<std::string, std::string> _attributes;
      public:
        parameter(const std::string &name="", const std::string &label="",
                  const std::string &help="")
          : _name(name), _label(label), _help(help), _neverChanged(false),
            _visible(true), _readOnly(false) {}
        virtual ~parameter(){}
        void setName(const std::string &name){ _name = name; }
        void setLabel(const std::string &label){ _label = label; }
        void setHelp(const std::string &help){ _help = help; }
        void setChanged(bool changed, const std::string &client="")
        {
          if(client.size()){
            std::map<std::string, bool>::iterator it = _clients.find(client);
            if(it != _clients.end()) it->second = changed;
          }
          else{
            for(std::map<std::string, bool>::iterator it = _clients.begin();
                it != _clients.end(); it++)
              it->second = changed;
          }
        }
        void setNeverChanged(bool never){ _neverChanged = never; }
        void setVisible(bool visible){ _visible = visible; }
        void setReadOnly(bool readOnly){ _readOnly = readOnly; }
        void setAttribute(const std::string &key, const std::string &value)
        {
          _attributes[key] = value;
        }
        void setAttributes(const std::map<std::string, std::string> &attributes)
        {
          _attributes = attributes;
        }
        void setClients(const std::map<std::string, bool> &clients){ _clients = clients; }
        void addClient(const std::string &client, bool changed)
        {
          if(_clients.find(client) == _clients.end())
            _clients[client] = changed;
        }
        void addClients(const std::map<std::string, bool> &clients)
        {
          _clients.insert(clients.begin(), clients.end());
        }
        bool hasClient(const std::string &client)
        {
          return (_clients.find(client) != _clients.end());
        }
        int getNumClients() { return (int)_clients.size(); };
        virtual std::string getType() const = 0;
        const std::string &getName() const { return _name; }
        const std::string &getLabel() const { return _label; }
        const std::string &getHelp() const { return _help; }
        std::string getPath() const
        {
          std::string::size_type last = _name.find_last_of('/');
          return _name.substr(0, last);
        }
        std::string getShortName() const
        {
          if(_label.size()) return _label;
          std::string s = _name;
          // remove path
          std::string::size_type last = _name.find_last_of('/');
          if(last != std::string::npos)
            s = _name.substr(last + 1);
          // remove starting white space
          while(s.size() && s[0] == ' ')
            s = s.substr(1);
          // remove starting braces: can be used to order parameters 'from the end',
          // as the ASCII code is after numbers and letters
          while(s.size() && (s[0] == '}' || s[0] == '{'))
            s = s.substr(1);
          // remove starting numbers: can be used to order parameters 'from the
          // start'
          while(s.size() && s[0] >= '0' && s[0] <= '9')
            s = s.substr(1);
          return s;
        }
        bool getChanged(const std::string &client="") const
        {
          if(client.size()){
            std::map<std::string, bool>::const_iterator it = _clients.find(client);
            if(it != _clients.end()) return it->second;
            else return false;
          }
          else{
            for(std::map<std::string, bool>::const_iterator it = _clients.begin();
                it != _clients.end(); it++){
              if(it->second) return true;
            }
            return false;
          }
        }
        bool getNeverChanged() const { return _neverChanged; }
        bool getVisible() const { return _visible; }
        bool getReadOnly() const { return _readOnly; }
        std::string getAttribute(const std::string &key) const
        {
          std::map<std::string, std::string>::const_iterator it = _attributes.find(key);
          if(it != _attributes.end()) return it->second;
          return "";
        }
        const std::map<std::string, std::string> &getAttributes() const
        {
          return _attributes;
        }
        const std::map<std::string, bool> &getClients() const { return _clients; }
        static char charSep() { return '\0'; }
        static double maxNumber() { return 1e200; }
        static std::string version() { return "1.1"; }
        static std::string getNextToken(const std::string &msg,
                                        std::string::size_type &first,
                                        char separator=charSep())
        {
          if(first == std::string::npos) return "";
          std::string::size_type last = msg.find_first_of(separator, first);
          std::string next("");
          if(last == std::string::npos){
            next = msg.substr(first);
            first = last;
          }
          else if(first == last){
            next = "";
            first = last + 1;
          }
          else{
            next = msg.substr(first, last - first);
            first = last + 1;
          }
          return next;
        }
        static std::vector<std::string> split(const std::string &msg,
                                              char separator=charSep())
        {
          std::vector<std::string> out;
          std::string::size_type first = 0;
          while(first != std::string::npos)
            out.push_back(getNextToken(msg, first, separator));
          return out;
        }
        std::string sanitize(const std::string &in) const
        {
          std::string out(in);
          for(unsigned int i = 0; i < in.size(); i++)
            if(out[i] == charSep()) out[i] = ' ';
          return out;
        }
        virtual std::string toChar() const
        {
          std::ostringstream sstream;
          sstream << version() << charSep() << getType() << charSep()
                  << sanitize(getName()) << charSep()
                  << sanitize(getLabel()) << charSep()
                  << sanitize(getHelp()) << charSep()
                  << (getNeverChanged() ? 1 : 0) << charSep()
                  << (getVisible() ? 1 : 0) << charSep()
                  << (getReadOnly() ? 1 : 0) << charSep()
                  << _attributes.size() << charSep();
          for(std::map<std::string, std::string>::const_iterator it = _attributes.begin();
              it != _attributes.end(); it++)
            sstream << sanitize(it->first) << charSep()
                    << sanitize(it->second) << charSep();
          sstream << getClients().size() << charSep();
          for(std::map<std::string, bool>::const_iterator it = getClients().begin();
              it != getClients().end(); it++)
            sstream << sanitize(it->first) << charSep()
                    << (it->second ? 1 : 0) << charSep();
          return sstream.str();
        }
        virtual std::string::size_type fromChar(const std::string &msg)
        {
          std::string::size_type pos = 0;
          if(getNextToken(msg, pos) != version()) return 0;
          if(getNextToken(msg, pos) != getType()) return 0;
          setName(getNextToken(msg, pos));
          setLabel(getNextToken(msg, pos));
          setHelp(getNextToken(msg, pos));
          setNeverChanged(atoi(getNextToken(msg, pos).c_str()));
          setVisible(atoi(getNextToken(msg, pos).c_str()));
          setReadOnly(atoi(getNextToken(msg, pos).c_str()));
          int numAttributes = atoi(getNextToken(msg, pos).c_str());
          for(int i = 0; i < numAttributes; i++){
            std::string key(getNextToken(msg, pos));
            setAttribute(key, getNextToken(msg, pos));
          }
          int numClients = atoi(getNextToken(msg, pos).c_str());
          for(int i = 0; i < numClients; i++){
            std::string client(getNextToken(msg, pos));
            int changed = atoi(getNextToken(msg, pos).c_str());
            addClient(client, changed ? true : false);
          }
          return pos;
        }
        static void getInfoFromChar(const std::string &msg, std::string &version,
                                    std::string &type, std::string &name)
        {
          std::string::size_type first = 0;
          version = getNextToken(msg, first);
          type = getNextToken(msg, first);
          name = getNextToken(msg, first);
        }
        static bool fromFile(std::vector<std::string> &msg,
                             FILE *fp)
        {
          msg.clear();
          char tmp[1000];
          if(!fgets(tmp, sizeof(tmp), fp)) return false; // first line is comment
          while(!feof(fp)){
            int numc = 0;
            if(!fscanf(fp, "%d ", &numc)) break; // space is important
            if(!numc) break;
            msg.push_back("");
            for(int i = 0; i < numc; i++)
              msg.back() += fgetc(fp);
            if(!fgets(tmp, sizeof(tmp), fp)) break; // end of line
          }
          return true;
        }
        static bool toFile(const std::vector<std::string> &msg,
                           FILE *fp,
                           const std::string &creator)
        {
          time_t now;
          time(&now);
          fprintf(fp, "ONELAB database created by %s on %s",
                  creator.c_str(), ctime(&now));
          for(unsigned int i = 0; i < msg.size(); i++){
            fprintf(fp, "%d ", (int)msg[i].size());
            for(unsigned int j = 0; j < msg[i].size(); j++)
              fputc(msg[i][j], fp);
            fputc('\n', fp);
          }
          return true;
        }
      };
    
      class parameterLessThan{
      public:
        bool operator()(const parameter *p1, const parameter *p2) const
        {
          return p1->getName() < p2->getName();
        }
      };
    
      // The number class. Numbers are stored internally as double precision real
      // numbers. All more complicated types (complex numbers, vectors, expressions,
      // functions, etc.) are supposed to be exchanged as strings.
      class number : public parameter{
      private:
        double _value, _min, _max, _step;
        // when in a loop, indicates current index in the vector _choices;
        // is -1 when not in a loop
        int _index;
        std::vector<double> _choices;
        std::map<double, std::string> _valueLabels;
      public:
        number(const std::string &name="", double value=0.,
               const std::string &label="", const std::string &help="")
          : parameter(name, label, help), _value(value),
          _min(-maxNumber()), _max(maxNumber()), _step(0.), _index(-1) {}
        void setValue(double value){ _value = value; }
        void setMin(double min){ _min = min; }
        void setMax(double max){ _max = max; }
        void setStep(double step){ _step = step; }
        void setIndex(int index){ _index = index; }
        void setChoices(const std::vector<double> &choices){ _choices = choices; }
        void setChoiceLabels(const std::vector<std::string> &labels)
        {
          if(labels.size() != _choices.size()) return;
          for(unsigned int i = 0; i < _choices.size(); i++)
            _valueLabels[_choices[i]] = labels[i];
        }
        void setValueLabels(const std::map<double, std::string> &valueLabels)
        {
          _valueLabels = valueLabels;
        }
        void setValueLabel(double value, const std::string &label)
        {
          _valueLabels[value] = label;
        }
        std::string getType() const { return "number"; }
        double getValue() const { return _value; }
        double getMin() const { return _min; }
        double getMax() const { return _max; }
        double getStep() const { return _step; }
        int getIndex() const { return _index; }
        const std::vector<double> &getChoices() const { return _choices; }
        const std::map<double, std::string> &getValueLabels() const
        {
          return _valueLabels;
        }
        std::string getValueLabel(double value) const
        {
          std::map<double, std::string>::const_iterator it = _valueLabels.find(value);
          if(it != _valueLabels.end()) return it->second;
          return "";
        }
        void update(const number &p)
        {
          addClients(p.getClients());
          setLabel(p.getLabel());
          setHelp(p.getHelp());
          setVisible(p.getVisible());
          setReadOnly(p.getReadOnly());
          setAttributes(p.getAttributes());
          if(p.getValue() != getValue()){
            setValue(p.getValue());
            setChanged(true);
          }
          setMin(p.getMin());
          setMax(p.getMax());
          setStep(p.getStep());
          setIndex(p.getIndex());
          setChoices(p.getChoices());
          setValueLabels(p.getValueLabels());
          if(getNeverChanged()) setChanged(false);
        }
        std::string toChar() const
        {
          std::ostringstream sstream;
          sstream.precision(16);
          sstream << parameter::toChar() << _value << charSep()
                  << _min << charSep() << _max << charSep() << _step << charSep()
    	      << _index << charSep()
                  << _choices.size() << charSep();
          for(unsigned int i = 0; i < _choices.size(); i++)
            sstream << _choices[i] << charSep();
          sstream << _valueLabels.size() << charSep();
          for(std::map<double, std::string>::const_iterator it = _valueLabels.begin();
              it != _valueLabels.end(); it++){
            sstream << it->first << charSep();
            sstream << sanitize(it->second) << charSep();
          }
          return sstream.str();
        }
        std::string::size_type fromChar(const std::string &msg)
        {
          std::string::size_type pos = parameter::fromChar(msg);
          if(!pos) return 0;
          setValue(atof(getNextToken(msg, pos).c_str()));
          setMin(atof(getNextToken(msg, pos).c_str()));
          setMax(atof(getNextToken(msg, pos).c_str()));
          setStep(atof(getNextToken(msg, pos).c_str()));
          setIndex(atoi(getNextToken(msg, pos).c_str()));
          _choices.resize(atoi(getNextToken(msg, pos).c_str()));
          for(unsigned int i = 0; i < _choices.size(); i++)
            _choices[i] = atof(getNextToken(msg, pos).c_str());
          int numValueLabels = atoi(getNextToken(msg, pos).c_str());
          for(int i = 0; i < numValueLabels; i++){
            double value = atof(getNextToken(msg, pos).c_str());
            _valueLabels[value] = getNextToken(msg, pos);
          }
          return pos;
        }
      };
    
      // 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?),
      // ...
      class string : public parameter{
      private:
        std::string _value, _kind;
        std::vector<std::string> _choices;
      public:
        string(const std::string &name="", const std::string &value="",
               const std::string &label="", const std::string &help="")
          : parameter(name, label, help), _value(value), _kind("generic") {}
        void setValue(const std::string &value){ _value = value; }
        void setKind(const std::string &kind){ _kind = kind; }
        void setChoices(const std::vector<std::string> &choices){ _choices = choices; }
        std::string getType() const { return "string"; }
        const std::string &getValue() const { return _value; }
        const std::string &getKind() const { return _kind; }
        const std::vector<std::string> &getChoices() const { return _choices; }
        void update(const string &p)
        {
          addClients(p.getClients());
          setLabel(p.getLabel());
          setHelp(p.getHelp());
          setVisible(p.getVisible());
          setReadOnly(p.getReadOnly());
          setAttributes(p.getAttributes());
          if(p.getValue() != getValue()){
            setValue(p.getValue());
            setChanged(true);
          }
          if(p.getKind() != getKind()){
            setKind(p.getKind());
            setChanged(true);
          }
          setChoices(p.getChoices());
          if(getNeverChanged()) setChanged(false);
        }
        std::string toChar() const
        {
          std::ostringstream sstream;
          sstream << parameter::toChar() << sanitize(_value) << charSep()
                  << sanitize(_kind) << charSep()
                  << _choices.size() << charSep();
          for(unsigned int i = 0; i < _choices.size(); i++)
            sstream << sanitize(_choices[i]) << charSep();
          return sstream.str();
        }
        std::string::size_type fromChar(const std::string &msg)
        {
          std::string::size_type pos = parameter::fromChar(msg);
          if(!pos) return 0;
          setValue(getNextToken(msg, pos));
          setKind(getNextToken(msg, pos));
          _choices.resize(atoi(getNextToken(msg, pos).c_str()));
          for(unsigned int i = 0; i < _choices.size(); i++)
            _choices[i] = getNextToken(msg, pos);
          return pos;
        }
      };
    
      // The parameter space, i.e., the set of parameters stored and handled by the
      // onelab server.
      class parameterSpace{
      private:
        std::set<number*, parameterLessThan> _numbers;
        std::set<string*, parameterLessThan> _strings;
        // delete a parameter from the parameter space
        template <class T> bool _clear(const std::string &name,
                                       const std::string &client,
                                       std::set<T*, parameterLessThan> &ps)
        {
          if(name.empty() && client.size()){
            std::vector<T*> toDelete;
            for(typename std::set<T*, parameterLessThan>::iterator it = ps.begin();
                it != ps.end(); ){
              T *p = *it;
              if(p->hasClient(client)){
                ps.erase(it++); // to avoid invalid iterator
                delete p;
              }
              else{
                it++;
              }
            }
          }
          else{
            T tmp(name);
            typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp);
            if(it != ps.end()){
              T *p = *it;
              if(client.empty() || p->hasClient(client)){
                ps.erase(it);
                delete p;
                return true;
              }
            }
          }
          return false;
        }
        // set a parameter in the parameter space; if it already exists, update it
        // (adding new clients if necessary). This would need to be locked to avoid
        // race conditions when several clients try to set a parameter at the same
        // time.
        template <class T> bool _set(const T &p, const std::string &client,
                                     std::set<T*, parameterLessThan> &ps)
        {
          typename std::set<T*, parameterLessThan>::iterator it = ps.find((T*)&p);
          if(it != ps.end()){
            (*it)->update(p);
            if(client.size()) (*it)->addClient(client, true);
          }
          else{
            T* newp = new T(p);
            if(client.size()) newp->addClient(client, true);
            ps.insert(newp);
          }
          return true;
        }
        // get the parameter matching the given name, or all the parameters in the
        // category if no name is given. If we find a given parameter by name, we
        // add the client requesting the parameter to the list of clients for this
        // parameter. This would also need to be locked.
        template <class T> bool _get(std::vector<T> &p, const std::string &name,
                                     const std::string &client,
                                     std::set<T*, parameterLessThan> &ps)
        {
          p.clear();
          if(name.empty()){
            for(typename std::set<T*, parameterLessThan>::iterator it = ps.begin();
                it != ps.end(); it++)
              p.push_back(**it);
          }
          else{
            T tmp(name);
            typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp);
            if(it != ps.end()){
              if(client.size()) (*it)->addClient(client, true);
              p.push_back(**it);
            }
          }
          return true;
        }
        template <class T> T* _getPtr(std::string name, const std::string client, std::set<T*, parameterLessThan> ps)
        {
          T tmp(name);
          typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp);
          if(it != ps.end()){
            if(client.size()) (*it)->addClient(client, true);
            return *it;
          }
          return NULL;
        }
        void _getAllParameters(std::set<parameter*, parameterLessThan> &ps) const
        {
          ps.insert(_numbers.begin(), _numbers.end());
          ps.insert(_strings.begin(), _strings.end());
        }
      public:
        parameterSpace(){}
        ~parameterSpace(){ clear(); }
        void clear(const std::string &name="", const std::string &client="")
        {
          if(name.empty() && client.empty()){
            std::set<parameter*, parameterLessThan> ps;
            _getAllParameters(ps);
            for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
                it != ps.end(); it++)
              delete *it;
            _numbers.clear();
            _strings.clear();
          }
          else{
            bool done = _clear(name, client, _numbers);
            if(!done) done = _clear(name, client, _strings);
          }
        }
        bool set(const number &p,
                 const std::string &client=""){ return _set(p, client, _numbers); }
        bool set(const string &p,
                 const std::string &client=""){ return _set(p, client, _strings); }
        bool get(std::vector<number> &ps, const std::string &name="",
                 const std::string &client=""){ return _get(ps, name, client, _numbers); }
        bool get(std::vector<onelab::string> &ps, const std::string &name="",
                 const std::string &client=""){ return _get(ps, name, client, _strings); }
        void getPtr(number **ptr, const std::string name, const std::string client="")
          {*ptr = _getPtr(name, client, _numbers);}
        void getPtr(string **ptr, const std::string name, const std::string client="")
          {*ptr = _getPtr(name, client, _strings);}
        void getAllParameters(std::set<parameter*, parameterLessThan> &ps) const
        {
          ps.insert(_numbers.begin(), _numbers.end());
          ps.insert(_strings.begin(), _strings.end());
        }
        unsigned int getNumParameters()
        {
          return (int)(_numbers.size() + _strings.size());
        }
        // check if at least one parameter depends on the given client
        bool hasClient(const std::string &client) const
        {
          std::set<parameter*, parameterLessThan> ps;
          _getAllParameters(ps);
          for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
              it != ps.end(); it++)
            if((*it)->hasClient(client)) return true;
          return false;
        }
        // check if some parameters have changed (optionnally only check the
        // parameters that depend on a given client)
        bool getChanged(const std::string &client="") const
        {
          std::set<parameter*, parameterLessThan> ps;
          _getAllParameters(ps);
          for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
              it != ps.end(); it++){
            if((*it)->getChanged(client)){
              return true;
            }
          }
          return false;
        }
        // set the changed flag for all the parameters that depend on the given
        // client (or for all parameters if no client name is provided)
        void setChanged(bool changed, const std::string &client="")
        {
          std::set<parameter*, parameterLessThan> ps;
          _getAllParameters(ps);
          for(std::set<parameter*, parameterLessThan>::iterator it = ps.begin();
              it != ps.end(); it++)
            (*it)->setChanged(changed, client);
        }
        // serialize the parameter space (optionally only serialize those parameters
        // that depend on the given client)
        std::vector<std::string> toChar(const std::string &client="") const
        {
          std::vector<std::string> s;
          std::set<parameter*, parameterLessThan> ps;
          _getAllParameters(ps);
          for(std::set<parameter*, parameterLessThan>::const_iterator it = ps.begin();
              it != ps.end(); it++)
            if(client.empty() || (*it)->hasClient(client)){
    	  if((*it)->getAttribute("NotInDb") != "True")
    	    s.push_back((*it)->toChar());
    	}
          return s;
        }
        // unserialize the parameter space
        bool fromChar(const std::vector<std::string> &msg, const std::string &client="")
        {
          for(unsigned int i = 0; i < msg.size(); i++){
            std::string version, type, name;
            onelab::parameter::getInfoFromChar(msg[i], version, type, name);
            if(onelab::parameter::version() != version) return false;
            if(type == "number"){
              onelab::number p; p.fromChar(msg[i]); set(p, client);
            }
            else if(type == "string"){
              onelab::string p; p.fromChar(msg[i]); set(p, client);
            }
            else
              return false;
          }
          return true;
        }
      };
    
      // The onelab client: a class that communicates with the onelab server. Each
      // client should be derived from this one. A client can be understood as "one
      // simulation step in a complex computation".
      class client{
      protected:
        // the name of the client
        std::string _name;
        // the id of the client, used to create a unique socket for this client
        int _id;
        // the index of the client in an external client list (if any)
        int _index;
      public:
        client(const std::string &name) : _name(name), _id(0), _index(-1){}
        virtual ~client(){}
        std::string getName(){ return _name; }
        void setId(int id){ _id = id; }
        int getId(){ return _id; }
        void setIndex(int index){ _index = index; }
        int getIndex(){ return _index; }
        virtual bool run(){ return false; }
        virtual bool isNetworkClient(){ return false; }
        virtual bool kill(){ return false; }
        virtual void sendInfo(const std::string &msg){ std::cout << msg << std::endl; }
        virtual void sendWarning(const std::string &msg){ std::cerr << msg << std::endl; }
        virtual void sendError(const std::string &msg){ std::cerr << msg << std::endl; }
        virtual void sendProgress(const std::string &msg){ std::cout << msg << std::endl; }
        virtual void sendMergeFileRequest(const std::string &msg){}
        virtual void sendOpenProjectRequest(const std::string &msg){}
        virtual void sendParseStringRequest(const std::string &msg){}
        virtual void sendVertexArray(const std::string &msg){}
        virtual bool clear(const std::string &name) = 0;
        virtual bool set(const number &p) = 0;
        virtual bool set(const string &p) = 0;
        virtual bool get(std::vector<number> &ps, const std::string &name="") = 0;
        virtual bool get(std::vector<onelab::string> &ps, const std::string &name="") = 0;
        std::vector<std::string> toChar()
        {
          std::vector<std::string> out;
          std::vector<number> n; get(n);
          for(unsigned int i = 0; i < n.size(); i++) out.push_back(n[i].toChar());
          std::vector<string> s; get(s);
          for(unsigned int i = 0; i < s.size(); i++) out.push_back(s[i].toChar());
          return out;
        }
        bool fromChar(const std::vector<std::string> &msg)
        {
          for(unsigned int i = 0; i < msg.size(); i++){
            std::string version, type, name;
            onelab::parameter::getInfoFromChar(msg[i], version, type, name);
            if(onelab::parameter::version() != version) return false;
            if(type == "number"){
              onelab::number p; p.fromChar(msg[i]); set(p);
            }
            else if(type == "string"){
              onelab::string p; p.fromChar(msg[i]); set(p);
            }
            else
              return false;
          }
          return true;
        }
        bool toFile(FILE *fp)
        {
          return parameter::toFile(toChar(), fp, getName());
        }
        bool fromFile(FILE *fp)
        {
          std::vector<std::string> msg;
          if(parameter::fromFile(msg, fp)) return fromChar(msg);
          return false;
        }
      };
      // The onelab server: a singleton that stores the parameter space and
      // interacts with onelab clients.
      class server{
      private:
        // the unique server (singleton behaviour due to the "static" specifier)
        static server *_server;
        // the address of the server
        std::string _address;
        // the connected clients
        std::set<client*> _clients;
        // the parameter space
        parameterSpace _parameterSpace;
      public:
        server(const std::string &address="") : _address(address) {}
        ~server(){}
        static server *instance(const std::string &address="")
        {
          if(!_server) _server = new server(address);
          return _server;
        }
        static void setInstance(server *s) { _server = s; }
        void clear(const std::string &name="", const std::string &client="")
        {
          _parameterSpace.clear(name, client);
        }
        template <class T> bool set(const T &p, const std::string &client="")
        {
          return _parameterSpace.set(p, client);
        }
        template <class T> bool get(std::vector<T> &ps, const std::string &name="",
                                    const std::string &client="")
        {
          return _parameterSpace.get(ps, name, client);
        }
        typedef std::set<client*>::iterator citer;
        citer firstClient(){ return _clients.begin(); }
        citer lastClient(){ return _clients.end(); }
        int getNumClients() { return (int)_clients.size(); };
        citer findClient(const std::string &name)
        {
          for(citer it = _clients.begin(); it != _clients.end(); it++)
            if((*it)->getName() == name) return it;
          return _clients.end();
        }
        void registerClient(client *c)
        {
          _clients.insert(c);
          c->setId(_clients.size());
        }
        void unregisterClient(client *c){ _clients.erase(c); }
        void setChanged(bool changed, const std::string &client="")
        {
          _parameterSpace.setChanged(changed, client);
        }
        bool getChanged(const std::string &client="")
        {
          return _parameterSpace.getChanged(client);
        }
        unsigned int getNumParameters(){ return _parameterSpace.getNumParameters(); }
        std::vector<std::string> toChar(const std::string &client="")
        {
          return _parameterSpace.toChar(client);
        }
        bool fromChar(const std::vector<std::string> &msg, const std::string &client="")
        {
          return _parameterSpace.fromChar(msg, client);
        }
        bool toFile(FILE *fp, const std::string &client="")
        {
          return parameter::toFile(toChar(client), fp, "onelab server");
        }
        bool fromFile(FILE *fp, const std::string &client="")
        {
          std::vector<std::string> msg;
          if(parameter::fromFile(msg, fp)) return fromChar(msg, client);
          return false;
        }
      };
    
      // A local client, which lives in the same memory space as the server.
      class localClient : public client{
      private:
        template <class T> bool _set(const T &p)
        {
          server::instance()->set(p, _name);
          return true;
        }
        template <class T> bool _get(std::vector<T> &ps,
                                     const std::string &name="")
        {
          server::instance()->get(ps, name, _name);
          return true;
        }
      public:
        localClient(const std::string &name) : client(name)
        {
          server::instance()->registerClient(this);
        }
        virtual ~localClient()
        {
          server::instance()->unregisterClient(this);
        }
        virtual bool clear(const std::string &name="")
        {
          server::instance()->clear(name);
          return true;
        }
        virtual bool set(const number &p){ return _set(p); }
        virtual bool set(const string &p){ return _set(p); }
        virtual bool get(std::vector<number> &ps,
                         const std::string &name=""){ return _get(ps, name); }
        virtual bool get(std::vector<onelab::string> &ps,
                         const std::string &name=""){ return _get(ps, name); }
      };
    
      // The local part of a network client.
      class localNetworkClient : public localClient{
      private:
        // executable of the client (including filesystem path, if necessary)
        std::string _executable;
        // treat the executable name as a full command line (will prevent the
        // escaping of the exe name, and will assume that the command line has been
        // correcly escaped)
        bool _treatExecutableAsFullCommandLine;
        // command to login to a remote host (if necessary)
        std::string _remoteLogin;
        // command line option to specify socket
        std::string _socketSwitch;
        // pid of the remote network client while it is running (-1 otherwise)
        int _pid;
        // underlying GmshServer
        GmshServer *_gmshServer;
      public:
        localNetworkClient(const std::string &name, const std::string &executable,
                           const std::string &remoteLogin="",
                           bool treatExecutableAsFullCommandLine=false)
          : localClient(name), _executable(executable),
            _treatExecutableAsFullCommandLine(treatExecutableAsFullCommandLine),
            _remoteLogin(remoteLogin), _socketSwitch("-onelab"), _pid(-1),
            _gmshServer(0) {}
        virtual ~localNetworkClient(){}
        virtual bool isNetworkClient(){ return true; }
        const std::string &getExecutable(){ return _executable; }
        void setExecutable(const std::string &s){ _executable = s; }
        const std::string &getRemoteLogin(){ return _remoteLogin; }
        bool treatExecutableAsFullCommandLine() const
        {
          return _treatExecutableAsFullCommandLine;
        }
        void setRemoteLogin(const std::string &s){ _remoteLogin = s; }
        const std::string &getSocketSwitch(){ return _socketSwitch; }
        void setSocketSwitch(const std::string &s){ _socketSwitch = s; }
        int getPid(){ return _pid; }
        void setPid(int pid){ _pid = pid; }
        GmshServer *getGmshServer(){ return _gmshServer; }
        void setGmshServer(GmshServer *server){ _gmshServer = server; }
        virtual bool run() = 0;
        virtual bool kill() = 0;
      };
    
      // The remote part of a network client.
      class remoteNetworkClient : public client{
      private:
        // address (inet:port or unix socket) of the server
        std::string _serverAddress;
        // underlying GmshClient
        GmshClient *_gmshClient;
        // number of subclients
        int _numSubClients;
        template <class T> bool _set(const T &p)
        {
          if(!_gmshClient) return false;
          std::string msg = p.toChar();
          _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER, msg.size(), &msg[0]);
          return true;
        }
        template <class T> bool _get(std::vector<T> &ps,
                                     const std::string &name="")
        {
          ps.clear();
          if(!_gmshClient) return false;
          T p(name);
          std::string msg = p.toChar();
          if (name.size())
    	_gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_QUERY, msg.size(), &msg[0]);
          else // get all parameters
    	_gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_QUERY_ALL, msg.size(), &msg[0]);
    
          while(1){
            // stop if we have no communications for 5 minutes
            int ret = _gmshClient->Select(500, 0);
            if(!ret){
              _gmshClient->Info("Timout: aborting remote get");
              return false;
            }
            else if(ret < 0){
              _gmshClient->Error("Error on select: aborting remote get");
              return false;
            }
            int type, length, swap;
            if(!_gmshClient->ReceiveHeader(&type, &length, &swap)){
              _gmshClient->Error("Did not receive message header: aborting remote get");
              return false;
            }
            std::string msg(length, ' ');
            if(!_gmshClient->ReceiveMessage(length, &msg[0])){
              _gmshClient->Error("Did not receive message body: aborting remote get");
              return false;
            }
            if(type == GmshSocket::GMSH_PARAMETER){
              T p;
              p.fromChar(msg);
              ps.push_back(p);
              return true;
            }
            if(type == GmshSocket::GMSH_PARAMETER_QUERY_ALL){
              T p;
              p.fromChar(msg);
              ps.push_back(p);
              // do NOT return until all parameters have been downloaded
            }
            else if(type == GmshSocket::GMSH_PARAMETER_QUERY_END){
    	  // all parameters have been sent
              return true;
            }
            else if(type == GmshSocket::GMSH_PARAMETER_NOT_FOUND){
              // parameter not found
              return true;
            }
            else if(type == GmshSocket::GMSH_INFO){
              return true;
            }
            else{
              _gmshClient->Error("Unknown message type: aborting remote get");
              return false;
            }
          }
          return true;
        }
      public:
        void waitOnSubClients()
        {
          if(!_gmshClient) return;
          while(_numSubClients > 0){
            int ret = _gmshClient->Select(500, 0);
            if(!ret){
              _gmshClient->Info("Timout: aborting wait on subclients");
              return;
            }
            else if(ret < 0){
              _gmshClient->Error("Error on select: aborting wait on subclients");
              return;
            }
            int type, length, swap;
            if(!_gmshClient->ReceiveHeader(&type, &length, &swap)){
              _gmshClient->Error("Did not receive message header: aborting wait on subclients");
              return;
            }
            std::string msg(length, ' ');
            if(!_gmshClient->ReceiveMessage(length, &msg[0])){
              _gmshClient->Error("Did not receive message body: aborting wait on subclients");
              return;
            }
            if(type == GmshSocket::GMSH_STOP)
              _numSubClients -= 1;
          }
        }
      public:
        remoteNetworkClient(const std::string &name, const std::string &serverAddress)
          : client(name), _serverAddress(serverAddress), _numSubClients(0)
        {
          _gmshClient = new GmshClient();
          if(_gmshClient->Connect(_serverAddress.c_str()) < 0){
            delete _gmshClient;
            _gmshClient = 0;
          }
          else{
            _gmshClient->Start();
          }
        }
        virtual ~remoteNetworkClient()
        {
          if(_gmshClient){
            waitOnSubClients();
            _gmshClient->Stop();
            _gmshClient->Disconnect();
            delete _gmshClient;
            _gmshClient = 0;
          }
        }
        GmshClient *getGmshClient(){ return _gmshClient; }
        virtual bool isNetworkClient(){ return true; }
        virtual bool clear(const std::string &name="")
        {
          if(!_gmshClient) return false;
          std::string msg = name;
          if(msg.empty()) msg = "*";
          _gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_CLEAR, msg.size(), &msg[0]);
          return true;
        }
        virtual bool set(const number &p){ return _set(p); }
        virtual bool set(const string &p){ return _set(p); }
        virtual bool get(std::vector<number> &ps,
                         const std::string &name=""){ return _get(ps, name); }
        virtual bool get(std::vector<onelab::string> &ps,
                         const std::string &name=""){ return _get(ps, name); }
        void sendInfo(const std::string &msg)
        {
          if(_gmshClient) _gmshClient->Info(msg.c_str());
        }
        void sendWarning(const std::string &msg)
        {
          if(_gmshClient) _gmshClient->Warning(msg.c_str());
        }
        void sendError(const std::string &msg)
        {
          if(_gmshClient) _gmshClient->Error(msg.c_str());
        }
        void sendProgress(const std::string &msg)
        {
          if(_gmshClient) _gmshClient->Progress(msg.c_str());
        }
        void sendMergeFileRequest(const std::string &msg)
        {
          if(_gmshClient) _gmshClient->MergeFile(msg.c_str());
        }
        void sendOpenProjectRequest(const std::string &msg)
        {
          if(_gmshClient) _gmshClient->OpenProject(msg.c_str());
        }
        void sendParseStringRequest(const std::string &msg)
        {
          if(_gmshClient) _gmshClient->ParseString(msg.c_str());
        }
        void runNonBlockingSubClient(const std::string &name, const std::string &command)
        {
          if(!_gmshClient){
            system(command.c_str());
            return;
          }
          std::string msg = name + parameter::charSep() + command;
          _gmshClient->SendMessage(GmshSocket::GMSH_CONNECT, msg.size(), &msg[0]);
          _numSubClients += 1;
        }
        void runSubClient(const std::string &name, const std::string &command)
        {
          runNonBlockingSubClient(name, command);
          waitOnSubClients();
        }
      };
    
    }
    
    #endif