Perspective

My journey,my life

The beginning of a journey

OK. I had been programming in PyQt4 for about three months, and it was becoming quite monotonous. I wanted to do start doing something different. Moreover my other projects weren’t going as good as expected. Still searching for something to do,  was it just a co-incidence that GSoC was announced that day? I would rate my programming ability, somewhere just above average and my knowledge of python around intermediate. I also knew a bit of ‘C’ that they had taught in college. I was comfortable till arrays, but when pointers started, umm.. well they pointed me away from C. And as for my knowledge about other programming languages, the less I speak about them, the better.

If I had to have any real shot at GSoC, that was my best opportunity to increase my skillset . I had tried to contribute to open source before for organisations like Orange and Ascend but never reached much after building from source (Quite lucky because those two organisations did not make it to GSoC after all). To begin with mentoring organisations can be broadly classified into OS based and stuff related to maths, CV, ML. Once I tried to write a plugin for Rhythmbox but for some reason I stopped in the middle. As far as Linux goes, though it is my primary OS right now, sincerely speaking I never knew much beyond installing packages and configuring proxy. Also I had just begun with CV and I knew it would take me quite a lot of dedication, for a project related to CV. Seriously not knowing what to do, I just googled “gsoc 2013 python ideas” and the first search result was sympy. I randomly skimmed through the ideas, and found the ones related to the ordinary differential equation solver quite interesting. Not wasting any time, I forked sympy and started looking through the source.

For the first one hour, I couldn’t understand anything and I felt disappointed. Then I introduced myself to the list, and I was advised to solve existing bugs in the ODE module, instead of looking through the entire source. I did nothing after that, since my exams were there (which I screwed up anyway) , and after they were over I looked into the bug tracker and I found a bug which I believed I could solve. Randomly littering the source code of the ODE module with print statements (Yeah, I’m a beginner) , and after spending two hours, I finally understood what was going on. And then I managed to fix the bug . I ran tests and then sent my first Pull Request. Damn, I had forgotten to add new tests for the bug fixed . After adding tests finally https://github.com/sympy/sympy/pull/1803 , it got merged. Woohoo! Nothing can explain that small moment of joy of your first merge. I then played with the source code using random examples, and I managed to find out a couple of bugs myself. I also found support for a few types of first order differential equations missing, and after a lot of work and discussion on my PR’s they got merged.

In between all this, I had to work for my SoC proposal as well. I first proposed a few ideas, but then I was told that they were trivial in a sense and could be implemented in a single Pull Request. I found something called as a Lie Group solver and I spent a week reading about it. After a lot of edits, I submitted my proposal for  proof reading to the sympy community. Aaron Meurer the lead developer of sympy, told my proposal to be good. He also told me that Partial Differential Equation support is missing in sympy and I would have to build the infrastructure myself. So I started to work on it. After two weeks, my PR got merged in master https://github.com/sympy/sympy/pull/1970  and now sympy can solve and check the solution of the most basic partial differential equation.

Before I go any further, I would like to thank a few people who helped me reach this far.  First of all my parents, who encouraged me to do what I like. Then Jay Rambhia , who introduced me to python, without whom I wouldn’t be doing what I am doing now, Priyans Murarka who kept pushing me on, Manoj Kumar Pandey Sir, my maths professor in semester 2, who gave me the required papers to study about the lie groups solvers, Debajyoti Datta, who gave suggestions to my proposal, the sympy community in general who treated even a rookie like me as a proper professional coder,  Sachin Joglekar for his timely help in git and Eejya Singh (if she ever reads this) who gave me moral support throughout the last part of my proposal. I definitely have more people to thank, but I wouldn’t want this post filled with names of people

I submitted my GSoC Proposal to melange today, and I have kept my expectations low. Overall this sem has been a roller-coaster ride (with many of my expectations , which I wouldn’t want to mention here crashing) and I hope it doesn’t disappoint any further. Also results are on May 27th, two years back I had given BITSAT the same day and got my “dream branch” (Yeah, Mechanical) which I hadn’t expected at all. Hopefully it is lucky for more than on reason. More on my proposal on May 27th if I get selected and till then sayonara (did I mention I’m learning Japanese?).

P. S :  Need some motivation to study for my end sem exams. This sem has been very average in terms of academics and thats not a really good thing.

Import sympy

I had just had a look at sympy’s documentation and it provides good support for solving differential equations. Sample this . Solving a differential equation would be as simple as this

