Select Git revision
elasticitySolver.h
-
Christophe Geuzaine authoredChristophe Geuzaine authored
onelab.h 61.21 KiB
// ONELAB - Copyright (C) 2011-2019 Universite de Liege - Universite catholique
// de Louvain
//
// 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.
#ifndef _ONELAB_H_
#define _ONELAB_H_
#include <time.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <algorithm>
#include <sstream>
#if __cplusplus >= 201103L
#include <mutex>
#endif
#include "GmshSocket.h"
#define HAVE_PICOJSON
#if defined(HAVE_PICOJSON)
#include "picojson.h"
#endif
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 0 if the client has already been run with the current value of
// the parameter; set to defaultChangedValue() when the value of a parameter
// has been changed; values between 1 and defaultChangedValue() can be used
// to "modulate" the degree of change, e.g. to change the action to be
// performed depending on the "severity" of the change)
std::map<std::string, int> _clients;
// flag indicating what the "changed" value should be set to when a
// parameter is updated to a different value (if set to 0, the parameter
// will appear as never being changed)
int _changedValue;
// 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), _visible(true),
_readOnly(false)
{
_changedValue = defaultChangedValue();
}
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(int changed, const std::string &client = "")
{
if(client.size()) {
std::map<std::string, int>::iterator it = _clients.find(client);
if(it != _clients.end()) it->second = changed;
}
else {
for(std::map<std::string, int>::iterator it = _clients.begin();
it != _clients.end(); it++)
it->second = changed;
}
}
void setChangedValue(int value) { _changedValue = value; }
void setNeverChanged(bool never)
{
_changedValue = never ? 0 : defaultChangedValue();
}
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, int> &clients)
{
_clients = clients;
}
void addClient(const std::string &client, int changed)
{
if(_clients.find(client) == _clients.end()) _clients[client] = changed;
}
void addClients(const std::map<std::string, int> &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
{
std::string units = getAttribute("Units");
if(_label.size()) {
if(units.empty())
return _label;
else
return _label + " [" + units + "]";
}
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);
if(units.empty())
return s;
else
return s + " [" + units + "]";
}
int getChanged(const std::string &client = "") const
{
if(client.size()) {
std::map<std::string, int>::const_iterator it = _clients.find(client);
if(it != _clients.end())
return it->second;
else
return 0;
}
else {
int changed = 0;
for(std::map<std::string, int>::const_iterator it = _clients.begin();
it != _clients.end(); it++) {
changed = std::max(changed, it->second);
}
return changed;
}
}
int getChangedValue() const { return _changedValue; }
bool getNeverChanged() const { return _changedValue ? false : true; }
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, int> &getClients() const { return _clients; }
static char charSep() { return '\0'; }
static double maxNumber() { return 1e200; }
static std::string version() { return "1.3"; }
static int defaultChangedValue() { return 31; }
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;
}
static std::string trim(const std::string &str,
const std::string &whitespace = " \t\n")
{
std::string::size_type strBegin = str.find_first_not_of(whitespace);
if(strBegin == std::string::npos) return ""; // no content
std::string::size_type strEnd = str.find_last_not_of(whitespace);
std::string::size_type strRange = strEnd - strBegin + 1;
return str.substr(strBegin, strRange);
}
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()
<< getChangedValue() << 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, int>::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));
setChangedValue(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);
}
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;
}
std::string sanitizeJSON(const std::string &in) const
{
// FIXME: replace \n with \\n, \t with \\t, etc.
return in;
}
virtual std::string toJSON() const
{
std::ostringstream sstream;
sstream << "\"type\":\"" << getType() << "\""
<< ", \"name\":\"" << sanitizeJSON(getName()) << "\"";
if(getLabel().size())
sstream << ", \"label\":\"" << sanitizeJSON(getLabel()) << "\"";
if(getHelp().size())
sstream << ", \"help\":\"" << sanitizeJSON(getHelp()) << "\"";
sstream << ", \"changedValue\":" << getChangedValue()
<< ", \"visible\":" << (getVisible() ? "true" : "false")
<< ", \"readOnly\":" << (getReadOnly() ? "true" : "false");
if(_attributes.size()) {
sstream << ", \"attributes\":{ ";
for(std::map<std::string, std::string>::const_iterator it =
_attributes.begin();
it != _attributes.end(); it++) {
if(it != _attributes.begin()) sstream << ", ";
sstream << "\"" << sanitizeJSON(it->first) << "\":\""
<< sanitizeJSON(it->second) << "\"";
}
sstream << " }";
}
if(getClients().size()) {
sstream << ", \"clients\":{ ";
for(std::map<std::string, int>::const_iterator it =
getClients().begin();
it != getClients().end(); it++) {
if(it != getClients().begin()) sstream << ", ";
sstream << "\"" << sanitizeJSON(it->first) << "\":" << it->second;
}
sstream << " }";
}
return sstream.str();
}
#if defined(HAVE_PICOJSON)
virtual bool fromJSON(const picojson::value::object &par)
{
for(picojson::value::object::const_iterator it = par.begin();
it != par.end(); ++it) {
if(it->first == "name") {
if(!it->second.is<std::string>()) return false;
setName(it->second.get<std::string>());
}
else if(it->first == "label") {
if(!it->second.is<std::string>()) return false;
setLabel(it->second.get<std::string>());
}
else if(it->first == "help") {
if(!it->second.is<std::string>()) return false;
setHelp(it->second.get<std::string>());
}
else if(it->first == "changedValue") {
if(!it->second.is<double>()) return false;
setChangedValue((int)it->second.get<double>());
}
else if(it->first == "visible") {
if(!it->second.is<bool>()) return false;
setVisible(it->second.get<bool>());
}
else if(it->first == "readOnly") {
if(!it->second.is<bool>()) return false;
setReadOnly(it->second.get<bool>());
}
else if(it->first == "attributes") {
if(!it->second.is<picojson::object>()) return false;
const picojson::value::object &obj =
it->second.get<picojson::object>();
for(picojson::value::object::const_iterator i = obj.begin();
i != obj.end(); ++i) {
std::string key(i->first);
if(!i->second.is<std::string>()) return false;
setAttribute(key, i->second.get<std::string>());
}
}
else if(it->first == "clients") {
if(!it->second.is<picojson::object>()) return false;
const picojson::value::object &obj =
it->second.get<picojson::object>();
for(picojson::value::object::const_iterator i = obj.begin();
i != obj.end(); ++i) {
std::string client(i->first);
if(!i->second.is<double>()) return false;
addClient(client, (int)i->second.get<double>());
}
}
}
return true;
}
#endif
};
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.
class number : public parameter {
private:
std::vector<double> _values, _choices;
double _min, _max, _step;
// when in a loop, indicates current index in the vector _choices; is -1
// when not in a loop
int _index;
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), _values(std::vector<double>(1, value)),
_min(-maxNumber()), _max(maxNumber()), _step(0.), _index(-1)
{
}
number(const std::string &name, const std::vector<double> &values,
const std::string &label = "", const std::string &help = "")
: parameter(name, label, help), _values(values), _min(-maxNumber()),
_max(maxNumber()), _step(0.), _index(-1)
{
}
void setValue(double value)
{
_values.resize(1);
_values[0] = value;
}
void setValues(const std::vector<double> &values) { _values = values; }
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;
if(_valueLabels.size()) _valueLabels.clear();
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
{
if(_values.empty()) return 0.;
return _values[0];
}
const std::vector<double> &getValues() const { return _values; }
unsigned int getNumValues() const { return _values.size(); }
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());
bool changed = false;
for(unsigned int i = 0; i < p.getValues().size(); i++) {
if(p.getValues()[i] != getValues()[i]) {
changed = true;
break;
}
}
if(changed) {
setValues(p.getValues());
setChanged(getChangedValue());
}
setMin(p.getMin());
setMax(p.getMax());
setStep(p.getStep());
setIndex(p.getIndex());
setChoices(p.getChoices());
setValueLabels(p.getValueLabels());
if(getNeverChanged()) setChanged(0);
}
std::string toChar() const
{
std::ostringstream sstream;
sstream.precision(16);
sstream << parameter::toChar() << _values.size() << charSep();
for(unsigned int i = 0; i < _values.size(); i++)
sstream << _values[i] << charSep();
sstream << _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() << 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;
_values.resize(atoi(getNextToken(msg, pos).c_str()));
for(unsigned int i = 0; i < _values.size(); i++)
_values[i] = 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;
}
std::string toJSON() const
{
std::ostringstream sstream;
sstream.precision(16);
sstream << "{ " << parameter::toJSON() << ", \"values\":[ ";
for(unsigned int i = 0; i < _values.size(); i++) {
if(i) sstream << ", ";
sstream << _values[i];
}
sstream << " ]"
<< ", \"min\":" << _min << ", \"max\":" << _max
<< ", \"step\":" << _step << ", \"index\":" << _index;
if(_choices.size()) {
sstream << ", \"choices\":[ ";
for(unsigned int i = 0; i < _choices.size(); i++) {
if(i) sstream << ", ";
sstream << _choices[i];
}
sstream << " ]";
}
if(_valueLabels.size()) {
sstream << ", \"valueLabels\":{ ";
for(std::map<double, std::string>::const_iterator it =
_valueLabels.begin();
it != _valueLabels.end(); it++) {
if(it != _valueLabels.begin()) sstream << ", ";
sstream << "\"" << sanitizeJSON(it->second) << "\":" << it->first;
}
sstream << " }";
}
sstream << " }";
return sstream.str();
}
bool fromJSON(const std::string &json)
{
#if defined(HAVE_PICOJSON)
picojson::value v;
std::string err = picojson::parse(v, json);
if(err.size()) return false;
if(!v.is<picojson::object>()) return false;
const picojson::value::object &par = v.get<picojson::object>();
picojson::value::object::const_iterator it = par.find("type");
if(it == par.end()) return false;
if(it->second.to_str() == "number") {
fromJSON(par);
return true;
}
#endif
return false;
}
#if defined(HAVE_PICOJSON)
bool fromJSON(const picojson::value::object &par)
{
if(!parameter::fromJSON(par)) return false;
for(picojson::value::object::const_iterator it = par.begin();
it != par.end(); ++it) {
if(it->first == "values") {
if(!it->second.is<picojson::array>()) return false;
const picojson::value::array &arr = it->second.get<picojson::array>();
_values.resize(arr.size());
for(unsigned int i = 0; i < arr.size(); i++) {
if(!arr[i].is<double>()) return false;
_values[i] = arr[i].get<double>();
}
}
else if(it->first == "min") {
if(!it->second.is<double>()) return false;
setMin(it->second.get<double>());
}
else if(it->first == "max") {
if(!it->second.is<double>()) return false;
setMax(it->second.get<double>());
}
else if(it->first == "step") {
if(!it->second.is<double>()) return false;
setStep(it->second.get<double>());
}
else if(it->first == "index") {
if(!it->second.is<double>()) return false;
setIndex((int)it->second.get<double>());
}
else if(it->first == "choices") {
if(!it->second.is<picojson::array>()) return false;
const picojson::value::array &arr = it->second.get<picojson::array>();
_choices.resize(arr.size());
for(unsigned int i = 0; i < arr.size(); i++) {
if(!arr[i].is<double>()) return false;
_choices[i] = arr[i].get<double>();
}
}
else if(it->first == "valueLabels") {
if(!it->second.is<picojson::object>()) return false;
const picojson::value::object &obj =
it->second.get<picojson::object>();
for(picojson::value::object::const_iterator i = obj.begin();
i != obj.end(); ++i) {
if(!i->second.is<double>()) return false;
_valueLabels[i->second.get<double>()] = i->first;
}
}
}
return true;
}
#endif
};
// The string class. A string has a mutable "kind", that can be changed at
// runtime. Kinds leading to specific behavior in Gmsh are: "file".
class string : public parameter {
private:
std::vector<std::string> _values, _choices;
std::string _kind;
public:
string(const std::string &name = "", const std::string &value = "",
const std::string &label = "", const std::string &help = "")
: parameter(name, label, help),
_values(std::vector<std::string>(1, value)), _kind("generic")
{
}
string(const std::string &name, const std::vector<std::string> &values,
const std::string &label = "", const std::string &help = "")
: parameter(name, label, help), _values(values), _kind("generic")
{
}
void setValue(const std::string &value)
{
_values.resize(1);
_values[0] = value;
}
void setValues(const std::vector<std::string> &values) { _values = values; }
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
{
static std::string n("");
if(_values.empty()) return n;
return _values[0];
}
const std::vector<std::string> &getValues() const { return _values; }
unsigned int getNumValues() const { return _values.size(); }
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());
bool changed = false;
for(unsigned int i = 0; i < p.getValues().size(); i++) {
if(p.getValues()[i] != getValues()[i]) {
changed = true;
break;
}
}
if(changed) {
setValues(p.getValues());
setChanged(getChangedValue());
}
if(p.getKind() != getKind()) {
setKind(p.getKind());
setChanged(getChangedValue());
}
setChoices(p.getChoices());
if(getNeverChanged()) setChanged(0);
}
std::string toChar() const
{
std::ostringstream sstream;
sstream << parameter::toChar() << _values.size() << charSep();
for(unsigned int i = 0; i < _values.size(); i++)
sstream << sanitize(_values[i]) << charSep();
sstream << 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;
_values.resize(atoi(getNextToken(msg, pos).c_str()));
for(unsigned int i = 0; i < _values.size(); i++)
_values[i] = 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;
}
std::string toJSON() const
{
std::ostringstream sstream;
sstream << "{ " << parameter::toJSON() << ", \"values\":[ ";
for(unsigned int i = 0; i < _values.size(); i++) {
if(i) sstream << ", ";
sstream << "\"" << sanitizeJSON(_values[i]) << "\"";
}
sstream << " ] ";
if(_kind.size())
sstream << ", \"kind\":\"" << sanitizeJSON(_kind) << "\"";
if(_choices.size()) {
sstream << ", \"choices\":[ ";
for(unsigned int i = 0; i < _choices.size(); i++) {
if(i) sstream << ", ";
sstream << "\"" << sanitizeJSON(_choices[i]) << "\"";
}
sstream << " ]";
}
sstream << " }";
return sstream.str();
}
bool fromJSON(const std::string &json)
{
#if defined(HAVE_PICOJSON)
picojson::value v;
std::string err = picojson::parse(v, json);
if(err.size()) return false;
if(!v.is<picojson::object>()) return false;
const picojson::value::object &par = v.get<picojson::object>();
picojson::value::object::const_iterator it = par.find("type");
if(it == par.end()) return false;
if(it->second.to_str() == "string") {
fromJSON(par);
return true;
}
#endif
return false;
}
#if defined(HAVE_PICOJSON)
bool fromJSON(const picojson::value::object &par)
{
if(!parameter::fromJSON(par)) return false;
for(picojson::value::object::const_iterator it = par.begin();
it != par.end(); ++it) {
if(it->first == "values") {
if(!it->second.is<picojson::array>()) return false;
const picojson::value::array &arr = it->second.get<picojson::array>();
_values.resize(arr.size());
for(unsigned int i = 0; i < arr.size(); i++) {
if(!arr[i].is<std::string>()) return false;
_values[i] = arr[i].get<std::string>();
}
}
else if(it->first == "kind") {
if(!it->second.is<std::string>()) return false;
setKind(it->second.get<std::string>());
}
else if(it->first == "choices") {
if(!it->second.is<picojson::array>()) return false;
const picojson::value::array &arr = it->second.get<picojson::array>();
_choices.resize(arr.size());
for(unsigned int i = 0; i < arr.size(); i++) {
if(!arr[i].is<std::string>()) return false;
_choices[i] = arr[i].get<std::string>();
}
}
}
return true;
}
#endif
};
// 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;
#if __cplusplus >= 201103L
std::mutex _mutex;
#endif
// 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)
{
#if __cplusplus >= 201103L
_mutex.lock();
#endif
typename std::set<T *, parameterLessThan>::iterator it = ps.find((T *)&p);
if(it != ps.end()) {
(*it)->update(p);
if(client.size())
(*it)->addClient(client, parameter::defaultChangedValue());
}
else {
T *newp = new T(p);
if(client.size())
newp->addClient(client, parameter::defaultChangedValue());
ps.insert(newp);
}
#if __cplusplus >= 201103L
_mutex.unlock();
#endif
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()){
#if __cplusplus >= 201103L
_mutex.lock();
#endif
(*it)->addClient(client, parameter::defaultChangedValue());
#if __cplusplus >= 201103L
_mutex.unlock();
#endif
}
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()){
#if __cplusplus >= 201103L
_mutex.lock();
#endif
(*it)->addClient(client, parameter::defaultChangedValue());
#if __cplusplus >= 201103L
_mutex.unlock();
#endif
}
return *it;
}
return NULL;
}
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<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)
int getChanged(const std::string &client = "") const
{
std::set<parameter *, parameterLessThan> ps;
getAllParameters(ps);
int changed = 0;
for(std::set<parameter *, parameterLessThan>::iterator it = ps.begin();
it != ps.end(); it++) {
changed = std::max(changed, (*it)->getChanged(client));
}
return changed;
}
// 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(int 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);
}
void thresholdChanged(int threshold, const std::string &client = "")
{
std::set<parameter *, parameterLessThan> ps;
getAllParameters(ps);
for(std::set<parameter *, parameterLessThan>::iterator it = ps.begin();
it != ps.end(); it++) {
int changed = (*it)->getChanged(client);
if(changed > threshold) (*it)->setChanged(threshold, 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") {
number p;
p.fromChar(msg[i]);
set(p, client);
}
else if(type == "string") {
string p;
p.fromChar(msg[i]);
set(p, client);
}
else
return false;
}
return true;
}
bool toJSON(std::string &json, const std::string &creator = "",
const std::string &client = "") const
{
time_t now;
time(&now);
std::string t(ctime(&now));
t.resize(t.size() - 1);
json.clear();
json += "{ \"onelab\":{\n";
json += " \"creator\":\"" + creator + "\",\n";
json += " \"date\":\"" + t + "\",\n";
json += " \"version\":\"" + parameter::version() + "\",\n";
json += " \"parameters\":[\n";
std::set<parameter *, parameterLessThan> ps;
getAllParameters(ps);
for(std::set<parameter *, parameterLessThan>::const_iterator it =
ps.begin();
it != ps.end(); it++) {
if(it != ps.begin()) json += ",\n";
if(client.empty() || (*it)->hasClient(client)) {
if((*it)->getAttribute("NotInDb") != "True") {
json += " " + (*it)->toJSON();
}
}
}
json += "\n ] }\n}\n";
return true;
}
bool fromJSON(const std::string &json, const std::string &client = "")
{
#if defined(HAVE_PICOJSON)
picojson::value v;
std::string err = picojson::parse(v, json);
if(err.size()) return false;
if(v.is<picojson::object>()){ // onelab database or single parameter
const picojson::value::object &obj = v.get<picojson::object>();
picojson::value::object::const_iterator it = obj.find("onelab");
if(it != obj.end()){ // onelab database
if(!it->second.is<picojson::object>()) return false;
const picojson::value::object &db = it->second.get<picojson::object>();
for(picojson::value::object::const_iterator j = db.begin(); j != db.end(); ++j) {
if(j->first == "version") {
if(!j->second.is<std::string>()) return false;
if(j->second.get<std::string>() != parameter::version())
return false;
}
else if(j->first == "parameters") {
if(!j->second.is<picojson::array>()) return false;
const picojson::value::array &arr = j->second.get<picojson::array>();
for(unsigned int k = 0; k < arr.size(); k++) {
if(!arr[k].is<picojson::object>()) return false;
const picojson::value::object &par = arr[k].get<picojson::object>();
if(!fromJSON(par, client)) return false;
}
}
}
return true;
}
else{ // single parameter
return fromJSON(obj, client);
}
}
else if(v.is<picojson::array>()){ // array of parameters
const picojson::value::array &arr = v.get<picojson::array>();
for(unsigned int k = 0; k < arr.size(); k++) {
if(!arr[k].is<picojson::object>()) return false;
const picojson::value::object &par = arr[k].get<picojson::object>();
if(!fromJSON(par, client)) return false;
}
return true;
}
else{
return false;
}
#else
return false;
#endif
}
#if defined(HAVE_PICOJSON)
bool fromJSON(const picojson::value::object &par, const std::string &client = "")
{
picojson::value::object::const_iterator it = par.find("type");
if(it == par.end()) return false;
if(it->second.to_str() == "number") {
number p;
p.fromJSON(par);
set(p, client);
return true;
}
else if(it->second.to_str() == "string") {
string p;
p.fromJSON(par);
set(p, client);
return true;
}
return false;
}
#endif
};
// 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<string> &ps, const std::string &name = "") = 0;
virtual bool setAndAppendChoices(const number &p) = 0;
virtual bool setAndAppendChoices(const string &p) = 0;
virtual bool getWithoutChoices(std::vector<number> &ps,
const std::string &name = "") = 0;
virtual bool getWithoutChoices(std::vector<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") {
number p;
p.fromChar(msg[i]);
set(p);
}
else if(type == "string") {
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(int changed, const std::string &client = "")
{
_parameterSpace.setChanged(changed, client);
}
int getChanged(const std::string &client = "")
{
return _parameterSpace.getChanged(client);
}
void thresholdChanged(int value, const std::string &client = "")
{
_parameterSpace.thresholdChanged(value, 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;
}
bool toJSON(std::string &json, const std::string &client = "")
{
return _parameterSpace.toJSON(json, client);
}
bool fromJSON(const std::string &json, const std::string &client = "")
{
return _parameterSpace.fromJSON(json, client);
}
};
// 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<string> &ps, const std::string &name = "")
{
return _get(ps, name);
}
virtual bool setAndAppendChoices(const number &p)
{
std::vector<number> ps;
_get(ps, _name);
std::vector<double> choices;
if(ps.size()) choices = ps[0].getChoices();
choices.insert(choices.end(), p.getChoices().begin(),
p.getChoices().end());
number p2(p);
p2.setChoices(choices);
return _set(p2);
}
virtual bool setAndAppendChoices(const string &p)
{
std::vector<string> ps;
_get(ps, _name);
std::vector<std::string> choices;
if(ps.size()) choices = ps[0].getChoices();
choices.insert(choices.end(), p.getChoices().begin(),
p.getChoices().end());
string p2(p);
p2.setChoices(choices);
return _set(p2);
}
virtual bool getWithoutChoices(std::vector<number> &ps,
const std::string &name = "")
{
bool ret = _get(ps, name);
for(unsigned int i = 0; i < ps.size(); i++)
ps[i].setChoices(std::vector<double>());
return ret;
}
virtual bool getWithoutChoices(std::vector<string> &ps,
const std::string &name = "")
{
bool ret = _get(ps, name);
for(unsigned int i = 0; i < ps.size(); i++)
ps[i].setChoices(std::vector<std::string>());
return ret;
}
};
// 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, bool withChoices = true)
{
if(!_gmshClient) return false;
std::string msg = p.toChar();
_gmshClient->SendMessage(withChoices ?
GmshSocket::GMSH_PARAMETER :
GmshSocket::GMSH_PARAMETER_WITHOUT_CHOICES,
msg.size(), &msg[0]);
return true;
}
template <class T>
bool _get(std::vector<T> &ps, const std::string &name = "",
bool withChoices = true)
{
ps.clear();
if(!_gmshClient) return false;
T p(name);
std::string msg = p.toChar();
if(name.size())
_gmshClient->SendMessage(
withChoices ? GmshSocket::GMSH_PARAMETER_QUERY :
GmshSocket::GMSH_PARAMETER_QUERY_WITHOUT_CHOICES,
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("Timeout: 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("Timeout: 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<string> &ps, const std::string &name = "")
{
return _get(ps, name);
}
virtual bool setAndAppendChoices(const number &p) { return _set(p, false); }
virtual bool setAndAppendChoices(const string &p) { return _set(p, false); }
virtual bool getWithoutChoices(std::vector<number> &ps,
const std::string &name = "")
{
return _get(ps, name, false);
}
virtual bool getWithoutChoices(std::vector<string> &ps,
const std::string &name = "")
{
return _get(ps, name, false);
}
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 !defined(BUILD_IOS)
if(!_gmshClient) {
int res = system(command.c_str());
if(res) {
// report error
}
return;
}
#endif
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();
}
};
} // namespace onelab
#endif