Skip to content
Snippets Groups Projects
Commit 078b15f7 authored by Christophe Geuzaine's avatar Christophe Geuzaine
Browse files

up

parent 1c80eb9c
No related branches found
No related tags found
No related merge requests found
Pipeline #
// Gmsh - Copyright (C) 1997-2018 C. Geuzaine, J.-F. Remacle
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished
// to do so, provided that the above copyright notice(s) and this
// permission notice appear in all copies of the Software and that
// both the above copyright notice(s) and this permission notice
// appear in supporting documentation.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// Please report all bugs and problems to the public mailing list
// <gmsh@onelab.info>.
#ifndef _GMSH_SOCKET_H_
#define _GMSH_SOCKET_H_
//#include "GmshConfig.h"
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_AIX)
#include <strings.h>
#endif
#if !defined(WIN32) || defined(__CYGWIN__)
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#if defined(HAVE_NO_SOCKLEN_T)
typedef int socklen_t;
#endif
#else
#include <winsock.h>
#include <process.h>
typedef int socklen_t;
#endif
class GmshSocket{
public:
// types of messages that can be exchanged (never use values greater
// that 65535: if we receive a type > 65535 we assume that we
// receive data from a machine with a different byte ordering, and
// we swap the bytes in the payload)
enum MessageType{
GMSH_START = 1,
GMSH_STOP = 2,
GMSH_INFO = 10,
GMSH_WARNING = 11,
GMSH_ERROR = 12,
GMSH_PROGRESS = 13,
GMSH_MERGE_FILE = 20,
GMSH_PARSE_STRING = 21,
GMSH_VERTEX_ARRAY = 22,
GMSH_PARAMETER = 23,
GMSH_PARAMETER_QUERY = 24,
GMSH_PARAMETER_QUERY_ALL = 25,
GMSH_PARAMETER_QUERY_END = 26,
GMSH_CONNECT = 27,
GMSH_OLPARSE = 28,
GMSH_PARAMETER_NOT_FOUND = 29,
GMSH_SPEED_TEST = 30,
GMSH_PARAMETER_CLEAR = 31,
GMSH_PARAMETER_UPDATE = 32,
GMSH_OPEN_PROJECT = 33,
GMSH_CLIENT_CHANGED = 34,
GMSH_PARAMETER_WITHOUT_CHOICES = 35,
GMSH_PARAMETER_QUERY_WITHOUT_CHOICES = 36,
GMSH_OPTION_1 = 100,
GMSH_OPTION_2 = 101,
GMSH_OPTION_3 = 102,
GMSH_OPTION_4 = 103,
GMSH_OPTION_5 = 104};
protected:
// the socket descriptor
int _sock;
// the socket name
std::string _sockname;
// statistics
unsigned long int _sent, _received;
// send some data over the socket
int _SendData(const void *buffer, int bytes)
{
const char *buf = (const char *)buffer;
long int sofar = 0;
long int remaining = bytes;
do {
long int len = send(_sock, buf + sofar, remaining, 0);
if(len < 0) return -1; // error
sofar += len;
remaining -= len;
} while(remaining > 0);
_sent += bytes;
return bytes;
}
// receive some data over the socket
int _ReceiveData(void *buffer, int bytes)
{
char *buf = (char *)buffer;
long int sofar = 0;
long int remaining = bytes;
do {
long int len = recv(_sock, buf + sofar, remaining, 0);
if(len == 0) break; // we're done!
if(len < 0) return -1; // error
sofar += len;
remaining -= len;
} while(remaining > 0);
_received += bytes;
return bytes;
}
// utility function to swap bytes in an array
void _SwapBytes(char *array, int size, int n)
{
char *x = new char[size];
for(int i = 0; i < n; i++) {
char *a = &array[i * size];
memcpy(x, a, size);
for(int c = 0; c < size; c++)
a[size - 1 - c] = x[c];
}
delete [] x;
}
// sleep for some milliseconds
void _Sleep(int ms)
{
#if !defined(WIN32) || defined(__CYGWIN__)
usleep(1000 * ms);
#else
Sleep(ms);
#endif
}
public:
GmshSocket() : _sock(0), _sent(0), _received(0)
{
#if defined(WIN32) && !defined(__CYGWIN__)
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
}
~GmshSocket()
{
#if defined(WIN32) && !defined(__CYGWIN__)
WSACleanup();
#endif
}
// Wait for some data to read on the socket (if seconds and microseconds == 0
// we check for available data and return immediately, i.e., we do
// polling). Returns 1 when data is available, 0 when nothing happened before
// the time delay, -1 on error.
int Select(int seconds, int microseconds, int socket=-1)
{
int s = (socket < 0) ? _sock : socket;
struct timeval tv;
tv.tv_sec = seconds;
tv.tv_usec = microseconds;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(s, &rfds);
// select checks all IO descriptors between 0 and its first arg, minus 1;
// hence the +1 below
return select(s + 1, &rfds, NULL, NULL, &tv);
}
void SendMessage(int type, int length, const void *msg)
{
// send header (type + length)
_SendData(&type, sizeof(int));
_SendData(&length, sizeof(int));
// send body
_SendData(msg, length);
}
void SendString(int type, const char *str)
{
SendMessage(type, strlen(str), str);
}
void Info(const char *str){ SendString(GMSH_INFO, str); }
void Warning(const char *str){ SendString(GMSH_WARNING, str); }
void Error(const char *str){ SendString(GMSH_ERROR, str); }
void Progress(const char *str){ SendString(GMSH_PROGRESS, str); }
void MergeFile(const char *str){ SendString(GMSH_MERGE_FILE, str); }
void OpenProject(const char *str){ SendString(GMSH_OPEN_PROJECT, str); }
void ParseString(const char *str){ SendString(GMSH_PARSE_STRING, str); }
void SpeedTest(const char *str){ SendString(GMSH_SPEED_TEST, str); }
void Option(int num, const char *str)
{
if(num < 1) num = 1;
if(num > 5) num = 5;
SendString(GMSH_OPTION_1 + num - 1, str);
}
int ReceiveHeader(int *type, int *len, int *swap)
{
*swap = 0;
if(_ReceiveData(type, sizeof(int)) > 0){
if(*type > 65535){
// the data comes from a machine with different endianness and
// we must swap the bytes
*swap = 1;
_SwapBytes((char*)type, sizeof(int), 1);
}
if(_ReceiveData(len, sizeof(int)) > 0){
if(*swap) _SwapBytes((char*)len, sizeof(int), 1);
return 1;
}
}
return 0;
}
int ReceiveMessage(int len, void *buffer)
{
if(_ReceiveData(buffer, len) == len) return 1;
return 0;
}
// str should be allocated with size (len+1)
int ReceiveString(int len, char *str)
{
if(_ReceiveData(str, len) == len) {
str[len] = '\0';
return 1;
}
return 0;
}
void CloseSocket(int s)
{
#if !defined(WIN32) || defined(__CYGWIN__)
close(s);
#else
closesocket(s);
#endif
}
void ShutdownSocket(int s)
{
#if !defined(WIN32) || defined(__CYGWIN__)
shutdown(s, SHUT_RDWR);
#endif
}
unsigned long int SentBytes(){ return _sent; }
unsigned long int ReceivedBytes(){ return _received; }
};
class GmshClient : public GmshSocket {
public:
GmshClient() : GmshSocket() {}
~GmshClient(){}
int Connect(const char *sockname)
{
if(strstr(sockname, "/") || strstr(sockname, "\\") || !strstr(sockname, ":")){
#if !defined(WIN32) || defined(__CYGWIN__)
// UNIX socket (testing ":" is not enough with Windows paths)
_sock = socket(PF_UNIX, SOCK_STREAM, 0);
if(_sock < 0) return -1;
// try to connect socket to given name
struct sockaddr_un addr_un;
memset((char *) &addr_un, 0, sizeof(addr_un));
addr_un.sun_family = AF_UNIX;
strcpy(addr_un.sun_path, sockname);
for(int tries = 0; tries < 5; tries++) {
if(connect(_sock, (struct sockaddr *)&addr_un, sizeof(addr_un)) >= 0)
return _sock;
_Sleep(100);
}
#else
return -1; // Unix sockets are not available on Windows
#endif
}
else{
// TCP/IP socket
_sock = socket(AF_INET, SOCK_STREAM, 0);
if(_sock < 0) return -1;
char one = 1;
// disable Nagle's algorithm (very slow for many small messages)
setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
// try to connect socket to host:port
const char *port = strstr(sockname, ":");
int portno = atoi(port + 1);
int remotelen = strlen(sockname) - strlen(port);
char remote[256];
if(remotelen > 0)
strncpy(remote, sockname, remotelen);
remote[remotelen] = '\0';
struct hostent *server;
if(!(server = gethostbyname(remote))){
CloseSocket(_sock);
return -3; // no such host
}
struct sockaddr_in addr_in;
memset((char *) &addr_in, 0, sizeof(addr_in));
addr_in.sin_family = AF_INET;
memcpy((char *)&addr_in.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
addr_in.sin_port = htons(portno);
for(int tries = 0; tries < 5; tries++) {
if(connect(_sock, (struct sockaddr *)&addr_in, sizeof(addr_in)) >= 0){
return _sock;
}
_Sleep(100);
}
}
CloseSocket(_sock);
return -2; // couldn't connect
}
void Start()
{
char tmp[256];
#if !defined(WIN32) || defined(__CYGWIN__)
sprintf(tmp, "%d", getpid());
#else
sprintf(tmp, "%d", _getpid());
#endif
SendString(GMSH_START, tmp);
}
void Stop(){ SendString(GMSH_STOP, "Goodbye!"); }
void Disconnect(){ CloseSocket(_sock); }
};
class GmshServer : public GmshSocket{
private:
int _portno;
public:
GmshServer() : GmshSocket(), _portno(-1) {}
virtual ~GmshServer(){}
virtual int NonBlockingSystemCall(const std::string &exe, const std::string &args) = 0;
virtual int NonBlockingWait(double waitint, double timeout, int socket=-1) = 0;
// start the client by launching "exe args" (args is supposed to contain
// '%s' where the socket name should appear)
int Start(const std::string &exe, const std::string &args, const std::string &sockname,
double timeout)
{
_sockname = sockname;
int tmpsock;
if(strstr(_sockname.c_str(), "/") || strstr(_sockname.c_str(), "\\") ||
!strstr(_sockname.c_str(), ":")){
// UNIX socket (testing ":" is not enough with Windows paths)
_portno = -1;
#if !defined(WIN32) || defined(__CYGWIN__)
// delete the file if it already exists
unlink(_sockname.c_str());
// create a socket
tmpsock = socket(PF_UNIX, SOCK_STREAM, 0);
if(tmpsock < 0) throw "Couldn't create socket";
// bind the socket to its name
struct sockaddr_un addr_un;
memset((char *) &addr_un, 0, sizeof(addr_un));
strcpy(addr_un.sun_path, _sockname.c_str());
addr_un.sun_family = AF_UNIX;
if(bind(tmpsock, (struct sockaddr *)&addr_un, sizeof(addr_un)) < 0){
CloseSocket(tmpsock);
throw "Couldn't bind socket to name";
}
// change permissions on the socket name in case it has to be rm'd later
chmod(_sockname.c_str(), 0666);
#else
throw "Unix sockets not available on Windows";
#endif
}
else{
// TCP/IP socket: valid names are either explicit ("hostname:12345")
// or implicit ("hostname:", "hostname: ", "hostname:0") in which case
// the system attributes at random an available port
const char *port = strstr(_sockname.c_str(), ":");
_portno = atoi(port + 1);
// create a socket
tmpsock = socket(AF_INET, SOCK_STREAM, 0);
char one = 1;
setsockopt(tmpsock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
#if !defined(WIN32) || defined(__CYGWIN__)
if(tmpsock < 0)
#else
if(tmpsock == (int)INVALID_SOCKET)
#endif
throw "Couldn't create socket";
// bind the socket to its name
struct sockaddr_in addr_in;
memset((char *) &addr_in, 0, sizeof(addr_in));
addr_in.sin_family = AF_INET;
addr_in.sin_addr.s_addr = INADDR_ANY;
addr_in.sin_port = htons(_portno); // random assign if _portno == 0
if(bind(tmpsock, (struct sockaddr *)&addr_in, sizeof(addr_in)) < 0){
CloseSocket(tmpsock);
throw "Couldn't bind socket to name";
}
if(!_portno){ // retrieve name if randomly assigned port
socklen_t addrlen = sizeof(addr_in);
getsockname(tmpsock, (struct sockaddr *)&addr_in, &addrlen);
_portno = ntohs(addr_in.sin_port);
int pos = _sockname.find(':'); // remove trailing ' ' or '0'
char tmp[256];
sprintf(tmp, "%s:%d", _sockname.substr(0, pos).c_str(), _portno);
_sockname.assign(tmp);
}
}
if(exe.size() || args.size()){
char s[1024];
sprintf(s, args.c_str(), _sockname.c_str());
NonBlockingSystemCall(exe, s); // starts the solver
}
else{
timeout = 0.; // no command launched: don't set a timeout
}
// listen on socket (queue up to 20 connections before having
// them automatically rejected)
if(listen(tmpsock, 20)){
CloseSocket(tmpsock);
throw "Socket listen failed";
}
// wait until we get data
int ret = NonBlockingWait(0.001, timeout, tmpsock);
if(ret){
CloseSocket(tmpsock);
if(ret == 2){
throw "Socket listening timeout";
}
else{
return -1; // stopped listening
}
}
// accept connection request
if(_portno < 0){
#if !defined(WIN32) || defined(__CYGWIN__)
struct sockaddr_un from_un;
socklen_t len = sizeof(from_un);
_sock = accept(tmpsock, (struct sockaddr *)&from_un, &len);
#endif
}
else{
struct sockaddr_in from_in;
socklen_t len = sizeof(from_in);
_sock = accept(tmpsock, (struct sockaddr *)&from_in, &len);
char one = 1;
setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
}
CloseSocket(tmpsock);
if(_sock < 0)
throw "Socket accept failed";
return _sock;
}
int Shutdown()
{
#if !defined(WIN32) || defined(__CYGWIN__)
if(_portno < 0)
unlink(_sockname.c_str());
#endif
ShutdownSocket(_sock);
CloseSocket(_sock);
return 0;
}
};
#endif
This diff is collapsed.
// 1) compile with "c++ pend.cpp -o pend.exe"
// 2) launch "gmsh pend.exe"
#include <math.h>
#include <stdio.h>
#include "onelab.h"
void exportMsh(const std::string &path, double le1, double le2)
{
FILE *mshFile = fopen((path + "pend.msh").c_str(),"w");
if(!mshFile) return;
fprintf(mshFile, "$MeshFormat\n2.2 0 8\n$EndMeshFormat\n");
fprintf(mshFile, "$Nodes\n3\n1 0 0 0\n2 0 %f 0\n3 0 %f 0\n$EndNodes\n",
-le1, -le1-le2);
fprintf(mshFile, "$Elements\n3\n1 1 2 0 1 1 2\n2 1 2 0 1 2 3\n3 15 2 0 2 3\n"
"$EndElements\n");
fclose(mshFile);
}
void exportMshOpt(const std::string &path)
{
FILE *optFile = fopen((path + "pend.msh.opt").c_str(), "w");
if(!optFile) return;
fprintf(optFile, "n = PostProcessing.NbViews - 1;\n");
fprintf(optFile, "If(n >= 0)\nView[n].ShowScale = 0;\nView[n].VectorType = 5;\n");
fprintf(optFile, "View[n].ExternalView = 0;\nView[n].DisplacementFactor = 1 ;\n");
fprintf(optFile, "View[n].PointType = 1;\nView[n].PointSize = 5;\n");
fprintf(optFile, "View[n].LineWidth = 2;\nEndIf\n");
fclose(optFile);
}
void exportIter(const std::string &path, int iter, double t, double x1, double y1,
double x2, double y2)
{
FILE *mshFile = fopen((path + "pend.msh").c_str(), "a");
if(!mshFile) return;
fprintf(mshFile, "$NodeData\n1\n\"motion\"\n1\n\t%f\n3\n\t%d\n3\n", t, iter);
fprintf(mshFile, "\t3\n\t1 0 0 0\n\t2 %f %f 0\n\t3 %f %f 0\n$EndNodeData\n",
x1, y1, x2, y2);
fclose(mshFile);
}
double defineNumber(onelab::client *c, const std::string &name, double value,
const std::map<std::string, std::string> &attributes)
{
std::vector<onelab::number> ns;
c->get(ns, name);
if(ns.empty()){ // define new parameter
onelab::number n(name, value);
if(attributes.size()) n.setAttributes(attributes);
c->set(n);
return value;
}
// return value from server
return ns[0].getValue();
}
void setNumber(onelab::client *c, const std::string &name, double value,
double min=0, double max=0, bool visible=true)
{
onelab::number n(name, value);
n.setMin(min);
n.setMax(max);
n.setVisible(visible);
c->set(n);
}
void addNumberChoice(onelab::client *c, const std::string &name, double choice)
{
std::vector<onelab::number> ns;
c->get(ns, name);
if(ns.size()){
std::vector<double> choices = ns[0].getChoices();
choices.push_back(choice);
ns[0].setChoices(choices);
c->set(ns[0]);
}
}
int main(int argc, char **argv)
{
std::string name, address;
for(int i = 0; i < argc; i++){
if(std::string(argv[i]) == "-onelab" && i + 2 < argc){
name = std::string(argv[i + 1]);
address = std::string(argv[i + 2]);
}
}
if(name.empty() || address.empty()) return 1;
onelab::remoteNetworkClient *c = new onelab::remoteNetworkClient(name, address);
std::string action;
std::vector<onelab::string> ns;
c->get(ns, name + "/Action");
if(ns.size()) action = ns[0].getValue();
std::string path(argv[0]);
int islash = (int)path.find_last_of("/\\");
if(islash > 0)
path = path.substr(0, islash + 1);
else
path = "";
double g = 9.8; // acceleration of gravity
double m = 0.3; // mass of pendulum balls
std::map<std::string, std::string> attr;
double l = defineNumber(c, "Geom/arm length [m]", 1.0, attr);
double time = defineNumber(c, "Dyna/time [s]", 0., attr);
double dt = defineNumber(c, "Dyna/time step [s]", 0.001, attr);
double tmax = defineNumber(c, "Dyna/max time [s]", 20, attr);
double refresh = defineNumber(c, "Dyna/refresh interval [s]", 0.05, attr);
attr["Highlight"] = "Pink";
double theta0 = defineNumber(c, "Init/initial theta angle [deg]", 10, attr);
double phi0 = defineNumber(c, "Init/initial phi angle [deg]", 180, attr);
// we're done if we are not in the compute phase
if(action != "compute"){
delete c;
return 0;
}
double l1 = l;
double l2 = l;
double m1 = m;
double m2 = m;
double theta = theta0 / 180.*M_PI;
double phi = phi0 / 180.*M_PI;
double theta_dot = 0.0;
double phi_dot = 0.0;
double refr = 0.0;
int iter = 0;
time = 0.0;
while (time < tmax){
double delta = phi - theta;
double sdelta = sin(delta);
double cdelta = cos(delta);
double theta_dot_dot = ( m2*l1*(theta_dot*theta_dot)*sdelta*cdelta
+ m2*g*sin(phi)*cdelta
+ m2*l2*(phi_dot*phi_dot)*sdelta
- (m1+m2)*g*sin(theta) );
theta_dot_dot /= ( (m1+m2)*l1 - m2*l1*(cdelta*cdelta) );
double phi_dot_dot = ( -m2*l2*(phi_dot*phi_dot)*sdelta*cdelta
+ (m1+m2)*(g*sin(theta)*cdelta
- l1*(theta_dot*theta_dot)*sdelta
- g*sin(phi)) );
phi_dot_dot /= ( (m1+m2)*l2 - m2*l2*(cdelta*cdelta) );
theta_dot += theta_dot_dot*dt;
phi_dot += phi_dot_dot*dt;
theta += theta_dot*dt;
phi += phi_dot*dt;
double x1 = l1*sin(theta);
double y1 = -l1*cos(theta);
double x2 = l1*sin(theta) + l2*sin(phi);
double y2 = -l1*cos(theta) - l2*cos(phi);
time += dt;
refr += dt;
exportMshOpt(path);
if(refr >= refresh){
refr = 0;
setNumber(c, name + "/Progress", time, 0, tmax, false);
setNumber(c, "Dyna/time [s]", time);
setNumber(c, "Solu/phi", phi);
addNumberChoice(c, "Solu/phi", phi);
setNumber(c, "Solu/theta", theta);
addNumberChoice(c, "Solu/theta", theta);
setNumber(c, "Solu/phi dot", phi_dot);
addNumberChoice(c, "Solu/phi dot", phi_dot);
setNumber(c, "Solu/theta dot", theta_dot);
addNumberChoice(c, "Solu/theta dot", theta_dot);
// ask Gmsh to refresh
onelab::string s("Gmsh/Action", "refresh");
c->set(s);
// stop if we are asked to (by Gmsh)
c->get(ns, name + "/Action");
if(ns.size() && ns[0].getValue() == "stop") break;
exportMsh(path, l1, l2);
exportIter(path, iter, time, x1, y1+l1, x2, y2+l1+l2);
c->sendMergeFileRequest(path + "pend.msh");
iter += 1;
}
}
setNumber(c, name + "/Progress", 0, 0, tmax, false);
delete c;
return 0;
}
#!/usr/bin/env python
#coding=utf-8
# 1) Launch "gmsh pend.py", or open "pend.py" with Gmsh's File->Open menu
# 2) Click on "Run" in the left Gmsh panel
# 3) there is no number 3... :-)
# To interact with ONELAB, the script must first import the onelab.py module:
import onelab
import math, os
# The script then creates a ONELAB client with:
c = onelab.client(__file__)
# Creating the client connects the script to the onelab server, through a
# socket. The __file__ argument is a python variable. It tells ONELAB in which
# directory the script being executed is located.
def exportMsh(le1,le2):
mshFile = open(c.getPath("pend.msh"), 'w')
mshFile.write('$MeshFormat\n2.2 0 8\n$EndMeshFormat\n')
mshFile.write('$Nodes\n3\n1 0 0 0\n2 0 %s 0\n3 0 %s 0\n$EndNodes\n' %(-le1, -le1-le2))
mshFile.write('$Elements\n3\n1 1 2 0 1 1 2\n2 1 2 0 1 2 3\n3 15 2 0 2 3\n$EndElements\n')
mshFile.close()
def exportMshOpt():
optFile = open(c.getPath("pend.msh.opt"),'w')
optFile.write('n = PostProcessing.NbViews - 1;\n')
optFile.write('If(n >= 0)\nView[n].ShowScale = 0;\nView[n].VectorType = 5;\n')
optFile.write('View[n].ExternalView = 0;\nView[n].DisplacementFactor = 1 ;\n')
optFile.write('View[n].PointType = 1;\nView[n].PointSize = 5;\n')
optFile.write('View[n].LineWidth = 2;\nEndIf\n')
optFile.close()
def exportIter(iter,t,x1,y1,x2,y2):
mshFile = open(c.getPath("pend.msh"),'a')
mshFile.write('$NodeData\n1\n"motion"\n1\n\t%f\n3\n\t%d\n3\n' % (t, iter))
mshFile.write('\t3\n\t1 0 0 0\n\t2 %f %f 0\n\t3 %f %f 0\n$EndNodeData\n' %(x1,y1,x2,y2))
mshFile.close()
g = 9.8 # acceleration of gravity
m = 0.3 # mass of pendulum balls
# New ONELAB variables can then be defined using defineNumber, e.g.:
l = c.defineNumber('Geom/arm length [m]', value=1.0)
time = c.defineNumber('Dyna/time [s]', value=0.0)
dt = c.defineNumber('Dyna/time step [s]', value=0.001)
tmax = c.defineNumber('Dyna/max time [s]', value=20)
refresh = c.defineNumber('Dyna/refresh interval [s]', value=0.1)
theta0 = c.defineNumber('Init/initial theta angle [deg]', value=10,
attributes={'Highlight':'Pink'})
phi0 = c.defineNumber('Init/initial phi angle [deg]', value=180,
attributes={'Highlight':'Pink'})
# When the script is run, if the parameter Geom/arm length [m] has not been
# previously defined, it takes the value (1.0) provided in defineNumber and is
# sent to the ONELAB server. The "/" character in the variable name is
# interpreted as a path separator, and results in the creation of a sub-tree in
# the graphical user interface. If the script is re-run later, the value will be
# updated using the value from the server (unless it is labeled as readOnly: see
# below). When Gmsh runs a ONELAB client, the client can be run in two modes:
# c.action=='check' to check the coherence of the ONELAB database and make
# adjustments if necessary, and c.action=='compute' to perform the actual
# computation. For instance, in 'check' mode, the double pendulum client simply
# defines the ONELAB variables it wants to share with the server, then exits:
if c.action == 'check' :
exit(0)
# In 'compute' mode, the code enters a loop and performs the actual computation.
l1 = l;
l2 = l;
m1 = m;
m2 = m;
theta = theta0 / 180.*math.pi;
phi = phi0 / 180.*math.pi;
theta_dot = 0.0
phi_dot = 0.0
refr = 0.0
iter = 0
time = 0.0
while (time < tmax):
delta = phi - theta
sdelta = math.sin(delta)
cdelta = math.cos(delta)
theta_dot_dot = ( m2*l1*(theta_dot**2.0)*sdelta*cdelta
+ m2*g*math.sin(phi)*cdelta
+ m2*l2*(phi_dot**2.0)*sdelta
- (m1+m2)*g*math.sin(theta) )
theta_dot_dot /= ( (m1+m2)*l1 - m2*l1*(cdelta)**2.0 )
phi_dot_dot = ( -m2*l2*(phi_dot**2.0)*sdelta*cdelta
+ (m1+m2)*(g*math.sin(theta)*cdelta
- l1*(theta_dot**2.0)*sdelta
- g*math.sin(phi)) )
phi_dot_dot /= ( (m1+m2)*l2 - m2*l2*(cdelta)**2.0 )
theta_dot = theta_dot + theta_dot_dot*dt
phi_dot = phi_dot + phi_dot_dot*dt
theta = theta + theta_dot*dt
phi = phi + phi_dot*dt
x1 = l1*math.sin(theta)
y1 = -l1*math.cos(theta)
x2 = l1*math.sin(theta) + l2*math.sin(phi)
y2 = -l1*math.cos(theta) - l2*math.cos(phi)
time += dt
refr += dt
exportMshOpt()
if refr >= refresh:
refr = 0
# During the computation the script can directly set a value in the ONELAB
# database with setNumber:
c.setNumber(c.name + '/Progress', value=time, min=0, max=tmax, visible=0)
c.setNumber('Dyna/time [s]', value=time)
c.setNumber('Solu/phi', value=phi)
c.addNumberChoice('Solu/phi', phi)
c.setNumber('Solu/theta', value=theta)
c.addNumberChoice('Solu/theta', theta)
c.setNumber('Solu/phi dot', value=phi_dot)
c.addNumberChoice('Solu/phi dot', phi_dot)
c.setNumber('Solu/theta dot', value=theta_dot)
c.addNumberChoice('Solu/theta dot', theta_dot)
# It can also ask the server to refresh...
c.setString('Gmsh/Action', value='refresh')
# or to stop...
if(c.getString(c.name + '/Action') == 'stop'):
break;
exportMsh(l1, l2)
exportIter(iter, time, x1, y1+l1, x2, y2+l1+l2)
# or to read a file:
c.mergeFile(c.checkPath('pend.msh'))
iter += 1
# The check path function (c.checkPath) builds the pathname of a file
# named pend.msh located in the same directory as the script under
# execution, and then checks on whether the pathname exists on disk. If
# not, an error message is issued. Use the regular path function
# (c.getPath) to build a pathname without checking on the presence on disk
# of the file.
c.setNumber(c.name + '/Progress', value=0)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment