|
From: pmarie-dit-dalet <phi...@ac...> - 2011-03-16 10:28:12
|
#! /usr/bin/python
# -*- coding: utf-8 -*-
from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Tahoma']
from PythonCard import dialog, graphic, log, model
import matplotlib.mathtext as mathtext
import matplotlib as mpl
import locale,os,sys
import time
import ConfigParser
import codecs
import locale
import threading
from scipy import *
from scipy.optimize import fsolve
import wx, wx.html
from wx import ScreenDC, EmptyBitmap, MemoryDC,NullBitmap
VER="0.8"
reload(sys)
sys.setdefaultencoding('utf-8')
localcoding=locale.getdefaultlocale()[1]
aboutText = u"""<p><img style="width: 96px; height: 96px;" alt=""src="ava.png"><br>
<br>Avancement.py V %(version)s <br> écrit en python<br>
<br>DALET Philippe<br>Laboratoire Physique-Chimie<br>avenue pezet<br>46100 FIGEAC<br>FRANCE<br><br>
<a href="mailto:phi...@ac...?subject=Evenement">phi...@ac...</a><br><br>
<a href="http://sourceforge.net/projects/gpib82357a/">http://sourceforge.net/projects/gpib82357a/</a></p>"""
class LaTex:
def __init__(self, rawText, filename):
self.laTexParser = mathtext.MathTextParser('Bitmap')
mpl.rcParams['mathtext.default'] = 'rm'
self.laTexParser.to_png(filename, rawText, color='black', dpi=120, fontsize=8)
class MyTimer:
def __init__(self, tempo, target, args= [], kwargs={}):
self._target = target
self._args = args
self._kwargs = kwargs
self._tempo = tempo
def _run(self):
self._timer = threading.Timer(self._tempo, self._run)
self._timer.start()
self._target(*self._args, **self._kwargs)
def start(self):
self._timer = threading.Timer(self._tempo, self._run)
self._timer.start()
def stop(self): self._timer.cancel()
class HtmlWindow(wx.html.HtmlWindow):
def __init__(self, parent, id, size=(600,400)):
wx.html.HtmlWindow.__init__(self,parent, id, size=size)
if "gtk2" in wx.PlatformInfo: self.SetStandardFonts()
def OnLinkClicked(self, link):wx.LaunchDefaultBrowser(link.GetHref())
class AboutBox(wx.Dialog):
def __init__(self):
wx.Dialog.__init__(self, None, -1, 'Au sujet de',
style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL)
hwin = HtmlWindow(self, -1, size=(400,1200))
vers = {}
vers["version"] = VER
hwin.SetPage(aboutText % vers)
btn = hwin.FindWindowById(wx.ID_OK)
irep = hwin.GetInternalRepresentation()
hwin.SetSize((irep.GetWidth()+25, irep.GetHeight()+10))
self.SetClientSize(hwin.GetSize())
self.CentreOnParent(wx.BOTH)
self.SetFocus()
class MyBackground(model.Background):
def on_initialize(self,event):
# config
self.project=u""
if (len(sys.argv) == 2):
if (os.path.isfile(sys.argv[1]) == True):
self.project=sys.argv[1].decode(localcoding)
self.ini=ConfigParser.ConfigParser()
self.ini.readfp(open('avancement.ini'))
if (self.project==u""):
st= self.ini.get('settings','project').decode('utf-8')
if (os.path.isfile( self.ini.get('settings','project').decode('utf-8') ) == True): self.project=self.ini.get('settings','project').decode('utf-8')
else: self.project=u"avancement.ava"
self.Print (u"Projet %s chargé" %self.project)
self.prj=ConfigParser.ConfigParser()
self.prj.readfp(open(self.project))
self.nA=self.prj.get('settings','nA') ; self.components.nA.SetValue(self.nA)
self.nB=self.prj.get('settings','nB') ; self.components.nB.SetValue(self.nB)
self.nC=self.prj.get('settings','nC') ; self.components.nC.SetValue(self.nC)
self.nD=self.prj.get('settings','nD') ; self.components.nD.SetValue(self.nD)
self.K =self.prj.get('settings','k') ; self.components.K.SetValue(self.K)
self.strA =self.prj.get('settings','strA') ; self.A=self.GenerateImage(self.strA,'A')
self.strB =self.prj.get('settings','strB') ; self.B=self.GenerateImage(self.strB,'B')
self.strC =self.prj.get('settings','strC') ; self.C=self.GenerateImage(self.strC,'C')
self.strD =self.prj.get('settings','strD') ; self.D=self.GenerateImage(self.strD,'D')
self.strE =self.prj.get('settings','strE') ; self.E=self.GenerateImage(self.strE,'E')
self.V = self.prj.get('settings','V')
self.solution=self.prj.get('settings','solution')
self.titre = self.prj.get('settings','titre').decode('utf-8')
self.Update()
#debug
def OnKeyPress (self, evt):
print ('hello')
def Print (self, str):self.components.console.appendText(str+'\r\n')
def GenerateImage(self, str, k):
m = LaTex("$"+str+"$","./images/image"+k+".png")
if (k=='A'):
self.components.ImageButtonA._setFile (self.components.ImageButtonA._getFile ())
self.components.ImageButtonA._setBitmap( self.components.ImageButtonA._getBitmap() )
elif (k=='B'):
self.components.ImageButtonB._setFile (self.components.ImageButtonB._getFile ())
self.components.ImageButtonB._setBitmap( self.components.ImageButtonB._getBitmap() )
elif (k=='C'):
self.components.ImageButtonC._setFile (self.components.ImageButtonC._getFile ())
self.components.ImageButtonC._setBitmap( self.components.ImageButtonC._getBitmap() )
elif (k=='D'):
self.components.ImageButtonD._setFile (self.components.ImageButtonD._getFile ())
self.components.ImageButtonD._setBitmap( self.components.ImageButtonD._getBitmap() )
else :
self.components.ImageButtonE._setFile (self.components.ImageButtonE._getFile ())
self.components.ImageButtonE._setBitmap( self.components.ImageButtonE._getBitmap() )
if (str[0].isdigit()==False):
if (str[0].isdigit()=='.'): return '0'
else: return '1'
else: return str[0]
def on_ImageButtonA_mouseClick(self, event):
result = dialog.textEntryDialog(self, u'Entrer le nom en LAtex',u'Espèce chimique', self.strA)
if (result.accepted==True): self.strA = result.text; self.A=self.GenerateImage(self.strA,'A')
self.Update()
def on_ImageButtonB_mouseClick(self, event):
result = dialog.textEntryDialog(self, u'Entrer le nom en LAtex',u'Espèce chimique', self.strB)
if (result.accepted==True): self.strB = result.text; self.B=self.GenerateImage(self.strB,'B')
self.Update()
def on_ImageButtonC_mouseClick(self, event):
result = dialog.textEntryDialog(self, u'Entrer le nom en LAtex',u'Espèce chimique', self.strC)
if (result.accepted==True): self.strC = result.text; self.C=self.GenerateImage(self.strC,'C')
self.Update()
def on_ImageButtonD_mouseClick(self, event):
result = dialog.textEntryDialog(self, u'Entrer le nom en LAtex',u'Espèce chimique', self.strD)
if (result.accepted==True): self.strD = result.text; self.D=self.GenerateImage(self.strD,'D')
self.Update()
def on_ImageButtonE_mouseClick(self, event):
result = dialog.textEntryDialog(self, u'Entrer le texte en LAtex',u' = ', self.strE)
if (result.accepted==True): self.strE = result.text; self.E=self.GenerateImage(self.strE,'E')
self.Update()
def Refresh(self):
self.nA = self.components.nA.GetValue(); self.prj.set('settings','nA',self.nA)
self.nB = self.components.nB.GetValue(); self.prj.set('settings','nB',self.nB)
self.nC = self.components.nC.GetValue(); self.prj.set('settings','nC',self.nC)
self.nD = self.components.nD.GetValue(); self.prj.set('settings','nD',self.nD)
self.K = self.components.K.GetValue(); self.prj.set('settings','K',self.K)
self.prj.set('settings','strA',self.strA)
self.prj.set('settings','strB',self.strB)
self.prj.set('settings','strC',self.strC)
self.prj.set('settings','strD',self.strD)
self.prj.set('settings','strE',self.strE)
self.prj.set('settings','V' ,self.V)
self.prj.set('settings','titre',self.titre)
self.prj.set('settings','solution',self.solution)
self.ini.set('settings','project',self.project)
def func(self,x):
A=int(self.A);B=int(self.B);C=int(self.C);D=int(self.D)
V=float(self.V);K=float(self.K)
nA=float(self.nA);nB=float(self.nB);nC=float(self.nC);nD=float(self.nD)
ch1="_{(l)}";ch2="_{(s)}";ch3="_{(g)}"
if (ch1 in self.strA or ch2 in self.strA or ch3 in self.strA): A=0
if (ch1 in self.strB or ch2 in self.strB or ch3 in self.strB): B=0
if (ch1 in self.strC or ch2 in self.strC or ch3 in self.strC): C=0
if (ch1 in self.strD or ch2 in self.strD or ch3 in self.strD): D=0
return ( (nA-A*x)**A ) * ( (nB-B*x)**B ) - ( (nC+C*x)**C )*( (nD+D*x)** D ) * (V**(A+B-C-D)) / K
def Quotient(self):
A=int(self.A);B=int(self.B);C=int(self.C);D=int(self.D)
V=float(self.V);K=float(self.K)
nA=float(self.nA);nB=float(self.nB);nC=float(self.nC);nD=float(self.nD)
ch1="_{(s)}";ch2="_{(g)}"
if (ch1 in self.strA or ch2 in self.strA): A=0
if (ch1 in self.strB or ch2 in self.strB) : B=0
if (ch1 in self.strC or ch2 in self.strC): C=0
if (ch1 in self.strD or ch2 in self.strD): D=0
if (self.solution=="1"):
ch3="H_{2}O_{(l)}"
if (ch3 in self.strA): A=0
if (ch3 in self.strB): B=0
if (ch3 in self.strC): C=0
if (ch3 in self.strD): D=0
ch3="H^{+}"; ch4 ="HO^{-}"
if (ch3 in self.strE or ch4 in self.strE): # milieu acide ou basique
E=int(self.E)
nE=1.0 #valeur par defaut
return (nC**C)*(nD**D)/( (nA**A)*(nB**B)*(nE**E)) * (V**(A+B-C-D))
return (nC**C)*(nD**D)/( (nA**A)*(nB**B) ) * (V**(A+B-C-D))
def on_nA_loseFocus(self, event): self.nA = self.components.nA.GetValue() ; self.Update()
def on_nB_loseFocus(self, event): self.nB = self.components.nB.GetValue() ; self.Update()
def on_nC_loseFocus(self, event): self.nC = self.components.nC.GetValue() ; self.Update()
def on_nD_loseFocus(self, event): self.nD = self.components.nD.GetValue() ; self.Update()
def on_K_loseFocus (self, event): self.K = self.components.K.GetValue() ; self.Update()
def Form(self, a):
if (a==0.): return ("%1.1f")
elif(a <0.001): return ("1.2E")
else: return ("%1.3f")
def Update (self):
xf = fsolve(self.func,0.)
if (xf <0): self.Print (u"Error Equation Solving"); xf = 0.0
str = "x = %1.6f mol" %(xf)
self.components.Xf.SetValue(str)
if (self.A=='1'): str="%1.6f - x" %(float(self.nA))
else: str="%1.6f - %s.x" %(float(self.nA),self.A)
str1="%1.6f mol" %(float(self.nA)-int(self.A)*xf)
self.components.nAC.SetValue(str)
self.components.nAE.SetValue(str1)
if (self.B=='1'): str="%1.6f - x" %(float(self.nB))
else: str="%1.6f - %s.x" %(float(self.nB),self.B)
str1="%1.6f mol" %(float(self.nB)-int(self.B)*xf)
self.components.nBC.SetValue(str)
self.components.nBE.SetValue(str1)
if (self.C=='1'): str="%1.6f + x" %(float(self.nC))
else: str="%1.6f + %s.x" %(float(self.nC),self.C)
str1="%1.6f mol" %(float(self.nC)+int(self.C)*xf)
self.components.nCC.SetValue(str)
self.components.nCE.SetValue(str1)
if (self.D=='1'): str="%1.6f + x" %(float(self.nD))
else: str="%1.6f + %s.x" %(float(self.nD),self.D)
str1="%1.6f mol" %(float(self.nD)+int(self.D)*xf)
self.components.nDC.SetValue(str)
self.components.nDE.SetValue(str1)
xmax1=float(self.nA)/int(self.A)
xmax2=float(self.nB)/int(self.B)
if (xmax1<xmax2):
xmax=xmax1
self.components.nAM.SetValue("0.000000 mol")
val=float(self.nB) - int(self.B)*xmax
if (val <1.0): str= '%1.6f mol' %val
else: str= '%1.6f mol' %val
self.components.nBM.SetValue(str)
else:
xmax=xmax2
self.components.nBM.SetValue("0.000000 mol")
val=float(self.nA) - int(self.A)*xmax
if (val <1.0): str= '%1.6f mol' %val
else: str= '%1.6f mol' %val
self.components.nAM.SetValue(str)
str = "x = %1.6f mol" %(xmax)
self.components.Xmax.SetValue(str)
val=float(self.nC) + int(self.C)*xmax
if (val <1.0): str= '%1.6f mol' %val
else: str= '%2.6f mol' %val
self.components.nCM.SetValue(str)
val=float(self.nD) + int(self.D)*xmax
if (val <1.0): str= '%1.6f mol' %val
else: str= '%2.6f mol' %val
self.components.nDM.SetValue(str)
V=float(self.V)
self.Print (u"Vtotal= %3.3f L" %V )
Qri=self.Quotient()
self.Print (u"Quotient de réation initiale Qr,i= %2.9f" %Qri)
self.Print (u"Constante d'équilibre K= %s" %self.K)
if (float(self.K)>Qri): self.Print (u"Evolution du système chimique dans le sens direct")
else: self.Print (u"Evolution du système chimique dans le sens inverse")
self.Print (u"xf= %f mol" %xf)
self.Print (u"xmax= %f mol" %xmax)
self.Print (u"taux d'avancement final= %2.1f %%" %(xf/xmax*100))
chaine="H_{3}O^{+}"
if (chaine in self.strA): pH=-log10( (float(self.nA)-int(self.A)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
if (chaine in self.strB): pH=-log10( (float(self.nB)-int(self.B)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
if (chaine in self.strC): pH=-log10( (float(self.nC)+int(self.C)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
if (chaine in self.strD): pH=-log10( (float(self.nD)+int(self.D)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
chaine="HO^{-}"
if (chaine in self.strA): pH=14+log10( (float(self.nA)-int(self.A)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
if (chaine in self.strB): pH=14+log10( (float(self.nB)-int(self.B)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
if (chaine in self.strC): pH=14+log10( (float(self.nC)+int(self.C)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
if (chaine in self.strD): pH=14+log10( (float(self.nD)+int(self.D)*xf)/V);self.Print (u"pH = %2.2f" %(pH))
self.SetTitle(u"Tableau d'avancement - %s" %self.titre)
def on_menuAbout_select(self, event):
dlg = AboutBox()
dlg.ShowModal()
dlg.Destroy()
def on_menuSolution_select(self, event):
dlg = wx.MessageDialog( None,u"En solution aqueuse", "", wx.YES_NO | wx.ICON_QUESTION)
result = dlg.ShowModal() == wx.ID_YES
if (result ==True): self.solution="1"
else: self.solution="0"
dlg.Destroy()
def on_menuHelp_select(self, event):
msg=u"""
* Cliquez sur les coefficients stoechiométriques, K la constante d'équilibre et les quantités de matière initiales afin de pouvoir les modifier (couleur bleue)
* Cliquez sur les formules des espèces chimiques et entrez la formule en LAtex (Voir Menu : LAtex aide)
* Dans le menu Fichier, n'oubliez pas d'entrer le volume total de la solution pour calculer correctement l'équilibre.
* Au dessus du "=" de la transformation chimique il y a un bouton type image permettant d'inscrire un texte en LAtex comme 6H+ (ou 2HO-)
[H+] est fixé par défaut pour le calcul de Qr.
* Pour toute réaction où l'eau est un réactif (ex hydrolyse) ne pas mettre la réaction en solution (Menu fichier: Solution aqueuse ?)
* dans le dossier \database, des fiches de calcul .sm (format smathstudio) vous permettent de calculer les quantités de matière. D'autres fichiers projet .ava sont présents.
"""
dialog.scrolledMessageDialog(self, msg, u"Aide")
def on_menuLAtex_select(self, event):
msg=u""" _ signifie un indice. Le texte correspondant à l'indice doit être placé entre les crochets {}
ex: méthane CH_{4}
^ signifie exposant. Le texte correspondant à l'exposant doit être placé entre les crochets {}
ex: ion oxonium 2\ H_{3}O^{+}_{(aq)}
\ signifie espace !! laissez un blanc après \
ex: milieu\ acide
* Cliquer sur le symbole (qui est en réalité un Bouton de type Image) et entrer le texte en LAtex: une image sera alors générée
"""
dialog.scrolledMessageDialog(self, msg, u"Latex Aide")
def Quit(self):
self.Refresh()
fpi=open('avancement.ini','w'); self.ini.write(fpi)
fpp=open(self.project,"w"); self.prj.write(fpp)
self.Close()
def on_Quit_mouseClick(self, event): self.Quit()
def on_menuFileExit_select(self, event): self.Quit()
def on_menuJPG_select(self, event):
result = dialog.saveFileDialog(wildcard=u"Jpeg fichiers (*.jpg)|*.jpg")
if (result.accepted==True):
if result.paths[0].rfind('.jpg') ==-1: result.paths[0]+='.jpg'
if sys.platform == 'win32':
self.Tim = MyTimer(2.0, self.PrintScr, [result.paths[0]])
self.Tim.start()
else:
self.PrintScr(result.paths[0])
def on_menuSaveProject_select(self, event):
result = dialog.saveFileDialog(wildcard=u"Ava fichiers (*.ava)|*.ava")
if (result.accepted==True):
self.Refresh()
self.project=result.paths[0]
fp=open(self.project,"w"); self.prj.write(fp)
self.Print (u"Projet %s sauvé" %self.project)
def on_menuVolume_select(self, event):
result = dialog.textEntryDialog(self, u'Entrer le volume en L',u' Volume total de la solution ', self.V)
if (result.accepted==True): self.V = result.text
self.Print (u"Vtotal= %f L" %float(self.V) )
def on_menuTitle_select(self, event):
result = dialog.textEntryDialog(self, u'Entrer le Titre',u' Titre de la réaction ', self.titre.decode('utf-8'))
if (result.accepted==True):
self.titre = result.text
self.SetTitle(u"Tableau d'avancement - %s" %self.titre)
def on_cls_select(self, event): self.components.console.clear()
def on_menuLoadProject_select(self, event):
result = dialog.openFileDialog(wildcard=u"Ava fichiers (*.ava)|*.ava")
if (result.accepted==True):
self.prj.readfp(open(result.paths[0]))
self.project=result.paths[0]
self.components.console.clear()
self.nA=self.prj.get('settings','nA') ; self.components.nA.SetValue(self.nA)
self.nB=self.prj.get('settings','nB') ; self.components.nB.SetValue(self.nB)
self.nC=self.prj.get('settings','nC') ; self.components.nC.SetValue(self.nC)
self.nD=self.prj.get('settings','nD') ; self.components.nD.SetValue(self.nD)
self.K =self.prj.get('settings','K') ; self.components.K.SetValue(self.K)
self.strA =self.prj.get('settings','strA') ; self.A=self.GenerateImage(self.strA,'A')
self.strB =self.prj.get('settings','strB') ; self.B=self.GenerateImage(self.strB,'B')
self.strC =self.prj.get('settings','strC') ; self.C=self.GenerateImage(self.strC,'C')
self.strD =self.prj.get('settings','strD') ; self.D=self.GenerateImage(self.strD,'D')
self.strE =self.prj.get('settings','strE') ; self.E=self.GenerateImage(self.strE,'E')
self.titre = self.prj.get('settings','titre')
self.solution=self.prj.get('settings','solution')
self.V = self.prj.get('settings','V')
self.Print (u"Projet %s chargé" %self.project)
self.Update()
def PrintScr(self,str):
if sys.platform == 'win32':
self.Tim.stop()
else:
time.sleep( 5 )
rect = self.GetRect()
if sys.platform == 'linux2':
client_x, client_y = self.ClientToScreen((0, 0))
border_width = client_x - rect.x
title_bar_height = client_y - rect.y
rect.width += (border_width * 2)
rect.height += title_bar_height + border_width
dcScreen = wx.ScreenDC() #Create a DC for the whole screen area
bmp = wx.EmptyBitmap(rect.width, rect.height)
memDC = wx.MemoryDC() #Create a memory DC that will be used for actually taking the screenshot
#Tell the memory DC to use our Bitmap
#all drawing action on the memory DC will go to the Bitmap now
memDC.SelectObject(bmp)
#Blit (in this case copy) the actual screen on the memory DC
#and thus the Bitmap
memDC.Blit( 0, 0, rect.width, rect.height, dcScreen, rect.x, rect.y )
#Select the Bitmap out of the memory DC by selecting a new
#uninitialized Bitmap
memDC.SelectObject(wx.NullBitmap)
img = bmp.ConvertToImage()
img.SaveFile(str, wx.BITMAP_TYPE_JPEG)
self.Print(u"Fichier %s généré" %str)
if __name__ == '__main__':
app = model.Application(MyBackground)
app.MainLoop()
|