from sympy import Function , Derivative
from sympy.abc import x
f = Function('f')(x) #Creates a function f with respect to x
d = Derivative(f , x ) #Derivative of f wrt to x is stored in d
dsolve(d -f , f)

which gives   f(x) == C1*exp(x) as the ouput.

I also tried an example given in my book.

f = Function('f')(x) #Creates a function f with respect to x
d = Derivative(f , x , x)
d_ = Derivative(f , x)
dsolve(d - d_ - 2 * f - 4 * x * x)

which again gives me  f(x) == C1*exp(-x) + C2*exp(2*x) – 2*x**2 + 2*x – 3
as the required output.

P.S : I will try to fix a few bugs as soon as my exams get over , wish me luck.

Positioning of widgets in PyQt4

A short note on positioning of widgets in PyQt4 .

Let say you have a layout , a button and few labels. If I press a button and a label should become invisible , your code should look something like this.

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window , self).__init__()
        <code>layout = QtGui.QGridLayout(self)
        self.label1 = QtGui.QLabel('Label1')
        label2 = QtGui.QLabel('Label2')
        label3 = QtGui.QLabel('Label3')
        layout.addWidget(self.label1 , 0 , 0)
        layout.addWidget(label2 , 1 , 0)
        layout.addWidget(label3 , 2 , 0)
        button = QtGui.QPushButton('Hide')
        button.clicked.connect(self.fun)</code>

    def fun(self):
        self.label1.hide()

The problem with this however is , it automatically repositions your labels such that it occupies the entire window. In order to prevent this , its better to use a frame.


//In your __init__ constructor.
frame = QtGui.QFrame()
self.label1 = QtGui.QLabel(frame)

This makes sure the labels dont get repositioned.

Threading in PyQt4

Hello Everyone , I will explain on how to create a rotating circle using the concept of multithreading , qraphicsscene aand qgraphicsview. I struggled a lot to get the syntax( noobish I know) , but this is just to ensure no-one suffers the same.

from PyQt4 import QtGui , QtCore
import sys , time
#this imports the required libraries

We will be inheriting QtGui.QWidget , to create the basic user interface design.

class Example(QtGui.QWidget):
    def __init__(self):
        #Initialising the parent class and calling self.UI
        super(Example , self).__init__()
        self.UI()

My UI function should just have a layout with a graphics view and a button say Run . So this will be my function.

#Inside the UI function.
//Self Explanatory (Creating and adding widgets to my layout)
self.setWindowTitle('Revolving Circle')
self.setGeometry(200 , 200 , 500 , 500)
layout = QtGui.QGridLayout(self)
button = QtGui.QPushButton('Revolve')
view = QtGui.QGraphicsView()
scene = QtGui.QGraphicsScene()
view.setScene(scene)
layout.addWidget(view , 0 , 0)
layout.addWidget(button , 0 ,1)
self.show()
button.clicked.connect(self.revolve) #Connecting the button signal to the function revolve

Now for creating the circle and the line connecting the centre to the circumference of the circle.

#Inside the UI function
circle = QtGui.QGraphicsEllipseItem(150 , 250 , 50 , 50)
scene.addItem(circle)

The parameters that QGraphicsEllipseItem takes? Um. well , assume the ellipse is enclosed in a rectangle , the first two
numbers give the x and y coordinates , of the top left corner of the rectangle , the third and fourth give me the length
of the major axis and minor axis respectively.Now to add the line that represents the radius of the circle.

self.lin = QtCore.QLineF(QtCore.QPointF(175 , 275) , QtCore.QPointF(200 , 275))
self.line1 = QtGui.QGraphicsLineItem.setLine(self.lin)
scene.addItem(self.line1)

For setting a line in a QGraphicsScene , it is better to have a QLineF set in a QGraphicsLineItem , so that it becomes
easier to update , and the QLineF , takes as parameters , the starting and ending point.

So the basic interface is set. Now to add the function , the button sets off when clicked.

def revolve(self):
    theta = 10
    i = 0
    while 1:
        i = i + 1
        time.sleep(0.01)
        self.lin.setAngle(theta * i)
        self.line1.setLine(self.lin)

This should make the radius revolve right? But it wouldn’t. It would start to hang. The way to rectify is to create
a seperate thread for the time computation and passing it on to a function , instead of letting the GUI function do the
time computation itself. And for people who ask why , theta * i , just theta wouldn’t do because theta is with respect to
the position of the initial line.

So for the threading part , we need to inherit the QtCore.QThread class , and rewrite the run method.

class RevolveThread(QtCore.QThread):
    def __init__(self):
        super(RevolveThread , self).__init__()

    def run(self):
        i = 0
        while 1:
            i = i + 1
            time.sleep(0.01)
            self.emit(QtCore.SIGNAL('update(QString)') )

So every 0.01 seconds this runs , it emits a signal. which is caught by the function it is connected to.

Now write another function , change , which implements the rotation.

#Inside a function change
self.lin.setAngle(theta * i)
self.line1.setLine(self.lin)

Remove other lines in the function revolve , just add lines that initialises the thread , connects it to the function ,
change , and starts the thread

#Inside revolve
thread = WorkThread()
self.connect(thread , QtCore.SIGNAL('update(QString)') , self.change)
thread.start()

And as for managing threads , its better to create a list of them , and then call them one by one , as and when the
button is clicked.

So when you click on the Revolve Button , you will see a rotating circle.

Reference:
http://joplaete.wordpress.com/2010/07/21/threading-with-pyqt4/

Thanks for reading..

PyQt4 Notes – 1

Here are a few code snippets I had to search for . This is for my future reference and for any one who might needing it.

1 . First of all , a simple concept that I did not understand before.


app = QtGui.QApplication(sys.argv)

#Main Class here

sys.exit(app.exec_())  #app.exec_() runs the whole qt loop till you provide it with the exit method.

 

2 . And I had just started this thing called QtGraphicsView . It seems really complicated and this is what Ive understood till now.

#Inheriting the class QGraphicsView
class Example(QtGui.QGraphicsView):
    def  __init__ (self):
        super(Example , self).__init__() #As usual when you want to inherit the __init__ method of the class
        //Adding QGraphicsScene to your QGraphicsView which is the parent
        self.scene = QtGui.QGraphicsScene(self)

3 . And now you can add lines , ellipses and other stuff to your self.scene [For now I know just lines and ellipses]


self.line = QtGui.QGraphicsLineItem(self.startx , self.starty , self.endx , self.endy)
    //initial and final positions of the line.    self.scene.addItem(self.line)


4 . And for tracking the position of the mouse , the following functions come in handy


def mousePressEvent(self , event):
        //event is actually the class mousePressEvent        self.startx = event.x()
        self.starty = event.y()

The same applies for mouseReleaseEvents and mouseMoveEvents , the difference between event.x() and event.y() give the co-ordinates when the mouse is released or moved.

And if you want the clear the QGraphicsScene , what do you have to do?

Simple , self.scene.clear()

Thats all for now.

 

 

 

Runge-kutta method using Python.

My exams finally got over . I got back home and slept for a week continuously . After that I realised I had to solve a differential equation for a project . Seniors told me the Runge-kutta method is numerically the best method to find function values at a particular point provided you are given the differential equation and the initial conditions.

So here is my interpretation of the method .

You are given a function at a given point and you need to find the function value at a point . So you find the function value at a minutely greater point using the Runge-Kutta method and keep iterating till you reach the given point.

Suppose the given differential equation is

du / dx = x ; u(0) = 0 || Comparing it with  du / dx = f(x)

You need to increment by a really small value , lets say 0.1

The Runge-Kutta method gives us four values of slope , k1 , k2 , k3 and k4 , k1 and k4 are near the two ends of the function , k2 and k3 are near the midpoints .

k1 = f(x , u(x))  = f(0 , 0) = 0 at the initial point

k2 = f(x + delx / 2 ,  u(x) + 0.5k1) = f(0.05 , 0) = 0.05

k3 = f(x + delx / 2 , u(x) + 0.5k2) = f(0.05 , 0.025) = 0.05

These are approximate slope values at the midpoints.

k4 = f(x + delx , u(x) + k3) = f(0.1 ,  0.05) = 0.1

The A.M of these four values will be (k1 + 2 *(k2 + k3) + k4) / 6 and into delx will give the y increment

which gives (1 / 6) * (0 + 2 * (0.05 + 0.05) + 0.1) * 0.1 = 0.005

Which indeed is the function value that can be got by simple-integration , u(x) will be x^2 / 2

Suppose you would like to find the value at some larger point say at x = 100 . Simple , perform a number of iterations using delx = 0.1 till you reach 100 . The smaller the size of increment for each iteration , the better.

This is a simple python code for the case in which f(x) is a simple polynomial

https://github.com/Manoj-Kumar-S/Rk4-Polynomials/blob/master/rk4.py

Yes . Ive updated my Github account! Cheers!

Play Hangman using python

Since I was bored , I wanted to write a script to build a simple version of Hangman using PyQt4. The logic (of course) wasn’t that difficult , however finding syntax for certain parts of the program was difficult , so I thought this post should save time , for those needing the syntax as well as me , later on . So here goes!

One has to import all the required libraries and call QtGui.QApplication to start the application.


app = QtGui.QApplication(sys.argv)

ex = Hangman()

sys.exit(app.exec_())

The main requirements are , an on-screen keyboard , something to paint the Hangman , an edit box , a couple of labels . Half work done.

I would be focussing only a few methods (or) functions , which I had trouble in.

First , design your main window , with a simple label , and a qline-edit box , and a qpushbutton . You should place them in a container , vbox/hbox – layout (or) qgrid layour . I prefer qgrid layouts , since they are easier to understand . And for connecting a button to a function , you use this syntax


self.button.clicked.connect(self.fun)

self.sender()  //and by this you get the button which calls the function

P.S : For more details on how to build a simple window , please refer to almost any of my previous posts , almost all of them would be related to GUI programming , because that’s all I know .

1 . Painting the hangman

I had defined a list called hangman list which consisted a list of seven zeros . Whenever a wrong input is given , a zero is turned into a one , and a part of the hangman is painted . For this a method called paintEvent is used. This involves QtPainter .


def paintEvent(self , e):

    qp = QtGui.QPainter()  //initialising the painter

    qp.begin(self) //starting the painter

    pen = QtGui.QPen(QtCore.Qt.Red , 5 , QtCore.Qt.SolidLine)  //       pen to draw lines ,  red makes it scary , 5 - thickness
    qp.setPen(pen)
    qp.drawLine(20 , 20 , 20 , 200)  //first two co-ordinates are the starting points and the lat two are the ending points
    qp.drawLine(20 , 20 , 120 , 20)

    qp.drawLine(20 , 20 , 120 , 20)

    if self.hangman[0] == 1:

        qp.drawLine(120 , 20 , 120 , 50)   //this is for the noose
    if self.hangman[1] == 1:

        point = QtCore.QPoint(120 , 70)
        qp.drawEllipse(point , 20 , 20)   //this is for the head

An important thing is to be noted here . Wherever self.hangman is changed , self.update() must be called. This makes sure that the painting is updated.

2 . OnScreen Keyboard.

The onscreen keyboard can be implemented using 26 different push buttons , and linking them to the same function. For using functions , when the user presses keys , a method called keyPressEvent is used.


def keyPressEvent(self , e):

    if e.key() == QtCore.Qt.Key_A:
        fun()

This makes sure the given function gets executed when one presses A . If one wants to link the same function , when one
presses the key ‘Q’ and actually clicks the key ‘Q’ on the keyboard , what should be done. I have no idea in PyQt since
the syntax is quite different. However this code might help.

self.q.clicked.connect(self.fun)
def keyPressEvent(self , e):

    if e.key() == QtCore.Qt.Key_A:
        fun('q')

def fun(self , text):
    if text == False:
    '''This is the Push Button has default value of not checkable , and hence when clicked , False is passed'''
     \\implement function
    for i in range(self.layout.count()):
        w = self.layout.itemAt(i).widget()
        if isinstance(w , QtGui.QPushButton):
            if w.text() == text:
                \\implement function

And if all widgets have to be cleared , use

for i in range(self.layout.count()):
    self.layout.itemAt(i).widget().close()

For the entire code please refer to this.
https://gist.github.com/4090465

And these are the links I referred to .
http://stackoverflow.com/questions/13399598/qtcore-qt-key-doesnt-seem-to-work
http://stackoverflow.com/questions/13380003/changing-the-position-of-a-line-using-qpainter
This is how it looks.

Cycle Simulation – Part Two

Continuing with my previous post about cycle simulation , I will focus on the three , important gas cycles , Otto , Diesel and Dual Cycle. I used PyQt4 for the graphical user interface ,  and matplotlib for the simulation .

This was quite easy for the following reasons:

1 . Gas cycles are those in which you can assume the gas to be ideal , so you could ideal gas equations like P*V = m*R*T and so on.

2. The basic GUI framework was built with the Rankine cycle , and I just needed to add a few things here and there.

However I learnt a few things.

1. Inheritance , and superclassing , which I did use for the first time in my codes ( yeah screw me for that) . For those who dont know what it is (including me) , it is by which you built a basic template of a class , and you use this template to built similar classes , rather than writing those classes again.

Let us examine each cycle seperately:

1 . Otto Cycle

An idealized cycle is similar to one that is used in a four stroke engine.  Compression ,  Heat input , Expansion and then Heat Output where the exhaust gases move out. This is the graph I obtained using matplotlib.

As one can see the first process is adiabatic compression(ideal) , the second process is one in      which the volume is kept constant and is sparked so that the pressure rise is massive . The third process is one in which the high pressure makes the piston move and do work and at the end the residue  gases are released and the piston comes to the original position .

2 . Diesel Cycle

The main difference is here that the heat input is done at constant pressure , rather than at  constan  volume , hot fuel is injected , rather than heating it with a spark , and it is open to  the atmosphere. Diesel cycles are said to have lowest specific fuel combustion

3 . Dual Cycle

The Dual cycle , heat is given partly at constant pressure , and partly at constant volume , so the fuel can be completely be burnt. As can be seen in the graph the green line represents it being done at constant volume , and the red line at constant pressure

As for now my user interface built using pyqt4 looks like this.

Thats all in this post . Sorry for not explaining the code as the post is already pretty long.

Simulation of Rankine Cycle

If you are a mechanical engineer continue reading. If you are not then please still continue reading because you have taken efforts to click on the link.

So coming to the point , a Rankine cycle is a cycle that according to wiki , generates 90% of the electric power across the world. Before , the simulation part , let me just give a run through of what the cycle actually contains .

1 . Something that has to do work – a Turbine .

2 . Something that needs to compress the water -  a Condenser

3 . Something that has to increase the pressure of the water – a Pump , and a boiler which supplies heated steam to the turbine .

There are also three different types of process , simple , reheat and regenerative , which Ill be explaining later

I wanted to simulate the actual cycle , so I used PyQt4 (I shifted from PyGtk , Why? , Ill save that for another post) , and matplotlib ( a python library used for plotting graphs)

So this is how my GUI looks like  before and after simulation .

This is the graph that I obtained using matplotlib for the normal cycle.

From the graph one can observe the following things.

1 . The outpu of the turbine as far as possible should be in the saturation state , or else the condenser line wont be straight.

2 . Pump Work is almost negligible( I couldnt get values for the compressed state of water , so that shows to take it to the saturated liquid region. )

The graph obtained for the reheat cycle.

Reheat is basically sending the output of a high pressure turbine back to the boiler , heated , and  delivered back to another turbine at a lower pressure.

The principle reason behind is to make sure that the condenser input is as saturated as possibele.

Regenerative Cycle

Regenerative is when you use a heat exchanger in between to send the water to the boiler in a heated state again , so that it decreases the heat and increases the efficiency .

It can be clearly seen from the graph that the water heater functions at a different pressure given by the violet line

Things to do :

1 . Do extensive testing to see if my app is valid for all input values .

2 . Do both reheat and regenerative together and let the user choose the number of feed water heaters .

3. Extend the app to other cycles like Brayton e.t.c

4.Do stuff other than GUI Programming which I have been doing for a very long time now.

Thanks for reading.

Installing Orange in Ubuntu – 12.04

When it comes to installing a python – package in linux , most of the times you just need to do this.

sudo apt-get install python-package

or you could download an archive and go to the downloaded folder and do

python setup.py install

However I faced a lot of trouble while installing the python package Orange.I downloaded the nightly builds from this directory orange.biolab.si/download/orange-source-snapshot-hg-2012-09-24.zip and tried setup.py install. But it simply failed to install.

I also tried other stuff like going to the directory and doing

cd source
make

It terminated with the following statement .

make: *** No targets specified and no makefile found. Stop.

After spending a bit of time googling , Google finally gave me an answer

1 . Install all dependencies

sudo apt-get install python-numpy
sudo apt-get install python-qt4
sudo apt-get install python-dev

2 . Add the following lines to your /etc/apt/sources.list file . This file gives you the sources from which you can download the packages.

sudo gedit /etc/apt/sources.list
deb http://orange.biolab.si/debian squeeze main
deb-src http://orange.biolab.si/debian squeeze main

3.Then do this

sudo aptitude install-orange canvas

4.Then go to your python shell and do

import orange

Congrats.Orange is now successfully installed in your computer.

Edit : If this doesnt work , then try


sudo apt-get update

sudo apt-get install orange-canvas

Follow

Get every new post delivered to your Inbox.