# HG changeset patch # User windel # Date 1356352374 -3600 # Node ID 5a965e9664f2e6a7b3dae3315d4af015442d5b6c # Parent a350055d6119b88be3005f4c82b434c3f9bbf638 Movage diff -r a350055d6119 -r 5a965e9664f2 python/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/__init__.py Mon Dec 24 13:32:54 2012 +0100 @@ -0,0 +1,5 @@ +# File to make this directory a package. + +from .codeeditor import CodeEdit +from .astviewer import AstViewer + diff -r a350055d6119 -r 5a965e9664f2 python/astviewer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/astviewer.py Mon Dec 24 13:32:54 2012 +0100 @@ -0,0 +1,36 @@ +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +def astToNamedElement(astNode, parentNode): + """ Helper to convert and AST tree to NamedElement tree: """ + item = QStandardItem(str(astNode)) + item.setData(astNode) + parentNode.appendRow(item) + for c in astNode.getChildren(): + astToNamedElement(c, item) + +# The actual widget: +class AstViewer(QTreeView): + sigNodeSelected = pyqtSignal(object) + def __init__(self, parent=None): + super(AstViewer, self).__init__(parent) + self.setHeaderHidden(True) + self.clicked.connect(self.selectHandler) + + def setAst(self, ast): + """ Create a new model and add all ast elements to it """ + model = QStandardItemModel() + if ast: + astToNamedElement(ast, model.invisibleRootItem()) + self.setModel( model ) + self.expandAll() + + def selectHandler(self, index): + if not index.isValid(): + return + model = self.model() + item = model.itemFromIndex(index) + node = item.data() + self.sigNodeSelected.emit(node) + + diff -r a350055d6119 -r 5a965e9664f2 python/bouncing_cube_opencl.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/bouncing_cube_opencl.py Mon Dec 24 13:32:54 2012 +0100 @@ -0,0 +1,406 @@ +from PyQt4.QtGui import * +from PyQt4.QtCore import * +from PyQt4.QtOpenGL import QGLWidget +from OpenGL.GL import * +from OpenGL.GLU import gluPerspective +import sys +from random import random +from math import pi, cos, sin, fabs, sqrt +from numpy import mat, array, ones, zeros, eye +from numpy.linalg import norm +import numpy as np +import time +import scipy.integrate +import pyopencl + +""" + Test script that lets a dice bounce. + Converted from 20-sim equations into python code. + + 20-sim website: + http://www.20sim.com + +""" +def drawCube(w): + glBegin(GL_QUADS) # Start Drawing The Cube + glColor3f(0.0,1.0,0.0) # Set The Color To Blue + glVertex3f( w, w,-w) # Top Right Of The Quad (Top) + glVertex3f(-w, w,-w) # Top Left Of The Quad (Top) + glVertex3f(-w, w, w) # Bottom Left Of The Quad (Top) + glVertex3f( w, w, w) # Bottom Right Of The Quad (Top) + + glColor3f(1.0,0.5,0.0) # Set The Color To Orange + glVertex3f( w,-w, w) # Top Right Of The Quad (Bottom) + glVertex3f(-w,-w, w) # Top Left Of The Quad (Bottom) + glVertex3f(-w,-w,-w) # Bottom Left Of The Quad (Bottom) + glVertex3f( w,-w,-w) # Bottom Right Of The Quad (Bottom) + + glColor3f(1.0,0.0,0.0) # Set The Color To Red + glVertex3f( w, w, w) # Top Right Of The Quad (Front) + glVertex3f(-w, w, w) # Top Left Of The Quad (Front) + glVertex3f(-w,-w, w) # Bottom Left Of The Quad (Front) + glVertex3f( w,-w, w) # Bottom Right Of The Quad (Front) + + glColor3f(1.0,1.0,0.0) # Set The Color To Yellow + glVertex3f( w,-w,-w) # Bottom Left Of The Quad (Back) + glVertex3f(-w,-w,-w) # Bottom Right Of The Quad (Back) + glVertex3f(-w, w,-w) # Top Right Of The Quad (Back) + glVertex3f( w, w,-w) # Top Left Of The Quad (Back) + + glColor3f(0.0,0.0,1.0) # Set The Color To Blue + glVertex3f(-w, w, w) # Top Right Of The Quad (Left) + glVertex3f(-w, w,-w) # Top Left Of The Quad (Left) + glVertex3f(-w,-w,-w) # Bottom Left Of The Quad (Left) + glVertex3f(-w,-w, w) # Bottom Right Of The Quad (Left) + + glColor3f(1.0,0.0,1.0) # Set The Color To Violet + glVertex3f( w, w,-w) # Top Right Of The Quad (Right) + glVertex3f( w, w, w) # Top Left Of The Quad (Right) + glVertex3f( w,-w, w) # Bottom Left Of The Quad (Right) + glVertex3f( w,-w,-w) # Bottom Right Of The Quad (Right) + glEnd() # Done Drawing The Quad + +def drawFloor(w, h): + glBegin(GL_QUADS) # Start Drawing The Cube + + glColor3f(1.0,0.5,0.0) # Set The Color To Orange + glVertex3f( w,-w,h)# Top Right Of The Quad (Bottom) + glVertex3f(-w,-w,h)# Top Left Of The Quad (Bottom) + glVertex3f(-w,w,h)# Bottom Left Of The Quad (Bottom) + glVertex3f( w,w,h)# Bottom Right Of The Quad (Bottom) + glEnd() # Done Drawing The Quad + +def drawAxis(): + glLineWidth(0.5) + glBegin(GL_LINES) + glColor3f(1.0, 0.0, 0.0) + glVertex3f(0,0,0) + glVertex3f(1,0,0) + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0,0,0) + glVertex3f(0,1,0) + glColor3f(0.0, 0.0, 1.0) + glVertex3f(0,0,0) + glVertex3f(0,0,1) + glEnd() + + +def cross(A, B): + a = A.A1 + b = B.A1 + return mat(np.cross(a, b)).T + +def skew(X): + Y = mat(zeros( (3, 3) )) + a,b,c = X.A1 + Y[0,1] = -c + Y[0,2] = b + Y[1,0] = c + Y[1,2] = -a + Y[2,0] = -b + Y[2,1] = a + return Y + +def adjoint(T): + W = T[0:3, 0] + V = T[3:6, 0] + a = mat(zeros( (6,6) ) ) + a[0:3, 0:3] = skew(W) + a[3:6, 0:3] = skew(V) + a[3:6, 3:6] = skew(W) + return a + +def Adjoint(H): + R = H[0:3, 0:3] + P = H[0:3, 3] + a = mat(zeros( (6,6) ) ) + a[0:3, 0:3] = R + a[3:6, 3:6] = R + a[3:6, 0:3] = skew(P) * R + return a + +def quatToR(q): + x, y, z, w = q.A1 + r = mat(eye(3)) + r[0,0] = 1 - (2*y**2+2*z**2) + r[0,1] = 2*x*y+2*z*w + r[0,2] = 2*x*z - 2*y*w + r[1,0] = 2*x*y-2*z*w + r[1,1] = 1 - (2*x**2 + 2*z**2) + r[1,2] = 2*y*z + 2*x*w + r[2,0] = 2*x*z+2*y*w + r[2,1] = 2*y*z - 2*x*w + r[2,2] = 1 - (2*x**2+2*y**2) + return r + +def rotateAbout(axis, angle): + ax, ay, az = (axis/norm(axis)).A1 + qx = ax*sin(angle/2.0) + qy = ay*sin(angle/2.0) + qz = az*sin(angle/2.0) + qw = cos(angle/2.0) + q = mat(array([qx,qy,qz,qw])).T + return q + +def normalizeQuaternion(quat): + x,y,z,w = quat.A1 + magnitude = sqrt(x*x + y*y + z*z + w*w) + x = x / magnitude + y = y / magnitude + z = z / magnitude + w = w / magnitude + quat[0, 0] = x + quat[1, 0] = y + quat[2, 0] = z + quat[3, 0] = w + return quat + +def VTo4x4(V): + v1, v2, v3 = V.A1 + return mat(array( \ + [[0.0, -v3, v2, -v1], \ + [ v3, 0.0, -v1, -v2], \ + [-v2, v1, 0.0, -v3], \ + [v1, v2, v3, 0.0] ])) + +def homogeneous(R,p): + H = mat(eye(4)) + H[0:3, 0:3] = R + H[0:3, 3] = p + return H + +def rateOfChange(states, thetime, parameters): + quat = states[0:4, 0] # Orientation (4) + pos = states[4:7, 0] # Position (3) + P = states[7:13, 0] # Momentum (6) + massI, gravity = parameters + # Rigid body parts: + # Forward Kinematic chain: + H = homogeneous(quatToR(quat), pos) # Forward kinematics + + AdjX2 = mat(eye(6)) # The connectionpoint in the real world + adjAdjX2_1 = adjoint(AdjX2[0:6,0]) + adjAdjX2_2 = adjoint(AdjX2[0:6,1]) + adjAdjX2_3 = adjoint(AdjX2[0:6,2]) + adjAdjX2_4 = adjoint(AdjX2[0:6,3]) + adjAdjX2_5 = adjoint(AdjX2[0:6,4]) + adjAdjX2_6 = adjoint(AdjX2[0:6,5]) + AdjInv2 = Adjoint(H.I) + M2 = AdjInv2.T * (massI * AdjInv2) # Transfor mass to base frame + MassMatrix = M2 + + wrenchGrav2 = mat( zeros((1,6)) ) + wrenchGrav2[0, 0:3] = -cross(gravity, pos).T + wrenchGrav2[0, 3:6] = gravity.T + + Bk = mat( zeros( (6,6) )) + Bk[0:3, 0:3] = skew(P[0:3, 0]) + Bk[3:6, 0:3] = skew(P[3:6, 0]) + Bk[0:3, 3:6] = skew(P[3:6, 0]) + + # TODO: do this a cholesky: + v = np.linalg.solve(MassMatrix, P) # Matrix inverse like thingy ! + + T2_00 = v # Calculate the relative twist! + TM2 = T2_00.T * M2 + twistExternal = T2_00 # Twist van het blokje + TMSum2 = TM2 + + PDotBodies = mat( zeros( (6,1)) ) + PDotBodies[0,0] = TMSum2 * (adjAdjX2_1 * T2_00) + PDotBodies[1,0] = TMSum2 * (adjAdjX2_2 * T2_00) + PDotBodies[2,0] = TMSum2 * (adjAdjX2_3 * T2_00) + PDotBodies[3,0] = TMSum2 * (adjAdjX2_4 * T2_00) + PDotBodies[4,0] = TMSum2 * (adjAdjX2_5 * T2_00) + PDotBodies[5,0] = TMSum2 * (adjAdjX2_6 * T2_00) + + PDot = -PDotBodies - Bk * v + PDot += wrenchGrav2.T + + ##### Contact wrench part: + HB_W = H # Is H-matrix van het blokje + WrenchB = mat(zeros( (1,6) )) + for px in [-0.5, 0.5]: + for py in [-0.5, 0.5]: + for pz in [-0.5, 0.5]: + HB1_B = homogeneous(mat(eye(3)), mat([px,py,pz]).T) + HB1_W = HB_W * HB1_B + HW1_W = homogeneous(mat(eye(3)), HB1_W[0:3,3]) + HW_W1 = HW1_W.I + HB_W1 = HW_W1 * HB_W + + AdjHB_W1 = Adjoint(HB_W1) + TB_W1_W1 = AdjHB_W1 * twistExternal + z = HB1_W[2, 3] + vx, vy, vz = TB_W1_W1[3:6, 0].A1 + if z < 0: + # Contact forces: + Fx = -50.0*vx + Fy = -50.0*vy + Fz = -z*50000.0 + else: + Fx = 0.0 + Fy = 0.0 + Fz = 0.0 + # TODO: reflect impulse + WrenchW1 = mat([0,0,0,0,0,Fz]) + # Transform it back: + WrenchB += (AdjHB_W1.T * WrenchW1.T).T + ##### End of contact wrench + + PDot += (WrenchB * AdjInv2).T + + # Position and orientation rates: + QOmega = VTo4x4(v[0:3, 0]) + quatDot = 0.5 * QOmega * quat + vel = v[3:6, 0] + posDot = skew(v[0:3]) * pos + vel + # The rate vector: + rates = mat(zeros( (13,1) )) + rates[0:4, 0] = quatDot + rates[4:7, 0] = posDot + rates[7:13, 0] = PDot + return rates + +def fWrapper(y, t, parameters): + y = mat(y).T + dy = rateOfChange(y, t, parameters) + return dy.T.A1 + +def SCIPY(endtime, dt, state, parameters): + times = np.arange(0.0, endtime, dt) + y0 = state.T.A1 + res = scipy.integrate.odeint(fWrapper, y0, times, args=(parameters,)) + states = [] + res = res.T + r,c = res.shape + for ci in range(0,c): + states.append(mat(res[:,ci]).T) + return states + +def RK4(endtime, dt, state, parameters): + t = 0.0 + states = [] + while t < endtime: + newstate = mat (zeros( state.shape )) # Create a new object + + #### Runge Kutta integration: + k1 = rateOfChange(state, t, parameters) + k2 = rateOfChange(state + 0.5*dt*k1, t, parameters) + k3 = rateOfChange(state + 0.5*dt*k1, t, parameters) + k4 = rateOfChange(state + dt*k3, t, parameters) + newstate = state + (dt/6.0)*(k1+2*k2+2*k3+k4) + + # Normalize quat: + newstate[0:4, 0] = normalizeQuaternion(newstate[0:4, 0]) + states.append(newstate) + + state = newstate + + t += dt + print state[6,0], t, ' ', (t/endtime)*100.0, '%' + return states + + +def simulate(endtime, dt): + PInitial = mat( zeros((6,1)) ) + posInitial = mat(array([-1.2, -1.3, 2.8])).T + quatInitial = rotateAbout(mat(array([0.2, 1.0, 0.4])).T, 0.5) + # Parameters: + gravity = mat( array([0,0,-9.81]) ).T + massI = mat(eye(6)) * 1.01 # Mass matrix + parameters = (massI, gravity) + + # The state vector! + state = mat(zeros( (13,1) )) + state[0:4, 0] = quatInitial + state[4:7, 0] = posInitial + state[7:13, 0] = PInitial + + return SCIPY(endtime, dt, state, parameters) + +class W(QGLWidget): + time = 0.0 + index = 0 + def __init__(self, states, dt, parent=None): + super(W, self).__init__(parent) + self.firstRun = True + self.savePNGS = False + self.dt = dt + self.resize(500,500) + self.states = states + self.UP() + t = QTimer(self) + t.timeout.connect(self.UP) + t.start(self.dt*1000.0) + + def UP(self): + self.time += self.dt + if self.states: + state = self.states[self.index] + self.Dicequat = state[0:4, 0] + self.Dicepos = state[4:7, 0] + self.index += 1 + if self.index == len(self.states): + self.index = 0 + self.firstRun = False + # Paint: + self.update() + if self.firstRun: + # Create png images for the movie: + if self.savePNGS: + pm = self.renderPixmap() + pm.save('image'+str(self.index)+'.png') + + def initializeGL(self): + glClearColor(0.0, 0.5, 0.0, 1.0) + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LESS) + glShadeModel(GL_SMOOTH) + def resizeGL(self,w,h): + glViewport(0, 0, w, h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(45.0, float(w)/float(h), 0.1, 100.0) + glMatrixMode(GL_MODELVIEW) + def paintGL(self): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # Clear buffers + glLoadIdentity() # Reset The View + + glLoadIdentity() + glTranslatef(0.0,-2.0,-10.0) # Move Left And Into The Screen + glRotatef(-90.0, 1.0, 0.0, 0.0) + drawFloor(2.0, 0.0) + drawAxis() + self.renderText(1.0, 0.0, 0.0, 'X') + self.renderText(0.0, 1.0, 0.0, 'Y') + self.renderText(0.0, 0.0, 1.0, 'Z') + + self.renderText(0.0,0.0,1.2,str(self.time)) + + x,y,z = self.Dicepos.A1 + R = quatToR(self.Dicequat) + + glTranslatef(x, y, z) + # Trick to rotate the openGL matrix: + r = R.A1 + rotR = (r[0], r[3], r[6], 0.0, + r[1], r[4], r[7], 0.0, + r[2], r[5], r[8], 0.0, + 0.0, 0.0, 0.0, 1.0) + glMultMatrixd(rotR) + + drawCube(0.6) + +et = 20.0 +dt = 0.04 +print 'starting integration... endtime =', et, ' stepsize =', dt +t0 = time.time() +states = simulate(et, dt) +t1 = time.time() +print 'That was heavy, it took me ', t1-t0, ' seconds!' +app = QApplication(sys.argv) +w = W(states, dt) +w.show() +sys.exit(app.exec_()) + diff -r a350055d6119 -r 5a965e9664f2 python/codeeditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/codeeditor.py Mon Dec 24 13:32:54 2012 +0100 @@ -0,0 +1,140 @@ +from PyQt4.QtCore import * +from PyQt4.QtGui import * +import compiler.lexer +import os.path + +class MySyntaxHighlighter(QSyntaxHighlighter): + def __init__(self, parent=None): + super(MySyntaxHighlighter, self).__init__(parent) + # Syntax highlighting: + self.rules = [] + fmt = QTextCharFormat() + fmt.setForeground(Qt.darkBlue) + fmt.setFontWeight(QFont.Bold) + for kw in compiler.lexer.keywords: + pattern = '\\b'+kw+'\\b' + self.rules.append( (pattern, fmt) ) + + # Comments: + fmt = QTextCharFormat() + fmt.setForeground(Qt.gray) + fmt.setFontItalic(True) + pattern = '\{.*\}' + self.rules.append( (pattern, fmt) ) + + # Procedure: + fmt = QTextCharFormat() + fmt.setForeground(Qt.blue) + fmt.setFontItalic(True) + #pattern = '(?<=procedure )[A-Za-z]' + # TODO lookbehind does not work, think something else + #self.rules.append( (pattern, fmt) ) + + def highlightBlock(self, text): + for pattern, fmt in self.rules: + expression = QRegExp(pattern) + index = expression.indexIn(text) + while index >= 0: + length = expression.matchedLength() + self.setFormat(index, length, fmt) + index = expression.indexIn(text, index + length) + +class LineNumberArea(QWidget): + def __init__(self, codeedit): + super(LineNumberArea, self).__init__(codeedit) + self.codeedit = codeedit + # TODO: display error in this: self.setToolTip('hello world') + def sizeHint(self): + return QSize(self.codeedit.lineNumberAreaWidth(), 0) + def paintEvent(self, ev): + self.codeedit.lineNumberAreaPaintEvent(ev) + +class CodeEdit(QPlainTextEdit): + def __init__(self, parent=None): + super(CodeEdit, self).__init__(parent) + # members: + self.isUntitled = True + self.filename = None + self.setFont(QFont('Courier')) + self.lineNumberArea = LineNumberArea(self) + + self.blockCountChanged.connect(self.updateLineNumberAreaWidth) + self.updateRequest.connect(self.updateLineNumberArea) + + # Syntax highlighter: + self.highlighter = MySyntaxHighlighter(self.document()) + + def setFileName(self, filename): + self.filename = filename + self.isUntitled = False + self.setWindowTitle(filename) + def setSource(self, source): + self.setPlainText(source) + + def save(self): + pass + def saveAs(self): + pass + + def saveFile(self): + if self.isUntitled: + self.saveAs() + else: + source = str(self.toPlainText()) + f = open(self.filename, 'w') + f.write(source) + f.close() + + def highlightErrorLocation(self, row, col): + tc = QTextCursor(self.document()) + tc.clearSelection() + tc.movePosition(tc.Down, tc.MoveAnchor, row - 1) + tc.movePosition(tc.Right, tc.MoveAnchor, col - 1) + tc.movePosition(tc.NextCharacter, tc.KeepAnchor) # Select 1 character + selection = QTextEdit.ExtraSelection() + lineColor = QColor(Qt.red).lighter(160) + selection.format.setBackground(lineColor) + #selection.format.setProperty(QTextFormat.FullWidthSelection, True) + selection.cursor = tc + self.setExtraSelections( [ selection ] ) + def clearErrors(self): + self.setExtraSelections( [ ] ) + + def lineNumberAreaWidth(self): + digits = 1 + mx = max(1, self.blockCount()) + while mx >= 10: + mx = mx / 10 + digits += 1 + space = 3 + self.fontMetrics().width('8') * digits + return space + def lineNumberAreaPaintEvent(self, ev): + painter = QPainter(self.lineNumberArea) + painter.fillRect(ev.rect(), Qt.lightGray) + block = self.firstVisibleBlock() + blockNumber = block.blockNumber() + top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top() + bottom = top + self.blockBoundingRect(block).height() + while block.isValid() and top <= ev.rect().bottom(): + if block.isVisible() and bottom >= ev.rect().top(): + num = str(blockNumber + 1) + painter.setPen(Qt.black) + painter.drawText(0, top, self.lineNumberArea.width(), self.fontMetrics().height(), Qt.AlignRight, num) + block = block.next() + top = bottom + bottom = top + self.blockBoundingRect(block).height() + blockNumber += 1 + def resizeEvent(self, ev): + super(CodeEdit, self).resizeEvent(ev) + cr = self.contentsRect() + self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height() )) + def updateLineNumberAreaWidth(self, newBlockCount): + self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0) + def updateLineNumberArea(self, rect, dy): + if dy > 0: + self.lineNumberArea.scroll(0, dy) + else: + self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height()) + if rect.contains(self.viewport().rect()): + self.updateLineNumberAreaWidth(0) + diff -r a350055d6119 -r 5a965e9664f2 python/integration_methods.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/integration_methods.py Mon Dec 24 13:32:54 2012 +0100 @@ -0,0 +1,205 @@ +import sys +from random import random +import numpy as np +import pylab +import time +import scipy.integrate + +""" + This script compares different methods to solve an ODE. + + The solved system consists of: + y_dot = f(y, t, p) + y0 + + where + y: the state vector of the system + y0: the initial state of the system + y_dot: the derivatives of the state vector + f: the function that returns the derivatives. + t: the time instant + p: the parameters of the system +""" + +def func(y, t, parameters): + """ + The example system is a bouncing point mass on a hunt-cossley surface. + State vector: + y[0] = height + y[1] = vertical momentum + + y_dot[0] = velocity + y_dot[1] = force + """ + # Step 1: extract the states into variables: + h = y[0] + p = y[1] + mass = parameters[0] + Kp_floor = parameters[1] + Kd_floor = parameters[2] + + # Step 2: Calculate model: + v = p / mass + + # Ground reaction force: + if h > 0: + F = 0.0 + else: + F = -h * Kp_floor + + # Gravity: + F += -9.81 * mass + y_dot = np.array([v, F], dtype=np.float) + return y_dot + +parameters = np.array([3, 50000, 3000], dtype=np.float) +y0 = np.array([1, 0], dtype=np.float) # Start at 1 meter, with 0 momentum + +class SCIPY: + def __init__(self, dt): + self.dt = dt + def name(self): + return "scipy.integrate" + def integrate(self, f, y0, parameters, endtime): + timevector = np.arange(0.0, endtime, self.dt) + states = scipy.integrate.odeint(f, y0, timevector, args=(parameters,)) + return timevector, states + +class RK4: + def __init__(self, dt): + self.dt = dt + + def name(self): + return "RK4" + def integrate(self, f, y0, parameters, endtime): + print(y0, parameters) + t = 0.0 + states = [] + timevector = [] + state = y0 + states.append(state) + timevector.append(t) + while t < endtime: + #### Runge Kutta integration: + k1 = func(state, t, parameters) + k2 = func(state + 0.5*self.dt*k1, t, parameters) + k3 = func(state + 0.5*self.dt*k1, t, parameters) + k4 = func(state + self.dt*k3, t, parameters) + newstate = state + (self.dt/6.0)*(k1+2*k2+2*k3+k4) + + t += self.dt + state = newstate + + states.append(state) + timevector.append(t) + + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + + +class BDFfixed: + def __init__(self, order): + self.order = order + def name(self): + return "BDF" + def integrate(self, f, y0, parameters, endtime): + timevector = [] + states = [] + timevector.append(0.0) + states.append(y0) + t = 0.0 + h = 0.01 + state = y0 + while t < endtime: + if len(states) < 4: + k1 = func(state, t, parameters) + k2 = func(state + 0.5*h*k1, t, parameters) + k3 = func(state + 0.5*h*k1, t, parameters) + k4 = func(state + h*k3, t, parameters) + newstate = state + (h/6.0)*(k1+2*k2+2*k3+k4) + state = newstate + t += h + timevector.append(t) + states.append(state) + else: + t += h + if np.max(state) > 10: + break + hyn = (11.0/6.0)*states[-1] + (-3)*states[-2] + (3/2)*states[-3] + (-1/3)*states[-4] + state = state + hyn + timevector.append(t) + states.append(state) + + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + +class WODE: + def __init__(self): + pass + def integrate(self, f, y0, parameters, endtime): + timevector = [] + states = [] + timevector.append(0.0) + states.append(y0) + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + +class DOPRI45: + def __init__(self): + pass + def name(self): + return "DOPRI" + def integrate(self, f, y0, parameters, endtime): + timevector = [] + states = [] + timevector.append(0.0) + states.append(y0) + y = y0 + t = 0.0 + + h = 0.01 + iteration = 0 + while t < endtime: + k1 = h*f(y, t, parameters) + k2 = h*f(y + (1.0/5.0)*k1, t + (1.0/5.0)*h, parameters) + k3 = h*f(y + (3.0/40.0)*k1 + (9.0/40.0)*k2, t + (3.0/10.0)*h, parameters) + k4 = h*f(y + (44.0/45.0)*k1 - (56.0/15.0)*k2 + (32.0/9.0)*k3, t + (4.0/5.0)*h, parameters) + k5 = h*f(y + (19372.0/6561.0)*k1 - (25360.0/2187.0)*k2 + (64448.0/6561.0)*k3 - (212.0/729.0)*k4, t + (8.0/9.0)*h, parameters) + k6 = h*f(y + (9017.0/3168.0)*k1 - (355.0/33.0)*k2 - (46732.0/5247.0)*k3 + (49.0/176.0)*k4 - (5103.0/18656.0)*k5, t + h, parameters) + k7 = h*f(y + (35.0/384.0)*k1 + (500.0/1113.0)*k3 + (125.0/192.0)*k4 - (2187.0/6784.0)*k5 + (11.0/84.0)*k6, t + h, parameters) + + + y_next = y + (35.0/384.0)*k1 + (500.0/1113.0)*k3 + (125.0/192.0)*k4 - (2187.0/6784.0)*k5 + (11.0/84.0)*k6 + z_next = y + (5179.0/57600.0)*k1 + (7571.0/16695.0)*k3 + (393.0/640.0)*k4 - (92097.0/339200.0)*k5 + (187.0/2100.0)*k6 + (1.0/40.0)*k7 + error = np.linalg.norm(y_next - z_next) + #print(error, t) + eps = 0.01 + if error < eps: + y = y_next + t = t + h + timevector.append(t) + states.append(y) + + s = ((eps*h)/(2*error)) ** (1.0/5.0) + h = s * h + if h < 1e-5: + h = 1e-5 + iteration += 1 + if iteration > 10000: + break + + return np.array(timevector, dtype=np.float), np.array(states, dtype=np.float) + +rk4 = RK4(0.01) +sp = SCIPY(0.01) +wode = BDFfixed(4) +dopri = DOPRI45() +methods = [rk4, sp, dopri] + +pylab.figure() +pylab.hold(True) +for method in methods: + t, s = method.integrate(func, y0, parameters, 10) + print(t.shape, s.shape) + pylab.plot(t, s[:,0], 'x-', label=method.name()) + +pylab.legend() +pylab.show() + diff -r a350055d6119 -r 5a965e9664f2 python/libs/project.py --- a/python/libs/project.py Mon Dec 24 13:30:12 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -""" - source project - contains: - - modules - - primitives like functions, types and variables - - other modules -""" - -import json - -class Project: - def __init__(self, filename=None): - self.name = "" - self.modules = [] - self.elements = [] - self.settings = {} - if filename: - self.load(filename) - - def load(self, filename): - """ Load the project from file """ - self.filename = filename - - with open(self.filename, 'r') as f: - d = json.load(f) - self.elements = d['elements'] - - def save(self): - if self.filename: - d = {'elements': self.elements} - print(d) - with open(self.filename, 'w') as f: - json.dump(d, f) - diff -r a350055d6119 -r 5a965e9664f2 python/libs/widgets/__init__.py --- a/python/libs/widgets/__init__.py Mon Dec 24 13:30:12 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -# File to make this directory a package. - -from .codeeditor import CodeEdit -from .astviewer import AstViewer - diff -r a350055d6119 -r 5a965e9664f2 python/libs/widgets/astviewer.py --- a/python/libs/widgets/astviewer.py Mon Dec 24 13:30:12 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -from PyQt4.QtCore import * -from PyQt4.QtGui import * - -def astToNamedElement(astNode, parentNode): - """ Helper to convert and AST tree to NamedElement tree: """ - item = QStandardItem(str(astNode)) - item.setData(astNode) - parentNode.appendRow(item) - for c in astNode.getChildren(): - astToNamedElement(c, item) - -# The actual widget: -class AstViewer(QTreeView): - sigNodeSelected = pyqtSignal(object) - def __init__(self, parent=None): - super(AstViewer, self).__init__(parent) - self.setHeaderHidden(True) - self.clicked.connect(self.selectHandler) - - def setAst(self, ast): - """ Create a new model and add all ast elements to it """ - model = QStandardItemModel() - if ast: - astToNamedElement(ast, model.invisibleRootItem()) - self.setModel( model ) - self.expandAll() - - def selectHandler(self, index): - if not index.isValid(): - return - model = self.model() - item = model.itemFromIndex(index) - node = item.data() - self.sigNodeSelected.emit(node) - - diff -r a350055d6119 -r 5a965e9664f2 python/libs/widgets/codeeditor.py --- a/python/libs/widgets/codeeditor.py Mon Dec 24 13:30:12 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -from PyQt4.QtCore import * -from PyQt4.QtGui import * -import compiler.lexer -import os.path - -class MySyntaxHighlighter(QSyntaxHighlighter): - def __init__(self, parent=None): - super(MySyntaxHighlighter, self).__init__(parent) - # Syntax highlighting: - self.rules = [] - fmt = QTextCharFormat() - fmt.setForeground(Qt.darkBlue) - fmt.setFontWeight(QFont.Bold) - for kw in compiler.lexer.keywords: - pattern = '\\b'+kw+'\\b' - self.rules.append( (pattern, fmt) ) - - # Comments: - fmt = QTextCharFormat() - fmt.setForeground(Qt.gray) - fmt.setFontItalic(True) - pattern = '\{.*\}' - self.rules.append( (pattern, fmt) ) - - # Procedure: - fmt = QTextCharFormat() - fmt.setForeground(Qt.blue) - fmt.setFontItalic(True) - #pattern = '(?<=procedure )[A-Za-z]' - # TODO lookbehind does not work, think something else - #self.rules.append( (pattern, fmt) ) - - def highlightBlock(self, text): - for pattern, fmt in self.rules: - expression = QRegExp(pattern) - index = expression.indexIn(text) - while index >= 0: - length = expression.matchedLength() - self.setFormat(index, length, fmt) - index = expression.indexIn(text, index + length) - -class LineNumberArea(QWidget): - def __init__(self, codeedit): - super(LineNumberArea, self).__init__(codeedit) - self.codeedit = codeedit - # TODO: display error in this: self.setToolTip('hello world') - def sizeHint(self): - return QSize(self.codeedit.lineNumberAreaWidth(), 0) - def paintEvent(self, ev): - self.codeedit.lineNumberAreaPaintEvent(ev) - -class CodeEdit(QPlainTextEdit): - def __init__(self, parent=None): - super(CodeEdit, self).__init__(parent) - # members: - self.isUntitled = True - self.filename = None - self.setFont(QFont('Courier')) - self.lineNumberArea = LineNumberArea(self) - - self.blockCountChanged.connect(self.updateLineNumberAreaWidth) - self.updateRequest.connect(self.updateLineNumberArea) - - # Syntax highlighter: - self.highlighter = MySyntaxHighlighter(self.document()) - - def setFileName(self, filename): - self.filename = filename - self.isUntitled = False - self.setWindowTitle(filename) - def setSource(self, source): - self.setPlainText(source) - - def save(self): - pass - def saveAs(self): - pass - - def saveFile(self): - if self.isUntitled: - self.saveAs() - else: - source = str(self.toPlainText()) - f = open(self.filename, 'w') - f.write(source) - f.close() - - def highlightErrorLocation(self, row, col): - tc = QTextCursor(self.document()) - tc.clearSelection() - tc.movePosition(tc.Down, tc.MoveAnchor, row - 1) - tc.movePosition(tc.Right, tc.MoveAnchor, col - 1) - tc.movePosition(tc.NextCharacter, tc.KeepAnchor) # Select 1 character - selection = QTextEdit.ExtraSelection() - lineColor = QColor(Qt.red).lighter(160) - selection.format.setBackground(lineColor) - #selection.format.setProperty(QTextFormat.FullWidthSelection, True) - selection.cursor = tc - self.setExtraSelections( [ selection ] ) - def clearErrors(self): - self.setExtraSelections( [ ] ) - - def lineNumberAreaWidth(self): - digits = 1 - mx = max(1, self.blockCount()) - while mx >= 10: - mx = mx / 10 - digits += 1 - space = 3 + self.fontMetrics().width('8') * digits - return space - def lineNumberAreaPaintEvent(self, ev): - painter = QPainter(self.lineNumberArea) - painter.fillRect(ev.rect(), Qt.lightGray) - block = self.firstVisibleBlock() - blockNumber = block.blockNumber() - top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top() - bottom = top + self.blockBoundingRect(block).height() - while block.isValid() and top <= ev.rect().bottom(): - if block.isVisible() and bottom >= ev.rect().top(): - num = str(blockNumber + 1) - painter.setPen(Qt.black) - painter.drawText(0, top, self.lineNumberArea.width(), self.fontMetrics().height(), Qt.AlignRight, num) - block = block.next() - top = bottom - bottom = top + self.blockBoundingRect(block).height() - blockNumber += 1 - def resizeEvent(self, ev): - super(CodeEdit, self).resizeEvent(ev) - cr = self.contentsRect() - self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height() )) - def updateLineNumberAreaWidth(self, newBlockCount): - self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0) - def updateLineNumberArea(self, rect, dy): - if dy > 0: - self.lineNumberArea.scroll(0, dy) - else: - self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height()) - if rect.contains(self.viewport().rect()): - self.updateLineNumberAreaWidth(0) - diff -r a350055d6119 -r 5a965e9664f2 python/project.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/project.py Mon Dec 24 13:32:54 2012 +0100 @@ -0,0 +1,34 @@ +""" + source project + contains: + - modules + - primitives like functions, types and variables + - other modules +""" + +import json + +class Project: + def __init__(self, filename=None): + self.name = "" + self.modules = [] + self.elements = [] + self.settings = {} + if filename: + self.load(filename) + + def load(self, filename): + """ Load the project from file """ + self.filename = filename + + with open(self.filename, 'r') as f: + d = json.load(f) + self.elements = d['elements'] + + def save(self): + if self.filename: + d = {'elements': self.elements} + print(d) + with open(self.filename, 'w') as f: + json.dump(d, f) +