From 6c18ce78d6b238d210cae1a1aa16afba76deed61 Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@ulg.ac.be> Date: Thu, 4 Oct 2012 16:07:05 +0000 Subject: [PATCH] merge onelab project into contrib/ --- CMakeLists.txt | 7 + Common/GmshConfig.h.in | 1 + Common/GmshMessage.cpp | 20 +- Common/GmshMessage.h | 1 + Common/OpenFile.cpp | 7 + Fltk/onelabWindow.cpp | 117 ++- Fltk/onelabWindow.h | 2 + contrib/onelab/CMakeLists.txt | 14 + contrib/onelab/OnelabClients.cpp | 1071 ++++++++++++++++++++++++ contrib/onelab/OnelabClients.h | 316 +++++++ contrib/onelab/OnelabMessage.cpp | 664 +++++++++++++++ contrib/onelab/OnelabMessage.h | 132 +++ contrib/onelab/OnelabParser.cpp | 1344 ++++++++++++++++++++++++++++++ contrib/onelab/loader.cpp | 264 ++++++ contrib/onelab/metamodel.cpp | 56 ++ contrib/onelab/metamodel.h | 6 + 16 files changed, 3991 insertions(+), 31 deletions(-) create mode 100644 contrib/onelab/CMakeLists.txt create mode 100644 contrib/onelab/OnelabClients.cpp create mode 100644 contrib/onelab/OnelabClients.h create mode 100644 contrib/onelab/OnelabMessage.cpp create mode 100644 contrib/onelab/OnelabMessage.h create mode 100644 contrib/onelab/OnelabParser.cpp create mode 100644 contrib/onelab/loader.cpp create mode 100644 contrib/onelab/metamodel.cpp create mode 100644 contrib/onelab/metamodel.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 859bbc7f0d..afe0f732ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ option(ENABLE_NATIVE_FILE_CHOOSER "Enable native file chooser in GUI" ${DEFAULT} option(ENABLE_NETGEN "Enable Netgen mesh generator" ${DEFAULT}) option(ENABLE_OCC "Enable Open CASCADE geometrical models" ${DEFAULT}) option(ENABLE_ONELAB "Enable OneLab solver interface" ${DEFAULT}) +option(ENABLE_ONELAB_METAMODEL "Enable OneLab metamodel" ${DEFAULT}) option(ENABLE_OSMESA "Use OSMesa for offscreen rendering" OFF) option(ENABLE_PARSER "Build the GEO file parser" ${DEFAULT}) option(ENABLE_PETSC "Enable PETSc linear algebra solvers" ${DEFAULT}) @@ -902,6 +903,12 @@ if(ENABLE_ONELAB) set_config_option(HAVE_ONELAB "OneLab") endif(ENABLE_ONELAB) +if(ENABLE_ONELAB_METAMODEL) + add_subdirectory(contrib/onelab) + include_directories(contrib/onelab) + set_config_option(HAVE_ONELAB_METAMODEL "OneLabMetamodel") +endif(ENABLE_ONELAB_METAMODEL) + check_function_exists(vsnprintf HAVE_VSNPRINTF) if(NOT HAVE_VSNPRINTF) set_config_option(HAVE_NO_VSNPRINTF "NoVsnprintf") diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in index 0248ac92b9..c83a17dc8d 100644 --- a/Common/GmshConfig.h.in +++ b/Common/GmshConfig.h.in @@ -43,6 +43,7 @@ #cmakedefine HAVE_NO_VSNPRINTF #cmakedefine HAVE_OCC #cmakedefine HAVE_ONELAB +#cmakedefine HAVE_ONELAB_METAMODEL #cmakedefine HAVE_OPENGL #cmakedefine HAVE_OSMESA #cmakedefine HAVE_PARSER diff --git a/Common/GmshMessage.cpp b/Common/GmshMessage.cpp index 523c34b93e..2824dc42cb 100644 --- a/Common/GmshMessage.cpp +++ b/Common/GmshMessage.cpp @@ -16,6 +16,7 @@ #include "GModel.h" #include "Options.h" #include "Context.h" +#include "OpenFile.h" #include "OS.h" #if defined(HAVE_ONELAB) @@ -660,12 +661,25 @@ void Msg::SetOnelabString(std::string name, std::string val, bool visible) } } +class localGmsh : public onelab::localClient { +public: + localGmsh() : onelab::localClient("Gmsh") {} + void sendMergeFileRequest(const std::string &msg) + { + MergePostProcessingFile(msg, CTX::instance()->solver.autoShowLastStep, + CTX::instance()->solver.autoHideNewViews, true); + } + void sendInfo(const std::string &msg){ Msg::Info("%s", msg.c_str()); } + void sendWarning(const std::string &msg){ Msg::Warning("%s", msg.c_str()); } + void sendError(const std::string &msg){ Msg::Error("%s", msg.c_str()); } +}; + void Msg::InitializeOnelab(const std::string &name, const std::string &sockname) { #if defined(HAVE_ONELAB) if(_onelabClient) delete _onelabClient; if(sockname.empty()){ - _onelabClient = new onelab::localClient("Gmsh"); + _onelabClient = new localGmsh(); if(name != "Gmsh"){ // load db from file: if(!_onelabClient->fromFile(name)) Error("Error loading onelab database '%s'", name.c_str()); @@ -796,9 +810,6 @@ void Msg::ImportPhysicalsAsOnelabRegions() if(_onelabClient){ std::map<int, std::vector<GEntity*> > groups[4]; GModel::current()->getPhysicalGroups(groups); - // FIXME - // for(int dim = 0; dim < 3; dim++) is clearly a mistake - // should the loop start at dim=0 or dim=1? for(int dim = 0; dim <= 3; dim++){ for(std::map<int, std::vector<GEntity*> >::iterator it = groups[dim].begin(); it != groups[dim].end(); it++){ @@ -814,6 +825,7 @@ void Msg::ImportPhysicalsAsOnelabRegions() onelab::region p(name, num.str()); p.setDimension(dim); p.setReadOnly(true); + p.setAttribute("Closed", "1"); _onelabClient->set(p); } } diff --git a/Common/GmshMessage.h b/Common/GmshMessage.h index a1ee370189..4a65a163e1 100644 --- a/Common/GmshMessage.h +++ b/Common/GmshMessage.h @@ -84,6 +84,7 @@ class Msg { const char *one, const char *two=0); static void InitializeOnelab(const std::string &name, const std::string &sockname=""); static GmshClient *GetGmshClient(){ return _client; } + static onelab::client *GetOnelabClient(){ return _onelabClient; } static void FinalizeOnelab(); static bool UseOnelab(); static void SetOnelabNumber(std::string name, double val, bool visible); diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp index 23b2be1348..da305a1482 100644 --- a/Common/OpenFile.cpp +++ b/Common/OpenFile.cpp @@ -37,6 +37,7 @@ #if defined(HAVE_FLTK) #include <FL/fl_ask.H> #include "FlGui.h" +#include "onelabWindow.h" #include "menuWindow.h" #include "drawContext.h" #endif @@ -372,6 +373,12 @@ int MergeFile(const std::string &fileName, bool warnIfMissing) else if(ext == ".csv"){ status = readFile3M(fileName); } +#endif +#if defined(HAVE_ONELAB_METAMODEL) + else if(ext == ".ol"){ + // TODO: allow passing action to metamodel from command line + status = metamodel_cb(fileName); + } #endif else { CTX::instance()->geom.draw = 1; diff --git a/Fltk/onelabWindow.cpp b/Fltk/onelabWindow.cpp index 2518585f94..05fb3abf04 100644 --- a/Fltk/onelabWindow.cpp +++ b/Fltk/onelabWindow.cpp @@ -11,6 +11,10 @@ #include "onelab.h" #endif +#if defined(HAVE_ONELAB_METAMODEL) +#include "metamodel.h" +#endif + #if defined(HAVE_ONELAB) && (FL_MAJOR_VERSION == 1) && (FL_MINOR_VERSION == 3) #include <FL/Fl_Check_Button.H> @@ -402,6 +406,24 @@ static void saveDb(const std::string &fileName, bool withTimeStamp=false) // rename(old, new); on disk (in stdio.h) // need to detect if a file is already stamped. We could simply check the // sequence of _ - - - _ - - - . characters for this. + std::vector<onelab::string> strings; + onelab::server::instance()->get(strings); + for(unsigned int i = 0; i < strings.size(); i++){ + if(strings[i].getName().find("Output files") != std::string::npos){ + for(unsigned int j = 0; j < strings[i].getChoices().size(); j++){ + std::vector<std::string> split = SplitFileName(strings[i].getChoices()[j]); + int n = split[1].size(); + if(n > 18 && + split[1][n-3] == '-' && split[1][n-6] == '-' && split[1][n-9] == '_' && + split[1][n-12] == '-' && split[1][n-15] == '-' && split[1][n-18] == '_'){ + printf("already stamped! %s\n", strings[i].getChoices()[j].c_str()); + } + else{ + printf("renaming %s\n", strings[i].getChoices()[j].c_str()); + } + } + } + } } Msg::StatusBar(2, true, "Saving database '%s'...", name.c_str()); @@ -501,14 +523,15 @@ void onelab_cb(Fl_Widget *w, void *data) if(action == "compute") initializeLoops(); + // check whether we are running a metamodel + std::vector<onelab::number> n; + onelab::server::instance()->get(n, "IsMetamodel"); + bool isMetamodel = (n.size() && n[0].getValue()); + do{ // enter loop - // check whether the client is a onelab Metamodel - std::vector<onelab::number> n; - onelab::server::instance()->get(n, "HasGmsh"); - bool metamodel = (n.size() && n[0].getValue()); // if the client is a not a metamodel, run Gmsh - if(!metamodel){ + if(!isMetamodel){ if(onelabUtils::runGmshClient(action, CTX::instance()->solver.autoMesh)) drawContext::global()->draw(); } @@ -517,31 +540,32 @@ void onelab_cb(Fl_Widget *w, void *data) FlGui::instance()->onelab->checkForErrors("Gmsh"); if(FlGui::instance()->onelab->stop()) break; - // iterate over all other clients (there should narmally only be one) - for(onelab::server::citer it = onelab::server::instance()->firstClient(); - it != onelab::server::instance()->lastClient(); it++){ - onelab::client *c = it->second; - if(c->getName() == "Gmsh" || // local Gmsh client - c->getName() == "Listen" || // unknown client connecting through "-listen" - c->getName() == "GmshRemote") // distant post-processing Gmsh client - continue; - if(action != "initialize") onelabUtils::guessModelName(c); - onelab::string o(c->getName() + "/Action", action); - o.setVisible(false); - onelab::server::instance()->set(o); - c->run(); - if(action == "compute"){ - FlGui::instance()->onelab->checkForErrors(c->getName()); - if(metamodel) - onelab::server::instance()->setChanged(false,c->getName()); + if(isMetamodel){ +#if defined(HAVE_ONELAB_METAMODEL) + metamodel(action); +#endif + } + else{ + // iterate over all other clients (there should narmally only be one) + for(onelab::server::citer it = onelab::server::instance()->firstClient(); + it != onelab::server::instance()->lastClient(); it++){ + onelab::client *c = it->second; + if(c->getName() == "Gmsh" || // local Gmsh client + c->getName() == "Listen" || // unknown client connecting through "-listen" + c->getName() == "GmshRemote") // distant post-processing Gmsh client + continue; + if(action != "initialize") onelabUtils::guessModelName(c); + onelab::string o(c->getName() + "/Action", action); + o.setVisible(false); + onelab::server::instance()->set(o); + c->run(); + if(action == "compute"){ + FlGui::instance()->onelab->checkForErrors(c->getName()); + } + if(FlGui::instance()->onelab->stop()) break; } - if(FlGui::instance()->onelab->stop()) break; - } - // update geometry which might have been changed by the metamodel - if(metamodel) geometry_reload_cb(0, 0); - if(action != "initialize"){ updateGraphs(); FlGui::instance()->onelab->rebuildTree(); @@ -1298,6 +1322,39 @@ void solver_cb(Fl_Widget *w, void *data) onelab_cb(0, (void*)"check"); } +int metamodel_cb(const std::string &name, const std::string &action) +{ +#if defined(HAVE_ONELAB_METAMODEL) + Msg::ResetErrorCounter(); + if(FlGui::instance()->onelab->isBusy()) + FlGui::instance()->onelab->show(); + else{ + initializeMetamodel(Msg::GetOnelabClient()); + + onelab::number n("IsMetamodel", 1.); + n.setVisible(false); + onelab::server::instance()->set(n); + std::vector<std::string> split = SplitFileName(name); + onelab::string s1("Arguments/WorkingDir", split[0]); + s1.setVisible(false); + onelab::server::instance()->set(s1); + onelab::string s2("Arguments/FileName", split[1]); + s2.setVisible(false); + onelab::server::instance()->set(s2); + + FlGui::instance()->onelab->rebuildSolverList(); + + if(FlGui::instance()->available()) + onelab_cb(0, (void*)"check"); + else + metamodel(action); + } + return 1; +#else + return 0; +#endif +} + #else #if defined(HAVE_ONELAB) @@ -1321,4 +1378,10 @@ void solver_cb(Fl_Widget *w, void *data) Msg::Error("The solver interface requires OneLab and FLTK 1.3"); } +int metamodel_cb(const std::string &name, const std::string &action) +{ + Msg::Error("Metamodels require OneLab and FLTK 1.3"); + return 0; +} + #endif diff --git a/Fltk/onelabWindow.h b/Fltk/onelabWindow.h index 38024e39f4..58fcb7f04c 100644 --- a/Fltk/onelabWindow.h +++ b/Fltk/onelabWindow.h @@ -14,6 +14,7 @@ #include <FL/Fl_Window.H> #include <FL/Fl_Tree.H> #include <FL/Fl_Button.H> +#include <FL/Fl_Menu_Button.H> #include <FL/Fl_Input.H> #include "onelab.h" @@ -70,5 +71,6 @@ void onelab_cb(Fl_Widget *w, void *data); #endif void solver_cb(Fl_Widget *w, void *data); +int metamodel_cb(const std::string &name, const std::string &action=""); #endif diff --git a/contrib/onelab/CMakeLists.txt b/contrib/onelab/CMakeLists.txt new file mode 100644 index 0000000000..a1953f75f3 --- /dev/null +++ b/contrib/onelab/CMakeLists.txt @@ -0,0 +1,14 @@ +# Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle +# +# See the LICENSE.txt file for license information. Please report all +# bugs and problems to <gmsh@geuz.org>. + +set(SRC + OnelabClients.cpp + OnelabMessage.cpp + OnelabParser.cpp + metamodel.cpp +) + +file(GLOB_RECURSE HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.hxx) +append_gmsh_src(contrib/onelab "${SRC};${HDR}") diff --git a/contrib/onelab/OnelabClients.cpp b/contrib/onelab/OnelabClients.cpp new file mode 100644 index 0000000000..3bc2772117 --- /dev/null +++ b/contrib/onelab/OnelabClients.cpp @@ -0,0 +1,1071 @@ +#include "OnelabMessage.h" +#include "OnelabClients.h" +#include "StringUtils.h" +#include <algorithm> + + +class onelabMetaModelServer : public GmshServer{ + private: + localNetworkSolverClient *_client; + public: + onelabMetaModelServer(localNetworkSolverClient *client) + : GmshServer(), _client(client) {} + ~onelabMetaModelServer(){} + int NonBlockingSystemCall(const char *command) + { +#if defined(WIN32) + STARTUPINFO suInfo; + PROCESS_INFORMATION prInfo; + memset(&suInfo, 0, sizeof(suInfo)); + suInfo.cb = sizeof(suInfo); + std::string cmd(command); + OLMsg::Info("Calling <%s>", cmd.c_str()); + // DETACHED_PROCESS removes the console (useful if the program to launch is + // a console-mode exe) + CreateProcess(NULL,(char *)cmd.c_str(), NULL, NULL, FALSE, + NORMAL_PRIORITY_CLASS|DETACHED_PROCESS, NULL, NULL, + &suInfo, &prInfo); + return 0; +#else + if(!system(NULL)) { + OLMsg::Error("Could not find /bin/sh: aborting system call"); + return 1; + } + std::string cmd(command); + int pos; + if((pos=cmd.find("incomp_ssh ")) != std::string::npos){ + cmd.assign(cmd.substr(pos+7)); // remove "incomp_" + cmd.append(" & '"); + } + else + cmd.append(" & "); + + OLMsg::Info("Calling <%s>", cmd.c_str()); + return system(cmd.c_str()); +#endif + }// non blocking + int NonBlockingWait(int socket, double waitint, double timeout) + { + double start = GetTimeInSeconds(); + while(1){ + if(timeout > 0 && GetTimeInSeconds() - start > timeout) + return 2; // timout + // if(_client->getPid() < 0 || (_client->getCommandLine().empty() && + // !CTX::instance()->solver.listen)) + if(_client->getPid() < 0 || (_client->getCommandLine().empty())) + return 1; // process has been killed or we stopped listening + // check if there is data (call select with a zero timeout to + // return immediately, i.e., do polling) + int ret = Select(0, 0, socket); + if(ret == 0){ // nothing available + // if asked, refresh the onelab GUI + std::vector<onelab::string> ps; + onelab::server::instance()->get(ps, "Gmsh/Action"); + if(ps.size() && ps[0].getValue() == "refresh"){ + ps[0].setVisible(false); + ps[0].setValue(""); + onelab::server::instance()->set(ps[0]); + //onelab_cb(0, (void*)"refresh"); + } + // wait at most waitint seconds and respond to FLTK events + //FlGui::instance()->wait(waitint); + } + else if(ret > 0){ + return 0; // data is there! + } + else{ + // an error happened + _client->setPid(-1); + _client->setGmshServer(0); + return 1; + } + } + } +}; + +std::string localNetworkSolverClient::buildCommandLine(){ + std::string command; + command.assign(""); + if(!getWorkingDir().empty()) + command.append("cd " + getWorkingDir() + cmdSep); + command.append(FixWindowsPath(getCommandLine())); + return command; +} + +std::string localNetworkSolverClient::appendArguments(){ + + std::string action = getString("Action"); + std::string checkCommand = getString("9CheckCommand"); + std::string computeCommand = getString("9ComputeCommand"); + + std::string command; + if(action == "initialize"){ + command.assign(" " + getSocketSwitch() + " " + getName() + " %s"); + } + else if(action == "check") { + command.assign(" " + getString("Arguments") + " " + checkCommand) ; + command.append(" " + getSocketSwitch() + " " + getName() + " %s"); + } + else if(action == "compute"){ + command.assign(" " + getString("Arguments") + " " + computeCommand); + command.append(" " + getSocketSwitch() + " " + getName() + " %s"); + } + else + OLMsg::Fatal("buildCommandLine: Unknown Action <%s>", action.c_str()); + return command; +} + +bool localNetworkSolverClient::run() +{ + new_connection: + _pid = 0; + _gmshServer = 0; + + onelabMetaModelServer *server = new onelabMetaModelServer(this); + +#if defined(WIN32) + std::string socketName = ":"; +#else + std::string socketName; + if(getRemote()) + socketName = ":"; + else + socketName = getUserHomedir() + ".gmshsock"; +#endif + + std::string sockname; + std::ostringstream tmp; + if(!strstr(socketName.c_str(), ":")){ + // Unix socket + tmp << socketName << getId(); + sockname = FixWindowsPath(tmp.str()); + } + else{ + // TCP/IP socket + if(socketName.size() && socketName[0] == ':') + // prepend hostname if only the port number is given + tmp << GetHostName(); + tmp << socketName ; + sockname = tmp.str(); + } + + std::string command = buildCommandLine(); + if(command.size()) command.append(appendArguments()); + + // std::cout << "sockname=<" << sockname << ">" << std::endl; + // std::cout << "command=<" << command << ">" << std::endl; + + int sock; + try{ + sock = server->Start(command.c_str(), sockname.c_str(), 10); + } + catch(const char *err){ + OLMsg::Error("%s (on socket '%s')", err, sockname.c_str()); + sock = -1; + } + + if(sock < 0){ + server->Shutdown(); + delete server; + return false; + } + + OLMsg::StatusBar(2, true, "Now running client <%s>", _name.c_str()); + + while(1) { + if(_pid < 0) break; + + int stop = server->NonBlockingWait(sock, 0.1, 0.); + if(stop || _pid < 0) { + OLMsg::Info("Stop=%d _pid=%d",stop, _pid); + break; + } + int type, length, swap; + if(!server->ReceiveHeader(&type, &length, &swap)){ + OLMsg::Error("Did not receive message header: stopping server"); + break; + } + // else + // std::cout << "FHF: Received header=" << type << std::endl; + + std::string message(length, ' '); + if(!server->ReceiveMessage(length, &message[0])){ + OLMsg::Error("Did not receive message body: stopping server"); + break; + } + // else + // std::cout << "FHF: Received message=" << message << std::endl; + + switch (type) { + case GmshSocket::GMSH_START: + _pid = atoi(message.c_str()); + _gmshServer = server; + break; + case GmshSocket::GMSH_STOP: + _pid = -1; + _gmshServer = 0; + break; + case GmshSocket::GMSH_PARAMETER: + { + std::string version, type, name; + onelab::parameter::getInfoFromChar(message, version, type, name); + if(onelab::parameter::version() != version){ + OLMsg::Error("OneLab version mismatch for %s (server: %s / client: %s)", + message.c_str(), onelab::parameter::version().c_str(), version.c_str()); + } + if(type == "number"){ + onelab::number p; p.fromChar(message); set(p); + } + else if(type == "string"){ + onelab::string p; p.fromChar(message); set(p); + } + else if(type == "region"){ + onelab::region p; p.fromChar(message); set(p); + } + else if(type == "function"){ + onelab::function p; p.fromChar(message); set(p); + } + else + OLMsg::Fatal("FIXME query not done for this parameter type: <%s>", + message.c_str()); + } + break; + case GmshSocket::GMSH_PARAMETER_QUERY: + { + std::string version, type, name, reply; + onelab::parameter::getInfoFromChar(message, version, type, name); + if(onelab::parameter::version() != version){ + OLMsg::Error("OneLab version mismatch for %s (server: %s / client: %s)", + message.c_str(), onelab::parameter::version().c_str(), version.c_str()); + } + else if(type == "number"){ + std::vector<onelab::number> par; get(par, name); + if(par.size() == 1) reply = par[0].toChar(); + } + else if(type == "string"){ + std::vector<onelab::string> par; get(par, name); + if(par.size() == 1) reply = par[0].toChar(); + } + else if(type == "region"){ + std::vector<onelab::region> par; get(par, name); + if(par.size() == 1) par[0].toChar(); + } + else if(type == "function"){ + std::vector<onelab::function> par; get(par, name); + if(par.size() == 1) reply = par[0].toChar(); + } + else + OLMsg::Error("Unknown OneLab parameter type in query: %s", + type.c_str()); + + if(reply.size()){ + server->SendMessage(GmshSocket::GMSH_PARAMETER, + reply.size(), &reply[0]); + } + else{ + reply = "OneLab parameter '" + name + "' not found"; + server->SendMessage(GmshSocket::GMSH_INFO, reply.size(), &reply[0]); + } + } + break; + case GmshSocket::GMSH_PARAM_QUERY_ALL: + { + std::string version, type, name, reply; + std::vector<std::string> replies; + onelab::parameter::getInfoFromChar(message, version, type, name); + if(onelab::parameter::version() != version){ + OLMsg::Error("OneLab version mismatch for %s (server: %s / client: %s)", + message.c_str(), onelab::parameter::version().c_str(), version.c_str()); + } + else if(type == "number"){ + std::vector<onelab::number> numbers; get(numbers); + for(std::vector<onelab::number>::iterator it = numbers.begin(); + it != numbers.end(); it++) replies.push_back((*it).toChar()); + } + else if(type == "string"){ + std::vector<onelab::string> strings; get(strings); + for(std::vector<onelab::string>::iterator it = strings.begin(); + it != strings.end(); it++) replies.push_back((*it).toChar()); + } + else if(type == "region"){ + std::vector<onelab::region> regions; get(regions); + for(std::vector<onelab::region>::iterator it = regions.begin(); + it != regions.end(); it++) replies.push_back((*it).toChar()); + } + else if(type == "function"){ + std::vector<onelab::function> functions; get(functions); + for(std::vector<onelab::function>::iterator it = functions.begin(); + it != functions.end(); it++) replies.push_back((*it).toChar()); + } + else + OLMsg::Error("Unknown OneLab parameter type in query: %s", + type.c_str()); + + for(unsigned int i = 0; i < replies.size(); i++) + server->SendMessage(GmshSocket::GMSH_PARAM_QUERY_ALL, + replies[i].size(), &replies[i][0]); + reply = "Sent all OneLab " + type + "s"; + server->SendMessage(GmshSocket::GMSH_PARAM_QUERY_END, + reply.size(), &reply[0]); + } + break; + case GmshSocket::GMSH_PROGRESS: + OLMsg::StatusBar(2, false, "%s %s", _name.c_str(), message.c_str()); + break; + case GmshSocket::GMSH_INFO: + OLMsg::Direct("%-8.8s: %s", _name.c_str(), message.c_str()); + break; + case GmshSocket::GMSH_WARNING: + OLMsg::Direct(2, "%-8.8s: %s", _name.c_str(), message.c_str()); + break; + case GmshSocket::GMSH_ERROR: + //OLMsg::Direct(1, "%-8.8s: %s", _name.c_str(), message.c_str()); + OLMsg::Fatal("%-8.8s: %s", _name.c_str(), message.c_str()); + break; + case GmshSocket::GMSH_MERGE_FILE: + OLMsg::Info("Merge Post-Processing File %s",message.c_str()); + SystemCall("gmsh "+ message); + //implémentation pour le cas du loader en mode console. + break; + default: + OLMsg::Warning("Received unknown message type (%d)", type); + break; + } + } + + server->Shutdown(); + delete server; + OLMsg::StatusBar(2, true, "Done running '%s'", _name.c_str()); + return true; +} + +bool localNetworkSolverClient::kill() +{ + if(_pid > 0) { + if(KillProcess(_pid)){ + OLMsg::Info("Killed '%s' (pid %d)", _name.c_str(), _pid); + _pid = -1; + return true; + } + } + _pid = -1; + return false; +} + + +// client LOCALSOLVERCLIENT + +std::string localSolverClient::toChar(){ + std::ostringstream sstream; + if(getCommandLine().size()){ + sstream << getName() << "." << "commandLine(" + << getCommandLine() << ");\n"; + } + return sstream.str(); +} + +void localSolverClient::setAction(const std::string action){ + std::string name=getName() + "/Action"; + onelab::string s(name, action); + s.setVisible(false); + set(s); +} + +const std::string localSolverClient::getString(const std::string what){ + std::vector<onelab::string> strings; + get(strings, getName() + "/" + what); + if(strings.size()) + return strings[0].getValue(); + else + return ""; +} + +const bool localSolverClient::getList(const std::string type, std::vector<std::string> &choices){ + std::vector<onelab::string> strings; + get(strings, getName() + "/" + type); + if(strings.size()){ + choices= strings[0].getChoices(); + return true; + } + else + return false; +} + +bool localSolverClient::checkCommandLine(){ + OLMsg::Info("Check command line for <%s>",getName().c_str()); + // if(getCommandLine().empty()){ + // // look if one has a commandLine on server + // std::string commandLine = getString("CommandLine"); + + if(getCommandLine().empty()) + OLMsg::Fatal("No commandline for client <%s>", getName().c_str()); + + if(!isActive()) return true; + + if(!getCommandLine().empty()){ + setAction("initialize"); + run(); + } + else{ + if(OLMsg::hasGmsh) { + // exits metamodel and restores control to the onelab window + OLMsg::Error("The command line of client <%s> is undefined.", + getName().c_str()); + std::cout << "\n\nBrowse for executable in the ONELAB window.\n\n" + << std::endl; + return false; + } + else{ // asks the user in console mode + std::cout << "\nONELAB:Enter the command line (with path) of the executable file of <" << getName() << ">" << std::endl; + std::string cmdl; + std::getline (std::cin,cmdl); + setCommandLine(cmdl); + return cmdl.size(); + } + } + return true; +} + +bool localSolverClient::buildRmCommand(std::string &cmd){ + std::vector<std::string> choices; + + cmd.assign(""); + if(!getWorkingDir().empty()) + cmd.append("cd " + getWorkingDir() + cmdSep); + + if(getList("OutputFiles",choices)){ +#if defined(WIN32) + cmd.append("del "); +#else + cmd.append("rm -rf "); +#endif + for(unsigned int i = 0; i < choices.size(); i++) + cmd.append(choices[i]+" "); + return true; + } + else + return false; +} + +void localSolverClient::PostArray(std::vector<std::string> choices) +{ + int nb=0; + while( 4*(nb+1) <= choices.size()){ + //std::cout << "Nb Choices" << choices.size() << std::endl; + int lin= atof(choices[4*nb+1].c_str()); + int col= atof(choices[4*nb+2].c_str()); + std::string fileName = getWorkingDir()+choices[4*nb]; + //checkIfPresent or make available locally + double val=find_in_array(lin,col,read_array(fileName,' ')); + OLMsg::AddOnelabNumberChoice(choices[4*nb+3],val); + OLMsg::Info("Upload parameter <%s>=%e from file <%s>", + choices[4*nb+3].c_str(),val,fileName.c_str()); + nb++; + } +} + +void localSolverClient::GmshMerge(std::vector<std::string> choices) +{ + //if(!OLMsg::hasGmsh || choices.empty()) return; + for(unsigned int i = 0; i < choices.size(); i++){ + if(!choices[i].empty()){ + std::string fileName=getWorkingDir()+choices[i]; + //checkIfPresent or make available locally + OLMsg::SendMergeFileRequest(fileName); + OLMsg::Info("Send merge request <%s>",fileName.c_str()); + } + } +} + + +// REMOTE CLIENT + +bool remoteClient::checkCommandLine(const std::string &commandLine){ + struct stat buf; + std::string cmd; + char cbuf [1024]; + FILE *fp; + + cmd.assign("ssh "+getRemoteHost()+" 'mkdir -p "+getRemoteDir()+"'"); + mySystem(cmd); + + cmd.assign("ssh "+getRemoteHost()+" 'which "+commandLine+"'"); + fp = popen(cmd.c_str(), "r"); + if(fgets(cbuf, 1024, fp) == NULL){ + OLMsg::Warning("The executable <%s> does not exist", + commandLine.c_str()); + pclose(fp); + return false; + } + OLMsg::Info("The executable <%s> exists", commandLine.c_str()); + pclose(fp); + + return true; +} + +bool remoteClient::checkIfPresentRemote(const std::string &fileName){ + struct stat buf; + std::string cmd; + char cbuf [1024]; + FILE *fp; + + cmd.assign("ssh "+_remoteHost+" 'cd "+_remoteDir+"; ls "+fileName+" 2>/dev/null'"); + //std::cout << "check remote<" << cmd << ">" << std::endl; + fp = popen(cmd.c_str(), "r"); + if(fgets(cbuf, 1024, fp) == NULL){ + OLMsg::Fatal("The file <%s> is not present", fileName.c_str()); + pclose(fp); + return false; + } + OLMsg::Info("The file <%s> is present", fileName.c_str()); + pclose(fp); + return true; +} + +bool remoteClient::syncInputFile(const std::string &wdir, const std::string &fileName){ + int pos; + std::string cmd; + if((pos=fileName.find(onelabExtension)) != std::string::npos){ + // .ol file => local + // remove ext .ol + std::string trueName = + fileName.substr(fileName.find_first_not_of(" "),pos); + std::string fullName = wdir+trueName; + if(checkIfPresent(fullName)){ + cmd.assign("rsync -e ssh -auv "+fullName+" "+_remoteHost+":"+_remoteDir+"/"+trueName); + return mySystem(cmd); + } + else{ + OLMsg::Fatal("The input file <%s> is not present", fullName.c_str()); + return false; + } + } + else { // not a .ol file, apply the . rule + if(!fileName.compare(fileName.find_first_not_of(" "),1,".")){ + //should be found local + std::string fullName = wdir+fileName; + if(checkIfPresent(fullName)){ + cmd.assign("rsync -e ssh -auv "+fullName+" "+_remoteHost+":"+_remoteDir+"/"+fileName); + return mySystem(cmd); + } + else{ + OLMsg::Fatal("The input file <%s> is not present", fullName.c_str()); + return false; + } + } + else { //should be found remote + if(!checkIfPresentRemote(fileName)){ + OLMsg::Fatal("The input file <%s> is not present", fileName.c_str()); + return false; + } + else + return true; + } + } +} + +bool remoteClient::syncOutputFile(const std::string &wdir, const std::string &fileName){ + std::string cmd; + + if(checkIfPresentRemote(fileName)){ + int pos=fileName.find_first_not_of(" "); + if(!fileName.compare(pos,1,".")){ // the file must be copied back locally + cmd.assign("rsync -e ssh -auv "+_remoteHost+":"+_remoteDir+dirSep + +fileName.substr(pos,std::string::npos)+" ."); + if(!wdir.empty()) + cmd.append(dirSep+wdir); + return mySystem(cmd); + } + } + else + return false; +} + +// client METAMODEL + +void MetaModel::saveCommandLines(const std::string fileName){ + //save client command lines + std::string fileNameSave = getWorkingDir()+fileName+onelabExtension+".save"; + std::ofstream outfile(fileNameSave.c_str()); + + if (outfile.is_open()) + for(citer it = _clients.begin(); it != _clients.end(); it++) + outfile << (*it)->toChar(); + else + OLMsg::Fatal("The file <%s> cannot be opened",fileNameSave.c_str()); + outfile.close(); +} + +bool MetaModel::checkCommandLines(){ + bool allDefined=true; + for(citer it = _clients.begin(); it != _clients.end(); it++){ + allDefined = allDefined && (*it)->checkCommandLine(); + } + saveCommandLines(genericNameFromArgs); + return allDefined; +} + +void MetaModel::initialize() +{ + OLMsg::Info("Initialize Metamodel by the loader"); + OLMsg::SetOnelabString(clientName + "/9CheckCommand","-a",false); + OLMsg::SetOnelabNumber(clientName + "/UseCommandLine",1,false); + OLMsg::SetOnelabNumber(clientName + "/Initialized",1,false); +} + +void MetaModel::analyze() { + std::string fileName = genericNameFromArgs + onelabExtension; + OLMsg::Info("Metamodel now ANALYZING",fileName.c_str()); + openOnelabBlock(); + parse_onefile(fileName); + closeOnelabBlock(); +} + + +void MetaModel::compute() { + std::string fileName = genericNameFromArgs + onelabExtension; + OLMsg::Info("Metamodel now COMPUTING",fileName.c_str()); + openOnelabBlock(); + parse_onefile(fileName); + closeOnelabBlock(); + onelab::server::instance()->setChanged(false); +} + +void MetaModel::registerClient(const std::string &name, const std::string &type, const std::string &cmdl, const std::string &host, const std::string &rdir) { + localSolverClient *c; + // Clients are assigned by default the same working dir as the MetaModel + // i.e. the working dir from args + if(host.empty() || rdir.empty()){ //local client + if(!type.compare(0,6,"interf")) + c= new InterfacedClient(name,cmdl,getWorkingDir()); + else if(!type.compare(0,6,"encaps")) + c= new NativeClient(name,cmdl,getWorkingDir()); + else + OLMsg::Fatal("Unknown client type", type.c_str()); + } + else{ // remote client + if(!type.compare(0,6,"interf")) + c= new RemoteInterfacedClient(name,cmdl,getWorkingDir(),host,rdir); + else if(!type.compare(0,6,"encaps")) + c= new RemoteNativeClient(name,cmdl,getWorkingDir(),host,rdir); + else + OLMsg::Fatal("Unknown remote client type", type.c_str()); + } + _clients.push_back(c); +} + +void MetaModel::PostArray(std::vector<std::string> choices) +{ + int nb=0; + //onelab::number o; + while( 4*(nb+1) <= choices.size()){ + int lin= atof(choices[4*nb+1].c_str()); + int col= atof(choices[4*nb+2].c_str()); + std::string fileName = + OLMsg::GetOnelabString("Arguments/WorkingDir")+choices[4*nb]; + double val=find_in_array(lin,col,read_array(fileName,' ')); + OLMsg::AddOnelabNumberChoice(choices[4*nb+3],val); + OLMsg::Info("PostArray <%s>=%e",choices[4*nb+3].c_str(),val); + nb++; + } +} + +// INTERFACED client + +void InterfacedClient::analyze() { + int pos; + std::vector<std::string> choices; + + setAction("check"); + OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(), + onelab::server::instance()->getChanged(getName())); + getList("InputFiles", choices); + for(unsigned int i = 0; i < choices.size(); i++){ + if((pos=choices[i].find(onelabExtension)) != std::string::npos){ + // if .ol file + checkIfPresentLocal(choices[i]); + parse_onefile(choices[i]); + } + } + convert(); +} + +void InterfacedClient::convert() { + int pos; + std::vector<std::string> choices; + getList("InputFiles", choices); + for(unsigned int i = 0; i < choices.size(); i++){ + if((pos=choices[i].find(onelabExtension)) != std::string::npos){ + checkIfPresentLocal(choices[i]); + // remove .ol extension + std::string ofileName = getWorkingDir() + choices[i].substr(0,pos); + std::ofstream outfile(ofileName.c_str()); + if (outfile.is_open()) + convert_onefile(choices[i],outfile); + else + OLMsg::Fatal("The file <%s> cannot be opened",ofileName.c_str()); + outfile.close(); + } + } +} + +void InterfacedClient::compute(){ + std::string cmd; + std::vector<std::string> choices; + + setAction("compute"); + OLMsg::Info("Computes <%s> changed=%d", getName().c_str(), + onelab::server::instance()->getChanged(getName())); + + if(getActive() && onelab::server::instance()->getChanged(getName())){ + analyze(); + //convert(); + if(getList("InputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++){ + //remove .ol ext + checkIfPresentLocal( + choices[i].substr(0,choices[i].find(onelabExtension))); + } + } + + if(buildRmCommand(cmd)) + SystemCall(cmd,true); //blocking + + cmd.assign(""); + if(!getWorkingDir().empty()) + cmd.append("cd " + getWorkingDir() + cmdSep); + cmd.append(FixWindowsPath(getCommandLine() + " ")); + cmd.append(getString("Arguments")); + + SystemCall(cmd.c_str(),true); //blocking + + if(getList("OutputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++){ + checkIfPresentLocal(choices[i]); + } + } + } + OLMsg::Info("Client %s completed",_name.c_str()); +} + +// NATIVE Client + +void NativeClient::analyze() { + setAction("check"); + OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(), + onelab::server::instance()->getChanged(getName())); + run(); +} + +void NativeClient::compute() { + std::string cmd; + std::vector<std::string> choices; + + setAction("compute"); + OLMsg::Info("Computes <%s> changed=%d", getName().c_str(), + onelab::server::instance()->getChanged(getName())); + if(getActive() && onelab::server::instance()->getChanged(getName())){ + if(buildRmCommand(cmd)) + SystemCall(cmd,true); + + if(getList("InputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++){ + checkIfPresentLocal(choices[i]); + } + } + run(); + + if(getList("OutputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++){ + checkIfPresentLocal(choices[i]); + } + } + } +} + +// REMOTE INTERFACED Client + +bool RemoteInterfacedClient::checkCommandLine(){ + return remoteClient::checkCommandLine(getCommandLine()); +} + +void RemoteInterfacedClient::compute(){ + std::string cmd,rmcmd; + std::vector<std::string> choices; + + setAction("compute"); + OLMsg::Info("Computes <%s> changed=%d", getName().c_str(), + onelab::server::instance()->getChanged(getName())); + + if(getActive() && onelab::server::instance()->getChanged(getName())){ + if(getList("InputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++) + syncInputFile(getWorkingDir(),choices[i]); + } + + if(buildRmCommand(rmcmd)){ + cmd.assign("ssh "+getRemoteHost()+" 'cd "+getRemoteDir()+"; "+rmcmd+"'"); + mySystem(cmd); + } + + cmd.assign("ssh "+getRemoteHost()+" 'cd "+getRemoteDir()+"; " + +getCommandLine()+" "+getString("Arguments")+"'"); + mySystem(cmd); + + if(getList("OutputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++) + syncOutputFile(getWorkingDir(),choices[i]); + } + + if(getList("PostArray",choices)) + PostArray(choices); + } +} + +// REMOTE NATIVE Client + +std::string RemoteNativeClient::buildCommandLine(){ + std::string command; + command.assign("incomp_ssh -f "+getRemoteHost()); + command.append(" 'cd "+getRemoteDir()+"; "); + command.append(FixWindowsPath(getCommandLine())+" "); + return command; +} + +bool RemoteNativeClient::checkCommandLine(){ + return remoteClient::checkCommandLine(getCommandLine()); +} + +void RemoteNativeClient::analyze(){ + std::string cmd,rmcmd; + std::vector<std::string> choices; + + setAction("check"); + OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(), + onelab::server::instance()->getChanged(getName())); + + if(getList("InputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++) + syncInputFile(getWorkingDir(),choices[i]); + } + run(); +} + + +void RemoteNativeClient::compute(){ + std::string cmd,rmcmd; + std::vector<std::string> choices; + + setAction("compute"); + OLMsg::Info("Analyses <%s> changed=%d", getName().c_str(), + onelab::server::instance()->getChanged(getName())); + + if(getActive() && onelab::server::instance()->getChanged(getName())){ + if(getList("InputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++) + syncInputFile(getWorkingDir(),choices[i]); + } + + if(buildRmCommand(rmcmd)){ + cmd.assign("ssh "+getRemoteHost()+" 'cd "+getRemoteDir()+"; "+rmcmd+"'"); + mySystem(cmd); + } + + run(); + + if(getList("OutputFiles",choices)){ + for(unsigned int i = 0; i < choices.size(); i++) + syncOutputFile(getWorkingDir(),choices[i]); + } + + if(getList("PostArray",choices)) + PostArray(choices); + } +} + +// ONELAB additional TOOLS (no access to server in tools) +// options for 'onelab_client' + +int getOptions(int argc, char *argv[], parseMode &todo, std::string &commandLine, std::string &caseName, std::string &clientName, std::string &sockName){ + + commandLine=argv[0]; + todo=COMPUTE; + caseName="untitled"; + int i= 1; + while(i < argc) { + if(argv[i][0] == '-') { + if(!strcmp(argv[i] + 1, "onelab")) { + i++; + clientName = argv[i]; + i++; + sockName = argv[i]; + i++; + } + else if(!strcmp(argv[i] + 1, "a")) { + i++; + todo=ANALYZE; + } + else if(!strcmp(argv[i] + 1, "c")) { + i++; + std::cout << "\nONELAB: Present state of the onelab clients\n" + << std::endl; + for(onelab::server::citer it=onelab::server::instance()->firstClient(); + it != onelab::server::instance()->lastClient(); it++){ + std::string name= it->second->getName(); + std::cout << "<" << onelab::server::instance()->getChanged(name) + << "> " << name << std::endl; + } + todo=ANALYZE; + } + else { + i++; + printf("Usage: %s [-m num -a -c]\n", argv[0]); + printf("Options are:\nm model number\n"); + printf("a analyze only\n"); + exit(1); + } + } + else{ + caseName=argv[i]; + i++; + } + } +} + +std::string itoa(const int i){ + std::ostringstream tmp; + tmp << i ; + return tmp.str(); +} + +std::string ftoa(const double x){ + std::stringstream Num; + Num << x; + return Num.str(); +} + +int mySystem(std::string commandLine){ + //std::cout << "mySystem<" << commandLine << ">" << std::endl; + return SystemCall(commandLine.c_str(), true); +} + +#include <sys/stat.h> +#include <ctime> +bool checkIfPresent(std::string fileName){ + struct stat buf; + if (!stat(fileName.c_str(), &buf)) + return true; + else{ + OLMsg::Fatal("The file <%s> is not present.",fileName.c_str()); + return false; + } +} + +#include <unistd.h> +#include <sys/types.h> +#if not defined WIN32 +#include <pwd.h> +std::string getUserHomedir(){ + struct passwd *pw = getpwuid(getuid()); + std::string str(pw->pw_dir); + str.append("/"); + return str; +} +#endif + +#include <sys/param.h> +std::string getCurrentWorkdir(){ + char path[MAXPATHLEN]; + getcwd(path, MAXPATHLEN); + std::string str = path; + return str; +} + +std::string sanitize(const std::string &in) +{ + std::string out, forbidden(" ();"); + for(unsigned int i = 0; i < in.size(); i++) + if ( forbidden.find(in[i]) == std::string::npos) + out.push_back(in[i]); + return out; +} +std::string removeBlanks(const std::string &in) +{ + int pos0=in.find_first_not_of(" "); + int pos=in.find_last_not_of(" "); + if( (pos0 != std::string::npos) && (pos != std::string::npos)) + return in.substr(pos0,pos-pos0+1); + else + return ""; +} +bool isPath(const std::string &in) +{ + int pos=in.find_last_not_of(" 0123456789"); + if(in.compare(pos,1,dirSep)) + OLMsg::Fatal("The argument <%s> is not a valid path (must end with '/')",in.c_str()); + return true; +} + +void GmshDisplay(onelab::remoteNetworkClient *loader, std::string fileName, std::vector<std::string> choices){ + if(choices.empty()) return; +#if defined(WIN32) + std::string cmd = "gmsh.exe "; +#else + std::string cmd = "gmsh "; +#endif + cmd.append( fileName + ".geo "); + for(unsigned int i = 0; i < choices.size(); i++){ + std::string fileName=OLMsg::GetOnelabString("Arguments/WorkingDir")+choices[i]; + cmd.append(fileName+" "); + if(OLMsg::hasGmsh){ + loader->sendMergeFileRequest(fileName); + OLMsg::Info("Send merge request <%s>",fileName.c_str()); + } + } + if(!OLMsg::hasGmsh) system(cmd.c_str()); +} + +std::vector <double> extract_column(const int col, array data){ + std::vector<double> column; + for ( int i=0; i<data.size(); i++) + if ( col>0 && col<=data[i].size()) + column.push_back(data[i][col-1]); + else + OLMsg::Fatal("Column number (%d) out of range.",col); + return column; +} + +double find_in_array(int lin, int col, const std::vector <std::vector <double> > &data){ + if ( lin<0 ) { + lin=data.size(); + } + if ( lin>=1 && lin<=data.size()){ + if ( col>=1 && col<=data[lin-1].size() ) + return data[lin-1][col-1]; + } + OLMsg::Fatal("The value has not been calculated: (%d,%d) out of range",lin,col); +} + +array read_array(std::string fileName, char sep){ + std::ifstream infile(sanitize(fileName).c_str()); + std::vector <std::vector <double> > array; + + int deb,end; + double temp; + while (infile){ + std::string s; + if (!getline( infile, s )) break; + std::vector <double> record; + end=0; + while ( (deb=s.find_first_not_of(" \t\n", end)) != std::string::npos ) { + end=s.find_first_of(" \t\n",deb); + temp=atof( s.substr(deb,end).c_str() ); + record.push_back( temp ); + } + array.push_back( record ); + } + if (!infile.eof()){ + std::cerr << "Error reading array\n"; + } + return array; +} diff --git a/contrib/onelab/OnelabClients.h b/contrib/onelab/OnelabClients.h new file mode 100644 index 0000000000..ffcaf6619b --- /dev/null +++ b/contrib/onelab/OnelabClients.h @@ -0,0 +1,316 @@ +// ONELAB - Copyright (C) 2010-2012 C. Geuzaine, F. Henrotte +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#ifndef _ONELAB_CLIENTS_H_ +#define _ONELAB_CLIENTS_H_ + +#include <stdlib.h> +#include <fstream> +#include <iostream> +#include <sstream> + +#include "OS.h" +#include "onelab.h" +#include "OnelabMessage.h" + +// Onelab file extension +static std::string onelabExtension(".ol"); +// Possible actions for clients +enum parseMode {INITIALIZE, REGISTER, ANALYZE, COMPUTE, EXIT, STOP}; + +static char charSep() { return '\0'; } +#if defined(WIN32) +static std::string dirSep("\\"); +static std::string cmdSep(" & "); +#else +static std::string dirSep("/"); +static std::string cmdSep(" ; "); +#endif + +// TOOLS +int getOptions(int argc, char *argv[], parseMode &todo, std::string &commandLine, std::string &caseName, std::string &clientName, std::string &sockName); +std::string itoa(const int i); +std::string ftoa(const double x); +bool checkIfPresent(std::string fileName); +int mySystem(std::string commandLine); +void GmshDisplay(onelab::remoteNetworkClient *loader, std::string fileName, std::vector<std::string> choices); +std::string getCurrentWorkdir(); +std::string getUserHomedir(); +std::string sanitize(const std::string &in); +std::string removeBlanks(const std::string &in); +bool isPath(const std::string &in); + +// Parser TOOLS +int enclosed(const std::string &in, std::vector<std::string> &arguments); +int extract(const std::string &in, std::string ¶mName, std::string &action, std::vector<std::string> &arguments); +bool extractRange(const std::string &in, std::vector<double> &arguments); +std::string extractExpandPattern(const std::string& str); + + +typedef std::vector <std::vector <double> > array; +array read_array(std::string fileName, char sep); +double find_in_array(int i, int j, const std::vector <std::vector <double> > &data); +std::vector<double> extract_column(const int j, array data); + +static std::string getShortName(const std::string &name) { + 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 numbers + while(s.size() && s[0] >= '0' && s[0] <= '9') + s = s.substr(1); + return s; +} + +class ShortNameLessThan{ + public: + bool operator()(const std::string p1, const std::string p2) const + { + return getShortName(p1) < getShortName(p2); + } +}; + +/* +VIRTUAL and BASE CLASSES + +"localSolverClient" is the base class +for all onelab clients called from a metamodel. +It inherits from the "LocalClient" class of "onelab.h" +and has the additional metamodel specific functions: +analyze(), compute(), checkIfPresent(), checkCommandLine(), +inputFile(), outputFile() + +The subclass "localSolverNetworkClient" of "localSolverClient" +is for native clients (Gmsh and getDP so far) +that communicate with the server through sockets. +It has a GmshServer member, +uses localNetworkSolverClient::run instead of onelab::client::run(). + +Both "localSolverNetworkClient" and "localSolverClient" are pure virtual. + +The combination of two alternatives native/interfaced and local/remote +yields 4 clients: +InterfacedClient, RemoteInterfacesClient +NativeClient, RemoteINterfacedClient + +The base class "remoteClient" is a base class +for clients running on a remote host. +It provides appropriate versions of checkIfPresent() and checkCommandLine(). +*/ +class localSolverClient : public onelab::localClient{ + private: + std::string _commandLine; + std::string _workingDir; + int _active; + bool _onelabBlock; + std::set<std::string, ShortNameLessThan> _parameters; + std::string longName(const std::string name); + public: + localSolverClient(const std::string &name, const std::string &cmdl, + const std::string &wdir) + : onelab::localClient(name), _commandLine(cmdl), _workingDir(wdir), + _active(1), _onelabBlock(false) { + } + virtual ~localSolverClient(){} + const std::string &getCommandLine(){ return _commandLine; } + const std::string &getWorkingDir() { return _workingDir; } + virtual void setCommandLine(const std::string &s){ _commandLine = s; } + virtual void setWorkingDir(const std::string &s){ _workingDir = s; } + + void setAction(const std::string action); + const std::string getString(const std::string what); + const bool getList(const std::string type, + std::vector<std::string> &choices); + const bool isActive() { return (bool)_active; } + const void setActive(int val) { _active=val; } + int getActive() { return _active; } + virtual std::string toChar(); + + // parser + void modify_tags(const std::string lab, const std::string com); + const bool isOnelabBlock() { return _onelabBlock; } + const void openOnelabBlock() { _onelabBlock=true; } + const void closeOnelabBlock() { _onelabBlock=false; } + std::string resolveGetVal(std::string line); + bool resolveLogicExpr(std::vector<std::string> arguments); + void parse_sentence(std::string line) ; + void parse_oneline(std::string line, std::ifstream &infile) ; + bool parse_block(std::ifstream &infile) ; + bool parse_ifstatement(std::ifstream &infile, bool condition) ; + void parse_onefile(std::string ifileName, bool mandatory=true); + void convert_oneline(std::string line, std::ifstream &infile, + std::ofstream &outfile); + bool convert_ifstatement(std::ifstream &infile, + std::ofstream &outfile, bool condition) ; + void convert_onefile(std::string ifileName, std::ofstream &outfile); + virtual void client_sentence(const std::string &name, + const std::string &action, + const std::vector<std::string> &arguments); + + // execution + bool buildRmCommand(std::string &cmd); + bool checkIfPresentLocal(const std::string &fileName){ + return checkIfPresent(getWorkingDir()+fileName); + } + virtual bool checkCommandLine(); + virtual void analyze() =0; + virtual void compute() =0; + void PostArray(std::vector<std::string> choices); + void GmshMerge(std::vector<std::string> choices); +}; + +class localNetworkSolverClient : public localSolverClient{ + private: + // command line option to specify socket + std::string _socketSwitch; + // pid of the remote network client + int _pid; + // underlying GmshServer + GmshServer *_gmshServer; + // flag indicating if the client is a remote one + bool _remote; + public: + localNetworkSolverClient(const std::string &name, const std::string &cmdl, const std::string &wdir) + : localSolverClient(name,cmdl,wdir), _socketSwitch("-onelab"), + _pid(-1), _gmshServer(0), _remote(false) {} + virtual ~localNetworkSolverClient(){} + virtual bool isNetworkClient(){ return true; } + 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; } + int getRemote(){ return _remote; } + void setRemote(bool rem){ _remote = rem; } + + virtual std::string buildCommandLine(); + std::string appendArguments(); + virtual bool run(); + virtual bool kill(); + + virtual void analyze() =0; + virtual void compute() =0; +}; + +class remoteClient { + private: + std::string _remoteHost; + std::string _remoteDir; + public: + remoteClient(const std::string &host, const std::string &rdir) + : _remoteHost(host), _remoteDir(rdir) {} + ~remoteClient(){} + + const std::string &getRemoteHost() const { return _remoteHost; } + const std::string &getRemoteDir() const { return _remoteDir; } + + bool checkCommandLine(const std::string &commandLine); + bool checkIfPresentRemote(const std::string &fileName); + bool syncInputFile(const std::string &wdir, const std::string &fileName); + bool syncOutputFile(const std::string &wdir, const std::string &fileName); +}; + +// ONELAB CLIENTS + +class MetaModel : public localSolverClient { + private: + std::vector<localSolverClient *> _clients; + parseMode _todo; + public: + MetaModel(const std::string &cmdl, const std::string &wdir, const std::string &cname, const std::string &fname) + : localSolverClient(cname,cmdl,wdir){ + clientName = cname; + genericNameFromArgs = fname.size() ? fname : cmdl; + setWorkingDir(wdir); // wdir from args + openOnelabBlock(); + _todo=REGISTER; + parse_onefile( genericNameFromArgs + onelabExtension + ".save",false); + parse_onefile( genericNameFromArgs + onelabExtension); + closeOnelabBlock(); + } + ~MetaModel(){} + typedef std::vector<localSolverClient*>::iterator citer; + void setTodo(const parseMode x) { _todo=x; } + parseMode getTodo() { return _todo; } + bool isTodo(const parseMode x) { return (_todo==x);} + citer firstClient(){ return _clients.begin(); } + citer lastClient(){ return _clients.end(); } + int getNumClients() { return _clients.size(); }; + + void registerClient(const std::string &name, const std::string &type, + const std::string &cmdl, const std::string &host, + const std::string &rdir); + bool checkCommandLines(); + void saveCommandLines(const std::string fileName); + localSolverClient *findClientByName(std::string name){ + for(unsigned int i=0; i<_clients.size(); i++) + if(_clients[i]->getName() == name) return _clients[i]; + return 0; + } + std::string genericNameFromArgs, clientName; + void client_sentence(const std::string &name, const std::string &action, + const std::vector<std::string> &arguments); + std::string toChar(){} + void PostArray(std::vector<std::string> choices); + void initialize(); + void analyze(); + void compute(); +}; + +class InterfacedClient : public localSolverClient { + // n'utilise pas localNetworkSolverClient::run mais client::run() + public: + InterfacedClient(const std::string &name, const std::string &cmdl, const std::string &wdir) + : localSolverClient(name,cmdl,wdir) {} + ~InterfacedClient(){} + + void analyze(); + void convert(); + virtual void compute(); +}; + +class NativeClient : public localNetworkSolverClient { + // utilise localNetworkClient::run +public: + NativeClient(const std::string &name, const std::string &cmdl, const std::string &wdir) + : localNetworkSolverClient(name,cmdl,wdir) {} + ~NativeClient(){} + + //uses localNetworkSolver::buildCommandLine(); + virtual void analyze(); + virtual void compute() ; +}; + +class RemoteInterfacedClient : public InterfacedClient, public remoteClient { +public: + RemoteInterfacedClient(const std::string &name, const std::string &cmdl, const std::string &wdir, const std::string &host, const std::string &rdir) + : InterfacedClient(name,cmdl,wdir), remoteClient(host,rdir) {} + ~RemoteInterfacedClient(){} + + bool checkCommandLine(); + // uses InterfacedClient::analyze() + void compute() ; +}; + +class RemoteNativeClient : public NativeClient, public remoteClient { +public: + RemoteNativeClient(const std::string &name, const std::string &cmdl, const std::string &wdir, const std::string &host, const std::string &rdir) + : NativeClient(name,cmdl,wdir), remoteClient(host,rdir) { + setRemote(true); + } + ~RemoteNativeClient(){} + + std::string buildCommandLine(); + bool checkCommandLine(); + void analyze(); + void compute() ; +}; + +#endif + + diff --git a/contrib/onelab/OnelabMessage.cpp b/contrib/onelab/OnelabMessage.cpp new file mode 100644 index 0000000000..8416063622 --- /dev/null +++ b/contrib/onelab/OnelabMessage.cpp @@ -0,0 +1,664 @@ +// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <algorithm> +#include "OnelabMessage.h" +#include "GmshSocket.h" +#include "OS.h" + +#define ALWAYS_TRUE 1 + +onelab::remoteNetworkClient *OLMsg::loader = 0; + +int OLMsg::_commRank = 0; +int OLMsg::_commSize = 1; +int OLMsg::_verbosity = 4; +// int OLMsg::_progressMeterStep = 10; +// int OLMsg::_progressMeterCurrent = 0; +// std::map<std::string, double> OLMsg::_timers; +int OLMsg::_warningCount = 0; +int OLMsg::_errorCount = 0; +GmshMessage *OLMsg::_callback = 0; +std::string OLMsg::_commandLine; +std::string OLMsg::_launchDate; +GmshClient *OLMsg::_client = 0; +onelab::client *OLMsg::_onelabClient = 0; +bool OLMsg::hasGmsh=false; +std::set<std::string, fullNameLessThan> OLMsg::_fullNameDict; + +#if defined(HAVE_NO_VSNPRINTF) +static int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) +{ + if(strlen(fmt) > size - 1){ // just copy the format + strncpy(str, fmt, size - 1); + str[size - 1] = '\0'; + return size; + } + return vsprintf(str, fmt, ap); +} +#endif + +#if defined(_MSC_VER) && (_MSC_VER == 1310) //NET 2003 +#define vsnprintf _vsnprintf +#endif + +void OLMsg::Init(int argc, char **argv) +{ + time_t now; + time(&now); + _launchDate = ctime(&now); + _launchDate.resize(_launchDate.size() - 1); + _commandLine.clear(); + for(int i = 0; i < argc; i++){ + if(i) _commandLine += " "; + _commandLine += argv[i]; + } +} + +void OLMsg::Exit(int level) +{ + if(level){ + exit(level); + } + exit(_errorCount); +} + +void OLMsg::Fatal(const char *fmt, ...) +{ + _errorCount++; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(_callback) (*_callback)("Fatal", str); + if(_client) _client->Error(str); + + if(ALWAYS_TRUE){ + if(_commSize > 1) + fprintf(stderr, "Fatal : [On processor %d] %s\n", _commRank, str); + else + fprintf(stderr, "Fatal : %s\n", str); + fflush(stderr); + } + + OLMsg::SetOnelabString("MetaModel/STATUS","STOP"); + FinalizeClient(); + FinalizeOnelab(); + delete loader; + Exit(1); +} + +void OLMsg::Error(const char *fmt, ...) +{ + _errorCount++; + + if(_verbosity < 1) return; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(_callback) (*_callback)("Error", str); + if(_client) _client->Error(str); + + if(ALWAYS_TRUE){ + if(_commSize > 1) + fprintf(stderr, "Error : [On processor %d] %s\n", _commRank, str); + else + fprintf(stderr, "Error : %s\n", str); + fflush(stderr); + } +} + +void OLMsg::Warning(const char *fmt, ...) +{ + _warningCount++; + + if(_commRank || _verbosity < 2) return; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(_callback) (*_callback)("Warning", str); + if(_client) _client->Warning(str); + + if(ALWAYS_TRUE){ + fprintf(stderr, "Warning : %s\n", str); + fflush(stderr); + } +} + + + +void OLMsg::Info(const char *fmt, ...) +{ + if(_commRank || _verbosity < 3) return; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(_callback) (*_callback)("Info", str); + if(_client) _client->Info(str); + + if(ALWAYS_TRUE){ + fprintf(stdout, "Onelab : %s\n", str); + fflush(stdout); + } +} + +void OLMsg::Direct(const char *fmt, ...) +{ + if(_commRank || _verbosity < 3) return; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + Direct(3, str); +} + +void OLMsg::Direct(int level, const char *fmt, ...) +{ + if(_commRank || _verbosity < level) return; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(_callback) (*_callback)("Direct", str); + if(_client) _client->Info(str); + + if(ALWAYS_TRUE){ + fprintf(stdout, "%s\n", str); + fflush(stdout); + } +} + +void OLMsg::StatusBar(int num, bool log, const char *fmt, ...) +{ + if(_commRank || _verbosity < 3) return; + if(num < 1 || num > 3) return; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(_callback && log) (*_callback)("Info", str); + if(_client && log) _client->Info(str); + + if(log && ALWAYS_TRUE){ + fprintf(stdout, "Info : %s\n", str); + fflush(stdout); + } +} + +/* +void OLMsg::Debug(const char *fmt, ...) +{ + if(_verbosity < 99) return; + + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(_callback) (*_callback)("Debug", str); + if(_client) _client->Info(str); + + if(ALWAYS_TRUE){ + if(_commSize > 1) + fprintf(stdout, "Debug : [On processor %d] %s\n", _commRank, str); + else + fprintf(stdout, "Debug : %s\n", str); + fflush(stdout); + } +} + +void OLMsg::ProgressMeter(int n, int N, const char *fmt, ...) +{ + if(_commRank || _verbosity < 3) return; + + double percent = 100. * (double)n/(double)N; + + if(percent >= _progressMeterCurrent){ + char str[1024]; + va_list args; + va_start(args, fmt); + vsnprintf(str, sizeof(str), fmt, args); + va_end(args); + + if(strlen(fmt)) strcat(str, " "); + + char str2[1024]; + sprintf(str2, "(%d %%)", _progressMeterCurrent); + strcat(str, str2); + + if(_client) _client->Progress(str); + + if(ALWAYS_TRUE){ + fprintf(stdout, "%s \r", str); + fflush(stdout); + } + + while(_progressMeterCurrent < percent) + _progressMeterCurrent += _progressMeterStep; + } + + if(n > N - 1){ + if(_client) _client->Progress("Done!"); + + if(ALWAYS_TRUE){ + fprintf(stdout, "Done! \r"); + fflush(stdout); + } + } +} + +void OLMsg::PrintTimers() +{ + // do a single stdio call! + std::string str; + for(std::map<std::string, double>::iterator it = _timers.begin(); + it != _timers.end(); it++){ + if(it != _timers.begin()) str += ", "; + char tmp[256]; + sprintf(tmp, "%s = %gs ", it->first.c_str(), it->second); + str += std::string(tmp); + } + if(!str.size()) return; + + if(ALWAYS_TRUE){ + if(_commSize > 1) + fprintf(stdout, "Timers : [On processor %d] %s\n", _commRank, str.c_str()); + else + fprintf(stdout, "Timers : %s\n", str.c_str()); + fflush(stdout); + } +} + +void OLMsg::PrintErrorCounter(const char *title) +{ + if(_commRank || _verbosity < 1) return; + if(!_warningCount && !_errorCount) return; + + std::string prefix = _errorCount ? "Error : " : "Warning : "; + std::string help("Check the full log for details"); + std::string line(std::max(strlen(title), help.size()), '-'); + char warn[128], err[128]; + sprintf(warn, "%5d warning%s", _warningCount, _warningCount == 1 ? "" : "s"); + sprintf(err, "%5d error%s", _errorCount, _errorCount == 1 ? "" : "s"); + + if(ALWAYS_TRUE){ + fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n", (prefix + line).c_str(), + (prefix + title).c_str(), (prefix + warn).c_str(), + (prefix + err).c_str(), (prefix + help).c_str(), + (prefix + line).c_str()); + fflush(stderr); + } +} + +double OLMsg::GetValue(const char *text, double defaultval) +{ + printf("%s (default=%.16g): ", text, defaultval); + char str[256]; + char *ret = fgets(str, sizeof(str), stdin); + if(!ret || !strlen(str) || !strcmp(str, "\n")) + return defaultval; + else + return atof(str); +} + +std::string OLMsg::GetString(const char *text, std::string defaultval) +{ + printf("%s (default=%s): ", text, defaultval.c_str()); + char str[256]; + char *ret = fgets(str, sizeof(str), stdin); + if(!ret || !strlen(str) || !strcmp(str, "\n")) + return defaultval; + else + return std::string(str); +} + +int OLMsg::GetAnswer(const char *question, int defaultval, const char *zero, + const char *one, const char *two) +{ + if(two) + printf("%s\n\n0=[%s] 1=[%s] 2=[%s] (default=%d): ", question, + zero, one, two, defaultval); + else + printf("%s\n\n0=[%s] 1=[%s] (default=%d): ", question, + zero, one, defaultval); + char str[256]; + char *ret = fgets(str, sizeof(str), stdin); + if(!ret || !strlen(str) || !strcmp(str, "\n")) + return defaultval; + else + return atoi(ret); +} + +void OLMsg::InitClient(std::string sockname) +{ + if(_client) delete _client; + _client = new GmshClient(); + if(_client->Connect(sockname.c_str()) < 0){ + OLMsg::Error("Unable to connect to server on %s", sockname.c_str()); + delete _client; + _client = 0; + } + else + _client->Start(); +} + +void OLMsg::Barrier() +{ +} +*/ +void OLMsg::FinalizeClient() +{ + if(_client){ + _client->Stop(); + _client->Disconnect(); + delete _client; + } + _client = 0; +} + +void OLMsg::InitializeOnelab(const std::string &name, const std::string &sockname) +{ + if(_onelabClient) delete _onelabClient; + if (sockname.empty()) + _onelabClient = new onelab::localClient(name); + else{ + onelab::remoteNetworkClient *c = + new onelab::remoteNetworkClient(name, sockname); + _onelabClient = c; + _client = c->getGmshClient(); + } +} + +double OLMsg::GetOnelabNumber(std::string name) +{ + if(_onelabClient){ + std::vector<onelab::number> ps; + _onelabClient->get(ps, name); + if(ps.size()) + return ps[0].getValue(); + } + return 0; +} + +void OLMsg::GetOnelabNumber(std::string name, double *val) +{ + if(_onelabClient){ + std::vector<onelab::number> ps; + _onelabClient->get(ps, name); + if(ps.size()){ + *val = ps[0].getValue(); + return; + } + } + *val = 0; +} + +void OLMsg::SetOnelabNumber(std::string name, double val, bool visible) +{ + if(_onelabClient){ + std::vector<onelab::number> numbers; + _onelabClient->get(numbers, name); + if(numbers.empty()){ + numbers.resize(1); + numbers[0].setName(name); + } + numbers[0].setValue(val); + numbers[0].setVisible(visible); + _onelabClient->set(numbers[0]); + } +} + +std::string OLMsg::GetOnelabString(std::string name) +{ + std::string str=""; + if(_onelabClient){ + std::vector<onelab::string> ps; + _onelabClient->get(ps, name); + if(ps.size() && ps[0].getValue().size()) + str = ps[0].getValue(); + } + return str; +} + +bool OLMsg::GetOnelabChoices(std::string name, std::vector<std::string> &choices){ + if(_onelabClient){ + std::vector<onelab::string> ps; + _onelabClient->get(ps, name); + if(ps.size() && ps[0].getValue().size()){ + choices=ps[0].getChoices(); + return true; + } + } + return false; +} + +void OLMsg::SetOnelabString(std::string name, std::string val, bool visible) +{ + if(_onelabClient){ + std::vector<onelab::string> strings; + _onelabClient->get(strings, name); + if(strings.empty()){ + strings.resize(1); + strings[0].setName(name); + } + strings[0].setValue(val); + strings[0].setVisible(visible); + _onelabClient->set(strings[0]); + } +} + +void OLMsg::SetOnelabAttributeString(std::string name, + std::string attrib,std::string val){ + if(_onelabClient){ + std::vector<onelab::string> ps; + _onelabClient->get(ps, name); + if(ps.size()){ + ps[0].setAttribute(attrib,val); + } + } +} +std::string OLMsg::GetOnelabAttributeString(std::string name,std::string attrib){ + std::string str=""; + if(_onelabClient){ + std::vector<onelab::string> ps; + _onelabClient->get(ps, name); + if(ps.size()) + str = ps[0].getAttribute(attrib); + } + return str; +} +std::string OLMsg::GetOnelabAttributeNumber(std::string name,std::string attrib){ + std::string str=""; + if(_onelabClient){ + std::vector<onelab::number> ps; + _onelabClient->get(ps, name); + if(ps.size()) + str = ps[0].getAttribute(attrib); + } + return str; +} + +void OLMsg::AddOnelabNumberChoice(std::string name, double val) +{ + if(_onelabClient){ + std::vector<double> choices; + std::vector<onelab::number> ps; + _onelabClient->get(ps, name); + if(ps.size()){ + choices = ps[0].getChoices(); + } + else{ + ps.resize(1); + ps[0].setName(name); + } + ps[0].setAttribute("Highlight","Coral"); // only used by PostArray + ps[0].setReadOnly(false); + ps[0].setVisible(true); + ps[0].setValue(val); + choices.push_back(val); + ps[0].setChoices(choices); + _onelabClient->set(ps[0]); + } +} + +int fullNameLessThan::compareFullNames(const std::string a, const std::string b) const{ + std::string::const_iterator ita, itb; + ita=a.begin(); itb=b.begin(); + if( (*ita >= '0') && (*ita <= '9')) ita++; + if( (*itb >= '0') && (*itb <= '9')) itb++; + + while( (ita<a.end()) && (itb<b.end()) && (*ita == *itb) ){ + if(*ita == '/'){ + ita++; + if( (*ita >= '0') && (*ita <= '9')) ita++; + } + else + ita++; + + if(*itb == '/'){ + itb++; + if( (*itb >= '0') && (*itb <= '9')) itb++; + } + else + itb++; + } + return *ita < *itb ; +} +void OLMsg::recordFullName(const std::string &name){ + OLMsg::_fullNameDict.insert(name); +} +std::string OLMsg::obtainFullName(const std::string &name){ + std::set<std::string, fullNameLessThan>::iterator it; + + // fullNameLessThan* comp=new fullNameLessThan; + // std::cout << "Dict=" << OLMsg::_fullNameDict.size() << std::endl; + // std::cout << "Looking for " << name << std::endl; + // for ( it=OLMsg::_fullNameDict.begin() ; it != OLMsg::_fullNameDict.end(); it++ ) + // std::cout << *it << " <" << comp->operator()(*it,name) << ">" << std::endl; + // std::cout << std::endl; + + it = OLMsg::_fullNameDict.find(name); + if(it == OLMsg::_fullNameDict.end()){ + return name; + } + else{ + return *it; + } +} + +void OLMsg::SendMergeFileRequest(const std::string &name){ + _onelabClient->sendMergeFileRequest(name); +} + +int OLMsg::Synchronize_Down(){ + OLMsg::_fullNameDict.clear(); + std::vector<onelab::number> numbers; + loader->get(numbers,""); + if(numbers.size()){ + for(std::vector<onelab::number>::const_iterator it = numbers.begin(); + it != numbers.end(); it++){ + if(_onelabClient) _onelabClient->set(*it); + OLMsg::recordFullName((*it).getName()); + //std::cout << "FHF d " << (*it).getName() << "=" << (*it).getChanged() << std::endl; + } + } + std::vector<onelab::string> strings; + loader->get(strings,""); + if(strings.size()){ + for(std::vector<onelab::string>::const_iterator it = strings.begin(); + it != strings.end(); it++){ + if(_onelabClient) _onelabClient->set(*it); + OLMsg::recordFullName((*it).getName()); + //std::cout << "FHF d " << (*it).getName() << "=" << (*it).getChanged() << std::endl; + } + } + std::vector<onelab::region> regions; + loader->get(regions,""); + if(regions.size()){ + for(std::vector<onelab::region>::const_iterator it = regions.begin(); + it != regions.end(); it++){ + if(_onelabClient) _onelabClient->set(*it); + OLMsg::recordFullName((*it).getName()); + } + } + return(numbers.size()+strings.size()+regions.size()); +} + +int OLMsg::Synchronize_Up(){ + std::vector<onelab::number> numbers; + _onelabClient->get(numbers,""); + if(numbers.size()){ + for(std::vector<onelab::number>::const_iterator it = numbers.begin(); + it != numbers.end(); it++){ + loader->set(*it); + //std::cout << "FHF u " << (*it).getName() << "=" + //<< (*it).getChanged() << std::endl; + } + } + loader->get(numbers,""); + if(numbers.size()){ + for(std::vector<onelab::number>::const_iterator it = numbers.begin(); + it != numbers.end(); it++){ + //std::cout << "FHF control " << (*it).getName() << "=" + //<< (*it).getChanged() << std::endl; + } + } + + std::vector<onelab::string> strings; + _onelabClient->get(strings,""); + if(strings.size()){ + for(std::vector<onelab::string>::const_iterator it = strings.begin(); + it != strings.end(); it++){ + loader->set(*it); + //std::cout << "FHF u " << (*it).getName() << "=" << (*it).getChanged() << std::endl; + } + } + std::vector<onelab::region> regions; + _onelabClient->get(regions,""); + if(regions.size()){ + for(std::vector<onelab::region>::const_iterator it = regions.begin(); + it != regions.end(); it++){ + loader->set(*it); + } + } + return(numbers.size()+strings.size()+regions.size()); +} + +void OLMsg::FinalizeOnelab(){ + if(_onelabClient){ + delete _onelabClient; + _onelabClient = 0; + _client = 0; + } +} diff --git a/contrib/onelab/OnelabMessage.h b/contrib/onelab/OnelabMessage.h new file mode 100644 index 0000000000..5e5b8f1894 --- /dev/null +++ b/contrib/onelab/OnelabMessage.h @@ -0,0 +1,132 @@ +// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. + +#ifndef _ONELAB_MESSAGE_H_ +#define _ONELAB_MESSAGE_H_ + +#include <map> +#include <string> +#include <set> +#include <stdarg.h> +#include "onelab.h" + +class GmshClient; + +// the external message handler +class GmshMessage{ + public: + GmshMessage(){} + virtual ~GmshMessage(){} + virtual void operator()(std::string level, std::string message){} +}; + +class fullNameLessThan{ +public: + int compareFullNames(const std::string a, const std::string b) const; + bool operator()(const std::string p1, const std::string p2) const{ + return compareFullNames(p1,p2); + } +}; + +// a class to manage messages +class OLMsg { + private: + // current cpu number and total number of cpus + static int _commRank, _commSize; + // verbosity level (0: silent except fatal errors, 1: +errors, 2: + // +warnings, 3: +info except status bar, 4: normal, 99: debug) + static int _verbosity; + // step (in %) of the progress meter and current progress % + static int _progressMeterStep, _progressMeterCurrent; + // timers + static std::map<std::string, double> _timers; + // counters + static int _warningCount, _errorCount; + // callback + static GmshMessage *_callback; + // command-line and startup time + static std::string _commandLine, _launchDate; + // communication with Gmsh when run remotely + static GmshClient *_client; + // communication with onelab server + static onelab::client *_onelabClient; + // dictionnary for parameter names + static std::set<std::string, fullNameLessThan> _fullNameDict; + public: + OLMsg() {} + static void Init(int argc, char **argv); + static void Exit(int level); + /* static int GetCommRank(){ return _commRank; } */ + /* static int GetCommSize(){ return _commSize; } */ + /* static void SetCommRank(int val){ _commRank = val; } */ + /* static void SetCommSize(int val){ _commSize = val; } */ + /* static void SetCallback(GmshMessage *callback){ _callback = callback; } */ + /* static void Barrier(); */ + /* static int GetNumThreads(); */ + /* static int GetMaxThreads(); */ + /* static int GetThreadNum(); */ + /* static void SetVerbosity(int val){ _verbosity = val; } */ + /* static int GetVerbosity(){ return _verbosity; } */ + /* static std::string GetLaunchDate(){ return _launchDate; } */ + /* static std::string GetCommandLineArgs(){ return _commandLine; } */ + static void Fatal(const char *fmt, ...); + static void Error(const char *fmt, ...); + static void Warning(const char *fmt, ...); + static void Info(const char *fmt, ...); + static void Direct(const char *fmt, ...); + static void Direct(int level, const char *fmt, ...); + static void StatusBar(int num, bool log, const char *fmt, ...); + static void Debug(const char *fmt, ...); + static void ProgressMeter(int n, int N, const char *fmt, ...); + static void ProgressMeter(int n, int N){ ProgressMeter(n, N, ""); } + static void SetProgressMeterStep(int step){ _progressMeterStep = step; } + static void ResetProgressMeter(){ if(!_commRank) _progressMeterCurrent = 0; } + static double &Timer(std::string str){ return _timers[str]; } + static void PrintTimers(); + static void ResetErrorCounter(){ _warningCount = 0; _errorCount = 0; } + static void PrintErrorCounter(const char *title); + static double GetValue(const char *text, double defaultval); + static std::string GetString(const char *text, std::string defaultval); + static int GetAnswer(const char *question, int defaultval, const char *zero, + const char *one, const char *two=0); + static void InitClient(std::string sockname); + static GmshClient *GetClient(){ return _client; } + static void FinalizeClient(); + static void InitializeOnelab(const std::string &name, + const std::string &sockname); + static void SetOnelabClient(onelab::client *client){ _onelabClient = client; } + static void SetOnelabNumber(std::string name, double val, bool visible=true); + static void GetOnelabNumber(std::string name, double *val); + static double GetOnelabNumber(std::string name); + static void SetOnelabString(std::string name, std::string val, bool visible=true); + static std::string GetOnelabString(std::string name); + static void SetOnelabAttributeString(std::string name, + std::string attrib,std::string val); + static std::string GetOnelabAttributeString(std::string name,std::string attrib); + static std::string GetOnelabAttributeNumber(std::string name, + std::string attrib); + //static std::vector<std::string> GetOnelabChoices(std::string name); + static bool GetOnelabChoices(std::string name, std::vector<std::string> &choices); + static void ExchangeOnelabParameter(const std::string &key, + std::vector<double> &val, + std::map<std::string, + std::vector<double> > &fopt, + std::map<std::string, + std::vector<std::string> > &copt); + static void AddOnelabNumberChoice(std::string name, double val); + + static void SendMergeFileRequest(const std::string &name); + + // communication with loader + static onelab::remoteNetworkClient *loader; + static bool hasGmsh; + static int Synchronize_Down(); + static int Synchronize_Up(); + static void FinalizeOnelab(); + static void recordFullName(const std::string &name); + static std::string obtainFullName(const std::string &name); +}; + +#endif diff --git a/contrib/onelab/OnelabParser.cpp b/contrib/onelab/OnelabParser.cpp new file mode 100644 index 0000000000..821ca83d84 --- /dev/null +++ b/contrib/onelab/OnelabParser.cpp @@ -0,0 +1,1344 @@ +#include "OnelabClients.h" +#include <algorithm> +#include "mathex.h" + +// reserved keywords for the onelab parser + +namespace olkey{ + static std::string deflabel("onelab.tags"); + static std::string label("OL."), comment("#"), separator(";"); + static std::string line(label+"line"); + static std::string begin(label+"block"); + static std::string end(label+"endblock"); + static std::string include(label+"include"); + static std::string message(label+"msg"); + static std::string showParam(label+"show"); + static std::string dump(label+"dump"); + static std::string ifcond(label+"if"); + static std::string iftrue(label+"iftrue"), ifntrue(label+"ifntrue"); + static std::string olelse(label+"else"), olendif(label+"endif"); + static std::string getValue(label+"get"); + static std::string mathex(label+"eval"); + static std::string getRegion(label+"region"); +} + +int enclosed(const std::string &in, std::vector<std::string> &arguments, + int &end){ + // syntax: (arguments[Ø], arguments[1], ... , arguments[n]) + // arguments[i] may contain parenthesis + int pos, cursor; + arguments.resize(0); + cursor=0; + if ( (pos=in.find("(",cursor)) == std::string::npos ) + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + + if (pos>0){ + std::cout << pos << in << std::endl; + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + } + unsigned int count=1; + pos++; // skips '(' + cursor = pos; + do{ + if(in[pos]=='(') count++; + else if(in[pos]==')') count--; + else if(in[pos]==',' && (count==1)) { + arguments.push_back(removeBlanks(in.substr(cursor,pos-cursor))); + if(count!=1) + OLMsg::Fatal("Syntax error: mismatched parenthesis <%s>",in.c_str()); + cursor=pos+1; // skips ',' + } + else if(in[pos]==';') + OLMsg::Fatal("Syntax error: unterminated sentence <%s>",in.c_str()); + + pos++; + } while( count && (pos!=std::string::npos) ); + // count is 0 when the closing brace is found. + + if(count) + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + else + arguments.push_back(removeBlanks(in.substr(cursor,pos-1-cursor))); + end=pos; + return arguments.size(); +} + +int extractLogic(const std::string &in, std::vector<std::string> &arguments){ + // syntax: ( argument[0], argument[1]\in{<,>,<=,>=,==,!=}, arguments[2]) + int pos, cursor; + arguments.resize(0); + cursor=0; + if ( (pos=in.find("(",cursor)) == std::string::npos ) + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + + unsigned int count=1; + pos++; // skips '(' + cursor=pos; + do{ + if(in[pos]=='(') count++; + if(in[pos]==')') count--; + if( (in[pos]=='<') || (in[pos]=='=') || (in[pos]=='>') ){ + arguments.push_back(removeBlanks(in.substr(cursor,pos-cursor))); + if(count!=1) + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + cursor=pos; + if(in[pos+1]=='='){ + arguments.push_back(in.substr(cursor,2)); + pos++; + } + else{ + arguments.push_back(in.substr(cursor,1)); + } + cursor=pos+1; + } + pos++; + } while( count && (pos!=std::string::npos) ); + // count is 0 when the closing brace is found. + + if(count) + OLMsg::Fatal("Syntax error: mismatched parenthesis in <%s>",in.c_str()); + else + arguments.push_back(removeBlanks(in.substr(cursor,pos-1-cursor))); + + if((arguments.size()!=1) && (arguments.size()!=3)) + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + return arguments.size(); +} + +int extract(const std::string &in, std::string ¶mName, + std::string &action, std::vector<std::string> &arguments){ + // syntax: paramName.action( arg1, arg2, ... ) + int pos, cursor; + cursor=0; + if ( (pos=in.find(".",cursor)) == std::string::npos ) + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + else + paramName.assign(sanitize(in.substr(cursor,pos-cursor))); + cursor = pos+1; // skips '.' + if ( (pos=in.find("(",cursor)) == std::string::npos ) + OLMsg::Fatal("Syntax error: <%s>",in.c_str()); + else + action.assign(sanitize(in.substr(cursor,pos-cursor))); + cursor = pos; + return enclosed(in.substr(cursor),arguments,pos); +} + +bool extractRange(const std::string &in, std::vector<double> &arguments){ + // syntax: a:b:c or a:b#n + int pos, cursor; + arguments.resize(0); + cursor=0; + if ( (pos=in.find(":",cursor)) == std::string::npos ) + OLMsg::Fatal("Syntax error in range <%s>",in.c_str()); + else{ + arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str())); + } + cursor = pos+1; // skips ':' + if ( (pos=in.find(":",cursor)) != std::string::npos ){ + arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str())); + arguments.push_back(atof(in.substr(pos+1).c_str())); + } + else if ( (pos=in.find("#",cursor)) != std::string::npos ){ + arguments.push_back(atof(in.substr(cursor,pos-cursor).c_str())); + double NumStep = atof(in.substr(pos+1).c_str()); + arguments.push_back((arguments[1]-arguments[0])/((NumStep==0)?1:NumStep)); + } + else + OLMsg::Fatal("Syntax error in range <%s>",in.c_str()); + return (arguments.size()==3); +} + +std::string extractExpandPattern(const std::string& str){ + int posa,posb; + posa=str.find_first_of("\"\'<"); + posb=str.find_last_of("\"\'>"); + std::string pattern=str.substr(posa+1,posb-posa-1); + posa=pattern.find("comma"); + if(posa!=std::string::npos) + pattern.replace(posa,5,","); + if(pattern.size()!=3) + OLMsg::Fatal("Incorrect expand pattern <%s>", + str.c_str()); + return pattern; +} + +std::string localSolverClient::longName(const std::string name){ + std::set<std::string>::iterator it; + std::string fullName; + if((it = _parameters.find(name)) != _parameters.end()) + fullName.assign(OLMsg::obtainFullName(*it)); + else + fullName.assign(OLMsg::obtainFullName(name)); + //std::cout << "Full name=<" << name << "> => <" << fullName << ">" << std::endl; + return fullName; +} + +std::string localSolverClient::resolveGetVal(std::string line) { + std::vector<onelab::number> numbers; + std::vector<onelab::string> strings; + std::vector<std::string> arguments; + std::string buff; + int pos,pos0,cursor; + + cursor=0; + while ( (pos=line.find(olkey::getValue,cursor)) != std::string::npos){ + pos0=pos; // for further use + cursor = pos+olkey::getValue.length(); + int NumArg=enclosed(line.substr(cursor),arguments,pos); + if(NumArg<1) + OLMsg::Fatal("Misformed %s statement: <%s>", + olkey::getValue.c_str(),line.c_str()); + std::string paramName=longName(arguments[0]); + get(numbers,paramName); + if (numbers.size()){ + std::stringstream Num; + if(NumArg==1){ + Num << numbers[0].getValue(); + buff.assign(Num.str()); + } + else if(NumArg==2){ + std::string name, action; + std::vector<std::string> args; + extract(arguments[1],name,action,args); + if(!name.compare("choices")) { + std::vector<double> choices=numbers[0].getChoices(); + if(!action.compare("size")) { + buff.assign(ftoa(choices.size())); + } + else if(!action.compare("begin")) { + buff.assign(ftoa(*choices.begin())); + } + else if(!action.compare("rbegin")) { + buff.assign(ftoa(*choices.rbegin())); + } + else if(!action.compare("comp")) { + int i=atoi(args[0].c_str()); + if( (i>=0) && (i<choices.size()) ) + Num << choices[i]; + buff.assign(ftoa(choices[i])); + } + else if(!action.compare("expand")) { + std::string pattern; + pattern.assign(extractExpandPattern(args[0])); + OLMsg::Info("Expand parameter <%s> with pattern <%s>", + paramName.c_str(),pattern.c_str()); + buff.assign(1,pattern[0]); + for(std::vector<double>::iterator it = choices.begin(); + it != choices.end(); it++){ + if(it != choices.begin()) + buff.append(1,pattern[1]); + buff.append(ftoa(*it)); + } + buff.append(1,pattern[2]); + } + else if(!action.compare("index")) { + Num << numbers[0].getIndex(); + buff.assign(Num.str()); + } + else + OLMsg::Fatal("Unknown action <%s> in %s statement", + action.c_str(),olkey::getValue.c_str()); + } + else if(!name.compare("range")) { + double stp, min, max; + if( ((stp=numbers[0].getStep()) == 0) || + ((min=numbers[0].getMin()) ==-onelab::parameter::maxNumber()) || + ((max=numbers[0].getMax()) ==onelab::parameter::maxNumber()) ) + OLMsg::Fatal("Invalid range description for parameter <%s>", + paramName.c_str()); + if(!action.compare("size")) { + buff.assign(ftoa(fabs((max-min)/stp))); + } + else if(!action.compare("comp")) { + int i= atof(args[0].c_str()); + if(stp > 0) + Num << min+i*stp; + else if(stp < 0) + Num << max-i*stp; + } + else if(!action.compare("expand")) { + } + else + OLMsg::Fatal("Unknown action <%s> in %s statement", + action.c_str(),olkey::getValue.c_str()); + } + } + } + else{ + get(strings,longName(paramName)); + if (strings.size()) + buff.assign(strings[0].getValue()); + else + OLMsg::Fatal("resolveGetVal: unknown variable: <%s>",paramName.c_str()); + } + line.replace(pos0,cursor+pos-pos0,buff); + cursor=pos0+buff.length(); + } + + // Check now wheter the line contains OL.mathex and resolve them + cursor=0; + while ( (pos=line.find(olkey::mathex,cursor)) != std::string::npos){ + int pos0=pos; + cursor=pos+olkey::mathex.length(); + if(enclosed(line.substr(cursor),arguments,pos) != 1) + OLMsg::Fatal("Misformed %s statement: <%s>", + olkey::mathex.c_str(),line.c_str()); + //std::cout << "MathEx evaluates now <"<< arguments[0]<< "> " << std::endl; + smlib::mathex* mathExp = new smlib::mathex(); + mathExp->expression(arguments[0]); + double val=mathExp->eval(); + //std::cout << "MathEx <" << arguments[0] << "> ="<< val << std::endl; + line.replace(pos0,cursor+pos-pos0,ftoa(val)); + } + + // Check now wheter the line still contains OL. + if ( (pos=line.find(olkey::label)) != std::string::npos) + OLMsg::Fatal("Unidentified onelab command in <%s>",line.c_str()); + + return line; +} + +bool localSolverClient::resolveLogicExpr(std::vector<std::string> arguments) { + std::vector<onelab::number> numbers; + double val1, val2; + bool condition; + + val1= atof( resolveGetVal(arguments[0]).c_str() ); + if(arguments.size()==1) + return (bool)val1; + + if(arguments.size()==3){ + val2=atof( resolveGetVal(arguments[2]).c_str() ); + if(!arguments[1].compare("<")) + condition = (val1<val2); + else if (!arguments[1].compare("<=")) + condition = (val1<=val2); + else if (!arguments[1].compare(">")) + condition = (val1>val2); + else if (!arguments[1].compare(">=")) + condition = (val1>=val2); + else if (!arguments[1].compare("==")) + condition = (val1==val2); + else if (!arguments[1].compare("!=")) + condition = (val1!=val2); + } + + return condition; +} + +void localSolverClient::parse_sentence(std::string line) { + int pos,cursor,NumArg; + std::string name,action,path; + std::vector<std::string> arguments; + std::vector<onelab::number> numbers; + std::vector<onelab::string> strings; + + cursor = 0; + while ( (pos=line.find(olkey::separator,cursor)) != std::string::npos){ + std::string name, action; + extract(line.substr(cursor,pos-cursor),name,action,arguments); + + if(!action.compare("number")) { + double val; + // syntax: paramName.number(val,path,help,range(optional)) + if((arguments.size()>1) && isPath(arguments[1])) + name.assign(arguments[1] + name); + _parameters.insert(name); + OLMsg::recordFullName(name); + get(numbers, name); + if(numbers.empty()){ + numbers.resize(1); + numbers[0].setName(name); + if(arguments[0].empty()) + val=0; + else + val=atof(resolveGetVal(arguments[0]).c_str()); + numbers[0].setValue(val); + } + // parameters defined with no value are ReadOnly + // if(arguments[0].empty()) numbers[0].setReadOnly(1); + + if(arguments.size()>2) + numbers[0].setLabel(arguments[2]); + if(arguments.size()>3){ + std::vector<double> bounds; + if (extractRange(arguments[3],bounds)){ + numbers[0].setMin(bounds[0]); + numbers[0].setMax(bounds[1]); + numbers[0].setStep(bounds[2]); + } + } + set(numbers[0]); + } + else if(!action.compare("string")) { + // syntax: paramName.string(val,path,help) + if((arguments.size()>1) && isPath(arguments[1])) + name.assign(arguments[1] + name); // append path + _parameters.insert(name); + OLMsg::recordFullName(name); + get(strings, name); + if(strings.empty()){ + strings.resize(1); + strings[0].setName(name); + std::string val=resolveGetVal(arguments[0]); + strings[0].setValue(val); + } + + // parameters defined with no value are ReadOnly + // if(arguments[0].empty()) strings[0].setReadOnly(1); + + // choices list is reset + std::vector<std::string> choices; + strings[0].setChoices(choices); + + if(arguments.size()>2) strings[0].setLabel(arguments[2]); + set(strings[0]); + } + else if(!action.compare("radioButton")) { + // syntax: paramName.radioButton(val,path,label) + if(arguments[0].empty()) + OLMsg::Fatal("No value given for param <%s>",name.c_str()); + double val=atof(arguments[0].c_str()); + if((arguments.size()>1) && isPath(arguments[1])) + name.assign(arguments[1] + name); + _parameters.insert(name); + OLMsg::recordFullName(name); + get(numbers, name); + if(numbers.size()){ + val = numbers[0].getValue(); // use value from server + } + else{ + numbers.resize(1); + numbers[0].setName(name); + numbers[0].setValue(val); + } + if(arguments.size()>2) + numbers[0].setLabel(arguments[2]); + std::vector<double> choices; + choices.push_back(0); + choices.push_back(1); + numbers[0].setChoices(choices); + set(numbers[0]); + } + else if(!action.compare("range")){ + // set the range of an existing number + // syntax: paramName.range({a:b:c|a:b#n|min,max,step}) + if(arguments[0].empty()) + OLMsg::Fatal("No argument given for MinMax <%s>",name.c_str()); + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ // parameter must exist + if(arguments.size()==1){ + std::vector<double> bounds; + if (extractRange(arguments[1],bounds)){ + numbers[0].setMin(bounds[0]); + numbers[0].setMax(bounds[1]); + numbers[0].setStep(bounds[2]); + } + } + else if(arguments.size()==3){ + numbers[0].setMin(atof(arguments[0].c_str())); + numbers[0].setMax(atof(arguments[1].c_str())); + numbers[0].setStep(atof(arguments[2].c_str())); + } + else + OLMsg::Fatal("Wrong number of arguments for MinMax <%s>",name.c_str()); + } + set(numbers[0]); + } + else if(!action.compare("resetChoices")){ + name.assign(longName(name)); + get(numbers,name); + + if(numbers.size()){ // parameter must exist + std::vector<double> choices; + numbers[0].setChoices(choices); + std::map<double, std::string> valuelabels; + numbers[0].setValueLabels(valuelabels); + set(numbers[0]); + } + else{ + get(strings,name); + if(strings.size()){ + std::vector<std::string> choices; + strings[0].setChoices(choices); + set(strings[0]); + } + else{ + OLMsg::Fatal("The parameter <%s> does not exist",name.c_str()); + } + } + } + else if(!action.compare("addChoices")){ + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ // parameter must exist + std::vector<double> choices=numbers[0].getChoices(); + for(unsigned int i = 0; i < arguments.size(); i++){ + double val=atof(resolveGetVal(arguments[i]).c_str()); + //if(std::find(choices.begin(),choices.end(),val)==choices.end()) + choices.push_back(val); + } + numbers[0].setChoices(choices); + set(numbers[0]); + } + else{ + get(strings,name); + if(strings.size()){ + std::vector<std::string> choices=strings[0].getChoices(); + for(unsigned int i = 0; i < arguments.size(); i++) + if(std::find(choices.begin(),choices.end(), + arguments[i])==choices.end()) + choices.push_back(arguments[i]); + strings[0].setChoices(choices); + set(strings[0]); + } + else{ + OLMsg::Fatal("The parameter <%s> does not exist",name.c_str()); + } + } + } + else if(!action.compare("valueLabels")){ + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ // parameter must exist + if(arguments.size() % 2) + OLMsg::Fatal("Nb of labels does not match nb of choices for <%s>", + name.c_str()); + std::vector<double> choices=numbers[0].getChoices(); + for(unsigned int i = 0; i < arguments.size(); i=i+2){ + double val=atof(resolveGetVal(arguments[i]).c_str()); + if(std::find(choices.begin(),choices.end(),val)==choices.end()) + choices.push_back(val); + numbers[0].setValueLabel(val,arguments[i+1]); + } + numbers[0].setChoices(choices); + set(numbers[0]); + } + else + OLMsg::Fatal("The number <%s> does not exist",name.c_str()); + } + else if(!action.compare("setValue")){ // force change on server + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ + if(arguments[0].empty()) + numbers[0].setValue(0); + else + numbers[0].setValue(atof(resolveGetVal(arguments[0]).c_str())); + numbers[0].setReadOnly(1); + set(numbers[0]); + } + else{ + get(strings,name); + if(strings.size()){ + if(arguments[0].empty()) + strings[0].setValue(""); + else + strings[0].setValue(arguments[0]); + set(strings[0]); + } + else{ + OLMsg::Fatal("The parameter <%s> does not exist",name.c_str()); + } + } + } + else if(!action.compare("setVisible")){ + if(arguments[0].empty()) + OLMsg::Fatal("Missing argument SetVisible <%s>",name.c_str()); + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ + numbers[0].setVisible(atof(resolveGetVal(arguments[0]).c_str())); + set(numbers[0]); + } + else{ + get(strings,name); + if(strings.size()){ + strings[0].setVisible(atof(resolveGetVal(arguments[0]).c_str())); + set(strings[0]); + } + else{ + OLMsg::Fatal("The parameter <%s> does not exist",name.c_str()); + } + } + } + else if(!action.compare("setReadOnly")){ + if(arguments[0].empty()) + OLMsg::Fatal("Missing argument SetReadOnly <%s>",name.c_str()); + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ + numbers[0].setReadOnly(atof(resolveGetVal(arguments[0]).c_str())); + set(numbers[0]); + } + else{ + get(strings,name); + if(strings.size()){ + strings[0].setReadOnly(atof(resolveGetVal(arguments[0]).c_str())); + set(strings[0]); + } + else{ + OLMsg::Fatal("The parameter <%s> does not exist",name.c_str()); + } + } + } + else if(!action.compare("layout")){ + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ + numbers[0].setReadOnly(0); + numbers[0].setAttribute("Highlight","Ivory"); + set(numbers[0]); + } + else{ + get(strings,name); + if(strings.size()){ + strings[0].setReadOnly(0); + strings[0].setAttribute("Highlight","Ivory"); + set(strings[0]); + } + else{ + OLMsg::Fatal("The parameter <%s> does not exist",name.c_str()); + } + } + } + else if(!action.compare("setAttribute")){ + if(arguments.size() !=2 ) + OLMsg::Fatal("SetAttribute <%s> needs two arguments %d", + name.c_str(), arguments.size()); + name.assign(longName(name)); + get(numbers,name); + if(numbers.size()){ + numbers[0].setAttribute(arguments[0].c_str(), + resolveGetVal(arguments[1]).c_str()); + set(numbers[0]); + } + else{ + get(strings,name); + if(strings.size()){ + strings[0].setAttribute(arguments[0].c_str(),arguments[1].c_str()); + set(strings[0]); + } + else{ + OLMsg::Fatal("The parameter <%s> does not exist",name.c_str()); + } + } + } + else{ + client_sentence(name,action,arguments); + } + cursor=pos+1; + } +} + +void localSolverClient::modify_tags(const std::string lab, const std::string com){ + bool changed=false; + if(lab.compare(olkey::label) && lab.size()){ + changed=true; + olkey::label.assign(lab); + olkey::line.assign(olkey::label+"line"); + olkey::begin.assign(olkey::label+"block"); + olkey::end.assign(olkey::label+"endblock"); + olkey::include.assign(olkey::label+"include"); + olkey::message.assign(olkey::label+"msg"); + olkey::showParam.assign(olkey::label+"show"); + olkey::dump.assign(olkey::label+"dump"); + olkey::ifcond.assign(olkey::label+"if"); + olkey::iftrue.assign(olkey::label+"iftrue"); + olkey::ifntrue.assign(olkey::label+"ifntrue"); + olkey::olelse.assign(olkey::label+"else"); + olkey::olendif.assign(olkey::label+"endif"); + olkey::getValue.assign(olkey::label+"get"); + olkey::mathex.assign(olkey::label+"eval"); + olkey::getRegion.assign(olkey::label+"region"); + } + if(com.compare(olkey::comment) && com.size()){ + changed=true; + olkey::comment.assign(com); + } + + if(changed) + OLMsg::Info("Using now onelab tags <%s,%s>", + olkey::label.c_str(), olkey::comment.c_str()); +} + +void localSolverClient::parse_oneline(std::string line, std::ifstream &infile) { + int pos,cursor; + std::vector<std::string> arguments; + std::vector<onelab::number> numbers; + std::vector<onelab::string> strings; + + if((pos=line.find_first_not_of(" \t"))==std::string::npos){ + // empty line, skip + } + else if(!line.compare(pos,olkey::comment.size(),olkey::comment)){ + // commented out line, skip + } + else if ( (pos=line.find(olkey::deflabel)) != std::string::npos){ + // onelab.tags(label,comment); + // onelab.tags(); -> reset to default + cursor = pos+olkey::deflabel.length(); + int NumArg=enclosed(line.substr(cursor),arguments,pos); + if((NumArg==1) && arguments[0].empty()) + modify_tags("",""); + else if(NumArg==2) + modify_tags(arguments[0],arguments[1]); + else + OLMsg::Fatal("Misformed <%s> statement", olkey::deflabel.c_str()); + } + else if( (pos=line.find(olkey::begin)) != std::string::npos) { + // onelab.begin + if (!parse_block(infile)) + OLMsg::Fatal("Misformed <%s> block <%s>", + olkey::begin.c_str(),olkey::end.c_str()); + } + else if ( (pos=line.find(olkey::iftrue)) != std::string::npos) { + // onelab.iftrue + cursor = pos+olkey::iftrue.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::iftrue.c_str(),line.c_str()); + bool condition = false; + get(strings,longName(arguments[0])); + if (strings.size()) + condition= true; + else{ + get(numbers,longName(arguments[0])); + if (numbers.size()) + condition = (bool) numbers[0].getValue(); + else + OLMsg::Fatal("Unknown parameter <%s> in <%s> statement", + arguments[0].c_str(),olkey::iftrue.c_str()); + } + if (!parse_ifstatement(infile,condition)) + OLMsg::Fatal("Misformed <%s> statement: <%s>", + olkey::iftrue.c_str(),arguments[0].c_str()); + } + else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) { + // onelab.ifntrue + cursor = pos+olkey::ifntrue.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::ifntrue.c_str(),line.c_str()); + bool condition = false; + get(strings,longName(arguments[0])); + if (strings.size()) + condition= true; + else{ + get(numbers,longName(arguments[0])); + if (numbers.size()) + condition = (bool) numbers[0].getValue(); + else + OLMsg::Fatal("Unknown parameter <%s> in <%s> statement", + arguments[0].c_str(),olkey::ifntrue.c_str()); + } + std::cout << "cond=" << condition << std::endl; + if (!parse_ifstatement(infile,!condition)) + OLMsg::Fatal("Misformed <%s> statement: <%s>", + olkey::ifntrue.c_str(),arguments[0].c_str()); + } + else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) { + // onelab.ifcond + cursor = pos+olkey::ifcond.length(); + int NumArgs=extractLogic(line.substr(cursor),arguments); + bool condition= resolveLogicExpr(arguments); + if (!parse_ifstatement(infile,condition)){ + OLMsg::Fatal("Misformed %s statement: <%s>", + olkey::ifcond.c_str(), line.c_str()); + } + } + else if ( (pos=line.find(olkey::include)) != std::string::npos) { + // onelab.include + cursor = pos+olkey::include.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::include.c_str(),line.c_str()); + parse_onefile(arguments[0]); + } + else if ( (pos=line.find(olkey::message)) != std::string::npos) { + // onelab.message + cursor = pos+olkey::message.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::message.c_str(),line.c_str()); + std::string msg = resolveGetVal(arguments[0]); + OLMsg::Info("%s",msg.c_str()); + } + else if ( (pos=line.find(olkey::showParam)) != std::string::npos) { + // onelab.showParam + cursor = pos+olkey::showParam.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::showParam.c_str(),line.c_str()); + std::string lname=longName(arguments[0]); + std::string msg; + get(numbers,lname); + if (numbers.size()) + msg.assign(numbers[0].toChar()); + else{ + get(strings,lname); + if (strings.size()) + msg.assign(strings[0].toChar()); + else + OLMsg::Fatal("Unknown parameter <%s> in <%s> statement", + arguments[0].c_str(),olkey::showParam.c_str()); + } + for(unsigned int i = 0; i < msg.size(); i++) + if(msg[i] == onelab::parameter::charSep()) msg[i] = '|'; + OLMsg::Info("%s",msg.c_str()); + } + else if ( (pos=line.find(olkey::dump)) != std::string::npos) { + // onelab.dump + cursor = pos+olkey::dump.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::dump.c_str(),line.c_str()); + onelab::server::instance()->toFile(resolveGetVal(arguments[0])); + } + else if( isOnelabBlock() || + ( !isOnelabBlock() && + ((pos=line.find(olkey::line)) != std::string::npos)) ){ + // either any other line within a onelabBlock or a line + // introduced by a "onelab.line" tag not within a onelabBlock + std::string cmds="",cmd; + int posa, posb, NbLines=1; + do{ + if( (pos=line.find(olkey::line)) != std::string::npos) + posa=pos + olkey::line.size(); + else + posa=0; // skip tag 'olkey::line' if any + + posb=line.find(olkey::comment); // skip trailing comments if any + if(posb==std::string::npos) + cmd.assign(line.substr(posa)); + else + cmd.assign(line.substr(posa,posb-posa)); + cmds.append(cmd); + + //std::cout << "cmds=<" << cmds << ">" << std::endl; + + // check whether "cmd" ends now with "olkey::separator" + posb=cmd.find_last_not_of(" \t")-olkey::separator.length()+1; + if(posb<0) posb=0; + if(cmd.compare(posb,olkey::separator.length(),olkey::separator)){ + // append the next line + getline (infile,line); + if((pos=line.find_first_not_of(" \t"))==std::string::npos){ + OLMsg::Fatal("Empty line not allowed within a command <%s>", + cmds.c_str()); + } + else if(!line.compare(pos,olkey::comment.size(),olkey::comment)){ + OLMsg::Fatal("Comment lines not allowed within a command <%s>", + cmds.c_str()); + } + NbLines++; // command should not span over more than 10 lines + } + else + break; + } while (infile.good() && NbLines<=10); + if(NbLines>=10) + OLMsg::Fatal("Command <%s> should not span over more than 10 lines", + cmds.c_str()); + parse_sentence(cmds); + } + else if ( (pos=line.find(olkey::getValue)) != std::string::npos) { + // onelab.getValue: nothing to do + } + else if ( (pos=line.find(olkey::mathex)) != std::string::npos) { + // onelab.mathex: nothing to do + } + else if ( (pos=line.find(olkey::getRegion)) != std::string::npos) { + // onelab.getRegion: nothing to do + } + else if( (pos=line.find(olkey::label)) != std::string::npos) { + OLMsg::Fatal("Unknown ONELAB keyword in <%s>",line.c_str()); + } + else{ + // not a onelab line, skip + } +} + +bool localSolverClient::parse_block(std::ifstream &infile) { + int pos; + std::string line; + openOnelabBlock(); + while (infile.good()){ + getline (infile,line); + if ((pos=line.find(olkey::end)) != std::string::npos){ + closeOnelabBlock(); + return true; + } + parse_oneline(line,infile); + } + return false; +} + +bool localSolverClient::parse_ifstatement(std::ifstream &infile, + bool condition) { + int level, pos; + std::string line; + + bool trueclause=true; + level=1; + while ( infile.good() && level) { + getline (infile,line); + if ( ((pos=line.find(olkey::olelse)) != std::string::npos) && (level==1) ) + trueclause=false; + else if ( (pos=line.find(olkey::olendif)) != std::string::npos) + level--; + else if ( !(trueclause ^ condition) ) // xor bitwise operator + parse_oneline(line,infile); + else { // check for opening if statements + if ( (pos=line.find(olkey::iftrue)) != std::string::npos) + level++; + else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) + level++; + else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) + level++; + } + } + return level?false:true ; +} + +void localSolverClient::parse_onefile(std::string fileName, bool mandatory) { + int pos; + std::string fullName=getWorkingDir()+fileName; + std::ifstream infile(fullName.c_str()); + if (infile.is_open()){ + OLMsg::Info("Parse file <%s>",fullName.c_str()); + while (infile.good()){ + std::string line; + getline(infile,line); + parse_oneline(line,infile); + } + infile.close(); + } + else + if(mandatory) + OLMsg::Fatal("The file <%s> does not exist",fullName.c_str()); + else + OLMsg::Info("The file <%s> does not exist",fullName.c_str()); +} + +bool localSolverClient::convert_ifstatement(std::ifstream &infile, std::ofstream &outfile, bool condition) { + int level, pos; + std::string line; + + bool trueclause=true; + level=1; + while ( infile.good() && level) { + getline (infile,line); + if ( ((pos=line.find(olkey::olelse)) != std::string::npos) && (level==1) ) + trueclause=false; + else if ( (pos=line.find(olkey::olendif)) != std::string::npos) + level--; + else if ( !(trueclause ^ condition) ) // xor bitwise operator + convert_oneline(line,infile,outfile); + else { // check for opening if statements + if ( (pos=line.find(olkey::iftrue)) != std::string::npos) + level++; + else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) + level++; + else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) + level++; + } + } + return level?false:true ; +} + +void localSolverClient::convert_oneline(std::string line, std::ifstream &infile, std::ofstream &outfile) { + int pos,cursor; + std::vector<std::string> arguments; + std::vector<onelab::number> numbers; + std::vector<onelab::string> strings; + std::vector<onelab::region> regions; + + if((pos=line.find_first_not_of(" \t"))==std::string::npos){ + // empty line, we keep them + outfile << line << std::endl; + } + else if(!line.compare(pos,olkey::comment.size(),olkey::comment)){ + // commented out, skip the line + } + else if ( (pos=line.find(olkey::deflabel)) != std::string::npos){ + // onelab.tags(label,comment,separator) + cursor = pos+olkey::deflabel.length(); + int NumArg=enclosed(line.substr(cursor),arguments,pos); + if(NumArg==0) + modify_tags("",""); + else if(NumArg==2) + modify_tags(arguments[0],arguments[1]); + else + OLMsg::Fatal("Misformed <%s> statement", olkey::deflabel.c_str()); + } + else if( (pos=line.find(olkey::begin)) != std::string::npos) { + // onelab.begin + while (infile.good()){ + getline (infile,line); + if( (pos=line.find(olkey::end)) != std::string::npos) return; + } + OLMsg::Fatal("Misformed <%s> block <%s>", + olkey::begin.c_str(),olkey::end.c_str()); + } + else if ( (pos=line.find(olkey::iftrue)) != std::string::npos) { + // onelab.iftrue + cursor = pos+olkey::iftrue.length(); + // pos=line.find_first_of(')',cursor)+1; + // if(enclosed(line.substr(cursor,pos-cursor),arguments)<1) + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::iftrue.c_str(),line.c_str()); + bool condition = false; + get(strings,longName(arguments[0])); + if (strings.size()) + condition= true; + else{ + get(numbers,longName(arguments[0])); + if (numbers.size()) + condition = (bool) numbers[0].getValue(); + else + OLMsg::Fatal("Unknown parameter <%s> in <%s> statement", + arguments[0].c_str(),olkey::iftrue.c_str()); + } + if (!convert_ifstatement(infile,outfile,condition)) + OLMsg::Fatal("Misformed <%s> statement: %s", + olkey::iftrue.c_str(),arguments[0].c_str()); + } + else if ( (pos=line.find(olkey::ifntrue)) != std::string::npos) { + // onelab.ifntrue + cursor = pos+olkey::ifntrue.length(); + // pos=line.find_first_of(')',cursor)+1; + // if(enclosed(line.substr(cursor,pos-cursor),arguments)<1) + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::ifntrue.c_str(),line.c_str()); + bool condition = false; + get(strings,longName(arguments[0])); + if (strings.size()) + condition= true; + else{ + get(numbers,longName(arguments[0])); + if (numbers.size()) + condition = (bool) numbers[0].getValue(); + else + OLMsg::Fatal("Unknown parameter <%s> in <%s> statement", + arguments[0].c_str(),olkey::ifntrue.c_str()); + } + if (!convert_ifstatement(infile,outfile,!condition)) + OLMsg::Fatal("Misformed <%s> statement: %s", + olkey::ifntrue.c_str(),arguments[0].c_str()); + } + else if ( (pos=line.find(olkey::ifcond)) != std::string::npos) { + // onelab.ifcond + cursor = pos+olkey::ifcond.length(); + int NumArgs=extractLogic(line.substr(cursor),arguments); + bool condition= resolveLogicExpr(arguments); + if (!convert_ifstatement(infile,outfile,condition)) + OLMsg::Fatal("Misformed %s statement: <%s>", line.c_str()); + } + else if ( (pos=line.find(olkey::include)) != std::string::npos) { + // onelab.include + cursor = pos+olkey::include.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::include.c_str(),line.c_str()); + convert_onefile(arguments[0],outfile); + } + else if ( (pos=line.find(olkey::message)) != std::string::npos) { + // onelab.message + cursor = pos+olkey::message.length(); + if(enclosed(line.substr(cursor),arguments,pos)<1) + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::message.c_str(),line.c_str()); + std::string msg = resolveGetVal(arguments[0]); + OLMsg::Info("%s",msg.c_str()); + } + else if ( (pos=line.find(olkey::getValue)) != std::string::npos) { + outfile << resolveGetVal(line) << std::endl; + } + else if ( (pos=line.find(olkey::getRegion)) != std::string::npos) { + // onelab.getRegion, possibly several times on the line + cursor=0; + std::string buff,action; + while ( (pos=line.find(olkey::getRegion,cursor)) != std::string::npos){ + int pos0=pos; + cursor = pos+olkey::getRegion.length(); + int NumArg=enclosed(line.substr(cursor),arguments,pos); + + if(NumArg>0){ + std::string paramName; + paramName.assign("Gmsh/Physical groups/"+arguments[0]); + get(regions,paramName); + if (regions.size()){ + std::set<std::string> region; + region=regions[0].getValue(); + + if(NumArg>1) + action.assign(arguments[1]); + else + action.assign("expand"); + + if(!action.compare("size")) + buff.assign(ftoa(region.size())); + else if(!action.compare("expand")){ + std::string pattern; + if(NumArg>=3) + pattern.assign(extractExpandPattern(arguments[2])); + else + pattern.assign(" "); + + buff.assign(1,pattern[0]); + for(std::set<std::string>::const_iterator it = region.begin(); + it != region.end(); it++){ + if(it != region.begin()) + buff.append(1,pattern[1]); + buff.append((*it)); + } + buff.append(1,pattern[2]); + } + else + OLMsg::Fatal("Unknown %s action: <%s>", + olkey::getRegion.c_str(), arguments[1].c_str()); + } + else + OLMsg::Fatal("Unknown region: <%s>",paramName.c_str()); + } + else + OLMsg::Fatal("Misformed <%s> statement: (%s)", + olkey::getRegion.c_str(),line.c_str()); + line.replace(pos0,cursor+pos-pos0,buff); + cursor=pos0+buff.length(); + } + outfile << line << std::endl; + } + else if ( (pos=line.find(olkey::label)) != std::string::npos){ + OLMsg::Fatal("Unidentified onelab command in <%s>",line.c_str()); + } + else{ + outfile << line << std::endl; + } +} + +void localSolverClient::convert_onefile(std::string fileName, std::ofstream &outfile) { + int pos; + std::string fullName=getWorkingDir()+fileName; + std::ifstream infile(fullName.c_str()); + if (infile.is_open()){ + OLMsg::Info("Convert file <%s>",fullName.c_str()); + while ( infile.good() ) { + std::string line; + getline (infile,line); + convert_oneline(line,infile,outfile); + } + infile.close(); + } + else + OLMsg::Fatal("The file %s cannot be opened",fullName.c_str()); +} + +void localSolverClient::client_sentence(const std::string &name, + const std::string &action, + const std::vector<std::string> &arguments) { + OLMsg::Fatal("The action <%s> is unknown in this context",action.c_str()); +} + +void MetaModel::client_sentence(const std::string &name, + const std::string &action, + const std::vector<std::string> &arguments){ + std::vector<onelab::string> strings; + + if(!action.compare("register")){ + if(isTodo(REGISTER)){ + // syntax name.register([interf...|encaps...]{,cmdl{host{,rdir}}}}) ; + if(!findClientByName(name)){ + OLMsg::Info("Define client <%s>", name.c_str()); + std::string cmdl="",host="",rdir=""; + if(arguments.size()>=2) cmdl.assign(resolveGetVal(arguments[1])); + if(arguments.size()>=3) host.assign(resolveGetVal(arguments[2])); + if(arguments.size()>=4) rdir.assign(resolveGetVal(arguments[3])); + if(arguments.size()>=5) + OLMsg::Warning("Unused arguments for client <%s>", name.c_str()); + + if(cmdl.empty()) { + // if argument 'cmdl' is empty, look for one on the server + // (read beforehand from the file metamodel.ol.save) + // otherwise register with empty cmdl + // (this situation is dealt with later on) + cmdl=OLMsg::GetOnelabString(name + "/CommandLine"); + if(cmdl.empty()) { + onelab::string str; + str.setName(name + "/CommandLine"); + str.setKind("file"); + str.setVisible(cmdl.empty()); + str.setAttribute("Highlight","Ivory"); + set(str); + } + } + registerClient(name,resolveGetVal(arguments[0]),cmdl,host,rdir); + } + else + OLMsg::Error("Redefinition of client <%s>", name.c_str()); + } + } + else if(!action.compare("commandLine")){ + if(isTodo(REGISTER)){ + if(arguments[0].size()){ + OLMsg::SetOnelabString(name + "/CommandLine",arguments[0],false); + // get(strings, name); + // if(strings.empty()){ + // strings.resize(1); + // strings[0].setName(name + "/CommandLine"); + // strings[0].setValue(arguments[0]); + // strings[0].setKind("file"); + // strings[0].setVisible(false); + // set(strings[0]); + // } + } + else + OLMsg::Error("No pathname given for client <%s>", name.c_str()); + } + } + else if(!action.compare("workingDir")){ + localSolverClient *c; + if(c=findClientByName(name)) + c->setWorkingDir(c->getWorkingDir()+arguments[0]); + else + OLMsg::Fatal("Unknown client <%s>", name.c_str()); + } + else if(!action.compare("active")){ + localSolverClient *c; + if(arguments[0].size()){ + if(c=findClientByName(name)) + c->setActive(atof( resolveGetVal(arguments[0]).c_str() )); + else + OLMsg::Fatal("Unknown client <%s>", name.c_str()); + } + else + OLMsg::Error("No argument for <%s.Active> statement", name.c_str()); + } + else if(!action.compare("in")){ + if(isTodo(REGISTER)){ + get(strings, name + "/InputFiles"); + if(strings.empty()){ + strings.resize(1); + strings[0].setName(name + "/InputFiles"); + } + strings[0].setKind("file"); + strings[0].setVisible(false); + std::vector<std::string> choices; + if(arguments[0].size()){ + for(unsigned int i = 0; i < arguments.size(); i++){ + std::string fileName=resolveGetVal(arguments[i]); + if(std::find(choices.begin(),choices.end(),fileName)==choices.end()) + choices.push_back(fileName); + } + strings[0].setValue(resolveGetVal(arguments[0])); + } + strings[0].setChoices(choices); + set(strings[0]); + } + } + else if(!action.compare("out")){ + if(isTodo(REGISTER)){ + get(strings, name + "/OutputFiles"); + if(strings.empty()){ + strings.resize(1); + strings[0].setName(name + "/OutputFiles"); + } + strings[0].setKind("file"); + strings[0].setVisible(false); + std::vector<std::string> choices; + if(arguments[0].size()){ + for(unsigned int i = 0; i < arguments.size(); i++){ + std::string fileName=resolveGetVal(arguments[i]); + if(std::find(choices.begin(),choices.end(),fileName)==choices.end()) + choices.push_back(fileName); + } + strings[0].setValue(resolveGetVal(arguments[0])); + } + strings[0].setChoices(choices); + set(strings[0]); + } + } + else if(!action.compare("run")){ + if(isTodo(REGISTER)){ + if(arguments[0].size()){ + get(strings, name + "/Arguments"); + if(strings.empty()){ + strings.resize(1); + strings[0].setName(name + "/Arguments"); + } + strings[0].setValue(resolveGetVal(arguments[0])); + strings[0].setVisible(false); + set(strings[0]); + } + } + else if(isTodo(ANALYZE)){ + localSolverClient *c; + if(c=findClientByName(name)) c->analyze(); + } + else if(isTodo(COMPUTE)){ + localSolverClient *c; + if(c=findClientByName(name)){ + c->analyze(); + c->compute(); + } + } + } + else if(!action.compare("check")){ + localSolverClient *c; + if(c=findClientByName(name)){ + c->checkCommandLine(); + c->analyze(); + } + else + OLMsg::Fatal("Unknown client <%s>", name.c_str()); + } + else if(!action.compare("up")){ + if(arguments.size()%4==0){ + if(isTodo(REGISTER)){ + // predefine the parameters to upload + for(unsigned int i = 0; i < arguments.size(); i++){ + if(i%4==3){ + std::string str=resolveGetVal(arguments[i]); + OLMsg::recordFullName(str); + std::vector<onelab::number> numbers; + get(numbers, str); + if(numbers.empty()){ + numbers.resize(1); + numbers[0].setName(str); + numbers[0].setValue(0); + set(numbers[0]); + } + } + } + } + else if(isTodo(COMPUTE)){ + std::vector<std::string> choices; + for(unsigned int i = 0; i < arguments.size(); i++){ + std::string str=resolveGetVal(arguments[i]); + OLMsg::recordFullName(str); + choices.push_back(str); + } + localSolverClient *c; + if(c=findClientByName(name)) c->PostArray(choices); + } + } + else + OLMsg::Fatal("Wrong number of arguments <%d> for <%s>", + arguments.size(), action.c_str()); + } + else if(!action.compare("merge")){ + if(isTodo(COMPUTE)){ + std::vector<std::string> choices; + for(unsigned int i = 0; i < arguments.size(); i++){ + choices.push_back(resolveGetVal(arguments[i])); + } + localSolverClient *c; + if(c=findClientByName(name)) c->GmshMerge(choices); + } + } + else + OLMsg::Fatal("Unknown action <%s>",action.c_str()); +} diff --git a/contrib/onelab/loader.cpp b/contrib/onelab/loader.cpp new file mode 100644 index 0000000000..5b37b49c23 --- /dev/null +++ b/contrib/onelab/loader.cpp @@ -0,0 +1,264 @@ +#include "StringUtils.h" +#include "onelabUtils.h" +#include "OnelabClients.h" + +onelab::server *onelab::server::_server = 0; + +std::string clientName; + +std::string stateToChar(){ + std::vector<onelab::number> numbers; + std::ostringstream sstream; + onelab::server::instance()->get(numbers); + for(std::vector<onelab::number>::iterator it = numbers.begin(); + it != numbers.end(); it++) + sstream << (*it).getValue() << '\t'; + return sstream.str(); +} + +std::string showParamSpace(){ + std::vector<std::string> parameters=onelab::server::instance()->toChar(); + std::string db = "ONELAB parameter space: size=" + + itoa(onelab::server::instance()->getNumParameters()) + "\n"; + for(unsigned int i = 0; i < parameters.size(); i++) + db.append(parameters[i] + '\n'); + for(unsigned int i = 0; i < db.size(); i++) + if(db[i] == onelab::parameter::charSep()) db[i] = ' '; + return db.c_str(); +} + +std::string showClientStatus(){ + std::ostringstream sstream; + std::string name; + std::cout << "\nONELAB: Present state of the onelab clients" << std::endl; + for(onelab::server::citer it = onelab::server::instance()->firstClient(); + it != onelab::server::instance()->lastClient(); it++){ + name.assign(it->first); + sstream << "<" << onelab::server::instance()->getChanged(name) << "> " + << name << std::endl; + } + return sstream.str(); +} + +void initializeLoop(const std::string &level) +{ + bool changed = false; + std::vector<onelab::number> numbers; + onelab::server::instance()->get(numbers); + for(unsigned int i = 0; i < numbers.size(); i++){ + + if(numbers[i].getAttribute("Loop") == level){ + if(numbers[i].getChoices().size() > 1){ + numbers[i].setIndex(0); + numbers[i].setValue(numbers[i].getChoices()[0]); + onelab::server::instance()->set(numbers[i]); + changed = true; + } + else if(numbers[i].getStep() > 0){ + if(numbers[i].getMin() != -onelab::parameter::maxNumber()){ + numbers[i].setValue(numbers[i].getMin()); + onelab::server::instance()->set(numbers[i]); + changed = true; + } + } + else if(numbers[i].getStep() < 0){ + if(numbers[i].getMax() != onelab::parameter::maxNumber()){ + numbers[i].setValue(numbers[i].getMax()); + onelab::server::instance()->set(numbers[i]); + changed = true; + } + } + } + } + + // force this to make sure that we remesh, even if a mesh exists and + // we did not actually change a Gmsh parameter + if(changed) + onelab::server::instance()->setChanged(true, "Gmsh"); +} + +bool incrementLoop(const std::string &level) +{ + bool recompute = false, loop = false; + std::vector<onelab::number> numbers; + onelab::server::instance()->get(numbers); + for(unsigned int i = 0; i < numbers.size(); i++){ + if(numbers[i].getAttribute("Loop") == level){ + loop = true; + + if(numbers[i].getChoices().size() > 1){ + int j = numbers[i].getIndex() + 1; + if((j >= 0) && (j < (int)numbers[i].getChoices().size())){ + numbers[i].setValue(numbers[i].getChoices()[j]); + numbers[i].setIndex(j); + onelab::server::instance()->set(numbers[i]); + OLMsg::Info("Recomputing with %dth choice %s=%g", j, + numbers[i].getName().c_str(), numbers[i].getValue()); + recompute = true; + } + } + else if(numbers[i].getStep() > 0){ + if(numbers[i].getMax() != onelab::parameter::maxNumber() && + numbers[i].getValue() < numbers[i].getMax()){ + numbers[i].setValue(numbers[i].getValue() + numbers[i].getStep()); + onelab::server::instance()->set(numbers[i]); + OLMsg::Info("Recomputing with new step %s=%g", + numbers[i].getName().c_str(), numbers[i].getValue()); + recompute = true; + } + } + else if(numbers[i].getStep() < 0){ + if(numbers[i].getMin() != -onelab::parameter::maxNumber() && + numbers[i].getValue() > numbers[i].getMin()){ + numbers[i].setValue(numbers[i].getValue() + numbers[i].getStep()); + onelab::server::instance()->set(numbers[i]); + OLMsg::Info("Recomputing with new step %s=%g", + numbers[i].getName().c_str(), numbers[i].getValue()); + recompute = true; + } + } + } + } + + if(loop && !recompute) // end of this loop level + initializeLoop(level); + + return recompute; +} + +void initializeLoops() +{ + initializeLoop("1"); + initializeLoop("2"); + initializeLoop("3"); +} + +bool incrementLoops() +{ + bool ret = false; + if(incrementLoop("3")) ret = true; + else if(incrementLoop("2")) ret = true; + else if(incrementLoop("1")) ret = true; + return ret; +} + +bool menu() { + int choice, counter1=0, counter2=0; + std::vector<onelab::number> numbers; + std::vector<onelab::string> strings; + + do { + std::cout << "\nONELAB: menu" << std::endl ; + std::cout << " 1- View parameter space\n 2- Client status\n 3- Set value\n 4- Analyze\n 5- Compute\n 6- Loop\n 7- Quit metamodel" << std::endl; + choice=0; + std::string mystr; + while( (choice<1 || choice>7) && ++counter1<10 ) { + std::cout << "\nONELAB: your choice? "; + std::getline (std::cin, mystr); + std::stringstream myStream(mystr); + if (myStream >> choice) break; + std::cout << "Invalid choice" << std::endl; + } + std::cout << "Your choice is <" << choice << ">" << std::endl; + + if (choice==1){ + std::cout << showParamSpace(); + choice=0; + } + if (choice==2){ + std::cout << showClientStatus(); + choice=0; + } + else if (choice==3){ + std::string name; + std::cout << "ONELAB: Variable name? "; std::cin >> name; + onelab::server::instance()->get(numbers,name); + if (numbers.size()) { + float fval; + std::cout << "ONELAB: Value? "; std::cin >> fval; + numbers[0].setValue(fval); + bool allowed = onelab::server::instance()->set(numbers[0]); + } + else{ + onelab::server::instance()->get(strings,name); + if (strings.size()) { + std::string sval; + std::cout << "ONELAB: Value? "; std::cin >> sval; + strings[0].setValue(sval); + onelab::server::instance()->set(strings[0]); + } + else + std::cout << "ONELAB: The variable " << name + << " is not defined" << std::endl; + } + choice=0; + } + else if (choice==4){ + metamodel(ANALYZE); + choice=0; + } + else if (choice==5){ + metamodel(COMPUTE); + choice=0; + } + else if (choice==6){ + initializeLoops(); + do{ + metamodel(COMPUTE); + }while(incrementLoops()); + choice=0; + } + else if (choice==7) + exit(1); + else + choice=0; + } while(!choice && ++counter2<20); +} + +void PrintUsage(const char *name){ + printf("\nUsage: %s [-a -i] modelName\n", name); + exit(1); +} + +int main(int argc, char *argv[]){ + bool launchMenu=false; + parseMode todo=COMPUTE; + int i = 1; + + clientName.assign("meta"); + OLMsg::loader = new onelab::remoteNetworkClient(clientName, ""); + // OLMsg::_onelabclient is a onelab:LocalClient independent of MetaModel + OLMsg::InitializeOnelab("onelab",""); + + + while(i < argc) { + if(argv[i][0] == '-') { + if(!strcmp(argv[i] + 1, "a")) { + i++; + todo=ANALYZE; + } + else if(!strcmp(argv[i] + 1, "i")) { + i++; + launchMenu=true; + } + } + else { + std::string caseName=argv[i]; + if(caseName.size()){ + modelName.assign(SplitFileName(caseName)[1]); + workingDir.assign(SplitFileName(caseName)[0]); + } + else + OLMsg::Fatal("No valid input model name."); + i++; + } + } + + if(launchMenu) + menu(); + else + metamodel(todo); + + OLMsg::FinalizeOnelab(); +} + diff --git a/contrib/onelab/metamodel.cpp b/contrib/onelab/metamodel.cpp new file mode 100644 index 0000000000..818d31fa4a --- /dev/null +++ b/contrib/onelab/metamodel.cpp @@ -0,0 +1,56 @@ +#include "OnelabClients.h" +#include "metamodel.h" + +void initializeMetamodel(onelab::client *client) +{ + OLMsg::SetOnelabClient(client); +} + +int metamodel(const std::string &action){ + + parseMode todo; + if(action == "check"){ + todo = ANALYZE; + } + else if(action == "compute"){ + todo = COMPUTE; + } + else{ + todo = STOP; + } + + std::string modelName = OLMsg::GetOnelabString("Arguments/FileName"); + std::string workingDir = OLMsg::GetOnelabString("Arguments/WorkingDir"); + std::string clientName = "meta"; + + MetaModel *myModel = + new MetaModel(clientName, workingDir, clientName, modelName); + myModel->setTodo(todo); + + if(OLMsg::GetOnelabNumber("LOGFILES")){ + freopen("stdout.txt","w",stdout); + freopen("stderr.txt","w",stderr); + } + + //if not all clients have valid commandlines -> exit metamodel + if(!myModel->checkCommandLines()) + myModel->setTodo(EXIT); + + if( myModel->isTodo(EXIT)){ + // exit metamodel + } + else if( myModel->isTodo(INITIALIZE)){ + myModel->initialize(); + } + else if( myModel->isTodo(ANALYZE)){ + myModel->analyze(); + } + else if( myModel->isTodo(COMPUTE)){ + myModel->compute(); + } + else + OLMsg::Fatal("Main: Unknown Action <%d>", todo); + + delete myModel; + OLMsg::Info("Leave metamodel"); +} diff --git a/contrib/onelab/metamodel.h b/contrib/onelab/metamodel.h new file mode 100644 index 0000000000..72104246b2 --- /dev/null +++ b/contrib/onelab/metamodel.h @@ -0,0 +1,6 @@ +#include <string> + +namespace onelab{ class client; } + +int metamodel(const std::string &todo); +void initializeMetamodel(onelab::client *); -- GitLab