Forked from
gmsh / gmsh
10247 commits behind the upstream repository.
-
Christophe Geuzaine authoredChristophe Geuzaine authored
onelabUtils.cpp 14.62 KiB
// Gmsh - Copyright (C) 1997-2014 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to the public mailing list <gmsh@geuz.org>.
#include "GmshConfig.h"
#if defined(HAVE_ONELAB)
#include "GmshDefines.h"
#include "GModel.h"
#include "Context.h"
#include "OS.h"
#include "OpenFile.h"
#include "CreateFile.h"
#include "StringUtils.h"
#include "onelabUtils.h"
#if defined(HAVE_POST)
#include "PView.h"
#include "PViewData.h"
#include "PViewOptions.h"
#endif
namespace onelabUtils {
// get command line arguments for the client if "UseCommandLine" is set for
// this client
std::vector<std::string> getCommandLine(onelab::client *c)
{
std::vector<std::string> args;
std::string name(c->getName());
std::vector<onelab::number> n;
c->get(n, name + "/UseCommandLine");
if(n.size() && n[0].getValue()){
std::vector<onelab::string> ps;
c->get(ps, name + "/Action");
std::string action = (ps.empty() ? "" : ps[0].getValue());
c->get(ps, name + "/1ModelName");
std::string modelName = (ps.empty() ? "" : ps[0].getValue());
c->get(ps, name + "/9CheckCommand");
std::string checkCommand = (ps.empty() ? "" : ps[0].getValue());
c->get(ps, name + "/9ComputeCommand");
std::string computeCommand = (ps.empty() ? "" : ps[0].getValue());
if(modelName.size()) args.push_back(" \"" + modelName + "\"");
if(action == "check")
args.push_back(" " + checkCommand) ;
else if(action == "compute")
args.push_back(" " + computeCommand);
}
return args;
}
std::string getMshFileName(onelab::client *c)
{
std::string name;
std::vector<onelab::string> ps;
c->get(ps, "Gmsh/MshFileName");
if(ps.size()){
name = ps[0].getValue();
}
else{
name = CTX::instance()->outputFileName;
if(name.empty()){
if(CTX::instance()->mesh.fileFormat == FORMAT_AUTO)
name = GetDefaultFileName(FORMAT_MSH);
else
name = GetDefaultFileName(CTX::instance()->mesh.fileFormat);
}
onelab::string o("Gmsh/MshFileName", name, "Mesh name");
o.setKind("file");
o.setAttribute("Closed", "1");
c->set(o);
}
// we could keep track of mesh file name in "Output files" so we could
// archive the mesh automatically:
/*
onelab::string copy("Gmsh/9Output files", name, "Mesh name");
copy.setKind("file");
copy.setVisible(false);
c->set(copy);
*/
return name;
}
void guessModelName(onelab::client *c)
{
std::vector<onelab::number> n;
c->get(n, c->getName() + "/GuessModelName");
if(n.size() && n[0].getValue()){
std::vector<onelab::string> ps;
c->get(ps, c->getName() + "/1ModelName");
if(ps.empty()){
std::vector<std::string> split = SplitFileName(GModel::current()->getFileName());
std::string ext = "";
onelab::server::instance()->get(ps, c->getName() + "/FileExtension");
if(ps.size()) ext = ps[0].getValue();
std::string name(split[0] + split[1] + ext);
onelab::string o(c->getName() + "/1ModelName", name, "Model name");
o.setKind("file");
c->set(o);
}
}
}
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());
numbers[i].setIndex(0); // indicates we are in a loop
std::vector<double> choices;
numbers[0].setChoices(choices);
onelab::server::instance()->set(numbers[i]);
changed = true;
}
}
else if(numbers[i].getStep() < 0){
if(numbers[i].getMax() != onelab::parameter::maxNumber()){
numbers[i].setIndex(0); // indicates we are in a loop
std::vector<double> choices;
numbers[0].setChoices(choices);
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 on disk
if(changed) setFirstComputationFlag(false);
}
bool incrementLoop(const std::string &level)
{
const double eps = 1.e-15; // for roundoff
// called at the end of the do{...} while(incrementLoops);
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]);
Msg::Info("Recomputing with %dth choice %s=%g", j,
numbers[i].getName().c_str(), numbers[i].getValue());
recompute = true;
}
}
else if(numbers[i].getStep() > 0){
int j = numbers[i].getIndex() + 1;
double val = numbers[i].getValue() + numbers[i].getStep();
if(numbers[i].getMax() != onelab::parameter::maxNumber() &&
val <= numbers[i].getMax() * (1 + eps)){
numbers[i].setValue(val);
numbers[i].setIndex(j);
onelab::server::instance()->set(numbers[i]);
Msg::Info("Recomputing with new step %s=%g",
numbers[i].getName().c_str(), numbers[i].getValue());
recompute = true;
}
else
numbers[i].setIndex(numbers[i].getMax());// FIXME makes sense?
}
else if(numbers[i].getStep() < 0){
int j = numbers[i].getIndex() + 1;
double val = numbers[i].getValue() + numbers[i].getStep();
if(numbers[i].getMin() != -onelab::parameter::maxNumber() &&
val >= numbers[i].getMin() * (1 - eps)){
numbers[i].setValue(val);
numbers[i].setIndex(j);
onelab::server::instance()->set(numbers[i]);
Msg::Info("Recomputing with new step %s=%g",
numbers[i].getName().c_str(), numbers[i].getValue());
recompute = true;
}
else
numbers[i].setIndex(numbers[i].getMin()); // FIXME makes sense?
}
}
}
if(loop && !recompute) // end of this loop level
initializeLoop(level);
return recompute;
}
std::vector<double> getRange(onelab::number &p)
{
const double eps = 1.e-15; // for roundoff
std::vector<double> v;
if(p.getChoices().size()){
v = p.getChoices();
}
else if(p.getMin() != -onelab::parameter::maxNumber() &&
p.getMax() != onelab::parameter::maxNumber()){
if(p.getStep() > 0){
for(double d = p.getMin(); d <= p.getMax() * (1 + eps); d += p.getStep())
v.push_back(d);
}
else if(p.getStep() < 0){
for(double d = p.getMin(); d <= p.getMax() * (1 + eps); d -= p.getStep())
v.push_back(d);
}
}
return v;
}
bool updateGraph(const std::string &graphNum)
{
bool changed = false;
#if defined(HAVE_POST)
PView *view = 0;
for(unsigned int i = 0; i < PView::list.size(); i++){
if(PView::list[i]->getData()->getFileName() == "OneLab" + graphNum){
view = PView::list[i];
break;
}
}
int num = atoi(graphNum.c_str());
std::vector<double> x, y;
std::string xName, yName;
std::vector<onelab::number> numbers;
onelab::server::instance()->get(numbers);
for(unsigned int i = 0; i < numbers.size(); i++){
std::string v = numbers[i].getAttribute("Graph");
v.resize(36, '0');
if(v[2 * num] == '1'){
x = getRange(numbers[i]);
xName = numbers[i].getShortName();
}
if(v[2 * num + 1] == '1'){
y = getRange(numbers[i]);
yName = numbers[i].getShortName();
}
}
if(x.empty()){
xName.clear();
for(unsigned int i = 0; i < y.size(); i++) x.push_back(i);
}
if(x.size() && y.size()){
if(x.size() != y.size())
Msg::Warning("X-Y data series have different length (%d != %d)",
(int)x.size(), (int)y.size());
if(view){
view->getData()->setXY(x, y);
view->getData()->setName(yName);
view->getOptions()->axesLabel[0] = xName;
view->setChanged(true);
}
else{
view = new PView(xName, yName, x, y);
view->getData()->setFileName("OneLab" + graphNum);
view->getOptions()->intervalsType = PViewOptions::Discrete;
view->getOptions()->autoPosition = num / 2 + 2;
}
changed = true;
}
else if(view){
delete view;
changed = true;
}
#endif
return changed;
}
static bool _firstComputation = true;
void setFirstComputationFlag(bool val){ _firstComputation = val; }
bool getFirstComputationFlag(){ return _firstComputation; }
bool runGmshClient(const std::string &action, bool meshAuto)
{
bool redraw = false;
onelab::server::citer it = onelab::server::instance()->findClient("Gmsh");
if(it == onelab::server::instance()->lastClient()) return redraw;
onelab::client *c = it->second;
std::string mshFileName = onelabUtils::getMshFileName(c);
static std::string modelName = GModel::current()->getName();
if(action == "initialize"){
// nothing to do
}
else if(action == "reset"){
setFirstComputationFlag(false);
// nothing more to do: "check" will be called right afterwards
}
else if(action == "check"){
if(onelab::server::instance()->getChanged("Gmsh") ||
modelName != GModel::current()->getName()){
// reload geometry if Gmsh parameters have been modified or if the model
// name has changed
modelName = GModel::current()->getName();
redraw = true;
OpenProject(GModel::current()->getFileName(), false);
}
}
else if(action == "compute"){
if(onelab::server::instance()->getChanged("Gmsh") ||
modelName != GModel::current()->getName()){
// reload the geometry, mesh it and save the mesh if Gmsh parameters
// have been modified or if the model name has changed
modelName = GModel::current()->getName();
redraw = true;
OpenProject(GModel::current()->getFileName(), false);
if(getFirstComputationFlag() && !StatFile(mshFileName)){
Msg::Info("Skipping mesh generation: assuming '%s' is up-to-date",
mshFileName.c_str());
}
else if(!GModel::current()->empty() && meshAuto){
GModel::current()->mesh(3);
CreateOutputFile(mshFileName, CTX::instance()->mesh.fileFormat);
}
}
else if(StatFile(mshFileName)){
// mesh+save if the mesh file does not exist
if(meshAuto){
redraw = true;
GModel::current()->mesh(3);
CreateOutputFile(mshFileName, CTX::instance()->mesh.fileFormat);
}
}
setFirstComputationFlag(false);
onelab::server::instance()->setChanged(false, "Gmsh");
}
return redraw;
}
// update x using y, giving priority to any settings in x that can be set in
// the GUI. The value of x is only changed if y is read-only.
double updateNumber(onelab::number &x, onelab::number &y, const bool readOnlyRange)
{
bool noRange = true, noChoices = true, noLoop = true;
bool noGraph = true, noClosed = true;
if(y.getReadOnly()){
x.setValue(y.getValue());
x.setReadOnly(true);
}
double val = x.getValue();
// keep track of these attributes, which can be changed server-side (unless,
// for the range/choices, when explicitely setting these attributes as
// ReadOnly)
if(!readOnlyRange){
if(x.getMin() != -onelab::parameter::maxNumber() ||
x.getMax() != onelab::parameter::maxNumber() ||
x.getStep() != 0.) noRange = false;
if(x.getChoices().size()) noChoices = false;
}
if(x.getAttribute("Loop").size()) noLoop = false;
if(x.getAttribute("Graph").size()) noGraph = false;
if(x.getAttribute("Closed").size()) noClosed = false;
if(noRange){
bool noRangeEither = true;
if(y.getMin() != -onelab::parameter::maxNumber() ||
y.getMax() != onelab::parameter::maxNumber() ||
y.getStep() != 0.) noRangeEither = false;
if(!noRangeEither){
x.setMin(y.getMin());
x.setMax(y.getMax());
}
else{
// if no range/min/max/step info is provided, try to compute a reasonnable
// range and step (this makes the GUI much nicer to use)
bool isInteger = (floor(val) == val);
double fact = isInteger ? 5. : 20.;
if(val > 0){
x.setMin(val / fact);
x.setMax(val * fact);
x.setStep((x.getMax() - x.getMin()) / 100.);
}
else if(val < 0){
x.setMin(val * fact);
x.setMax(val / fact);
x.setStep((x.getMax() - x.getMin()) / 100.);
}
if(val && isInteger){
x.setMin((int)x.getMin());
x.setMax((int)x.getMax());
x.setStep((int)x.getStep());
}
}
}
if(noChoices) {
x.setChoices(y.getChoices());
x.setValueLabels(y.getValueLabels());
}
if(noLoop) x.setAttribute("Loop", y.getAttribute("Loop"));
if(noGraph) x.setAttribute("Graph", y.getAttribute("Graph"));
if(noClosed) x.setAttribute("Closed", y.getAttribute("Closed"));
return val;
}
// update x using y, giving priority to any settings in x that can be set in
// the GUI. The value of x is only changed if y is read-only.
std::string updateString(onelab::string &x, onelab::string &y)
{
bool noChoices = true, noClosed = true, noMultipleSelection = true;
if(y.getReadOnly()){
x.setValue(y.getValue());
x.setReadOnly(true);
}
std::string val = x.getValue();
// keep track of these attributes, which can be changed server-side
if(x.getChoices().size()) noChoices = false;
if(x.getAttribute("Closed").size()) noClosed = false;
if(x.getAttribute("MultipleSelection").size()) noMultipleSelection = false;
//if(copt.count("Kind")) ps[0].setKind(copt["Kind"][0]);
if(noChoices) x.setChoices(y.getChoices());
if(noClosed) x.setAttribute("Closed", y.getAttribute("Closed"));
if(noMultipleSelection)
x.setAttribute("MultipleSelection", y.getAttribute("MultipleSelection"));
return val;
}
}
#endif