I wrote more than 200 lines of Ghpython codes,including one main program and 7 functions constructed by dictionary data structure.I have imported several necessary ghpython function pakages ,such as scriptcontext,rhinoscriptsyntax,ghpythonlib.components,Rhino.Geometry and so on.But it spent about ten seconds every time in finishing all.I want it done less than one second.GH_CPython has been unsuccessfully used to solve the problem because it can not import ghpython pakages metioned above.And I have tried to import numba to sort it out via installing Anacond3 which also confused me,failling at end.I use rhino6 and the grasshopper version is 1.0.0007.So how can I do to speed up my codes?
Please help me. Thank you all.
Iâll try it with some chinese fortune cookie wisdoms:
The better the question the higher the chance to speed up your definition.
The slowest part of your computer is yourself.
Donât blame a Rhino if you donât understand the Python
Hi,
âMake it run, make it right, make it fastâ
Thatâs a good first step : if your program runs correctly as it is then it is time to start thinking about speed. Here are some tips on improving performance in Python:
https://wiki.python.org/moin/PythonSpeed
If you can identify the parts of your program that are taking a long time then you can see where to concentrate on improvements.
Dictionaries can be very quick if used in the right way. In particular it may be quicker to use the iteritems(), iterkeys(), itervalues() methods rather than their list based equivalents. Checking presence of a key in a dict (mykey in mydict) is much quicker than checking presence in a list (mykey in mydict.keys())
Thanks for your reply.I will describle the problem more details.
I successfully intalled numba.py at "E:\ProgramData\Anaconda3\Lib\site-packages\blaze\compute"via Anaconda3 and copyed it into âC:\Program Files\Rhino 6\Plug-ins\IronPython\Libâ .But when I imported numba in ghpython interface,it turned out âRuntime error(ImportException):No module named numpyâ.I guess ghpython needs something else to recongnize it.Thank you all the same.
Hi Dancergraham,
Thank you for your suggestions.I used dictionary to store the data like {0:PolylineA,1:PolylineB,2:PolylineC,3:PolylineD} and used the structure âfor iValue in Dict.values():â to traverse the values.I will check again and optimize them more careful.
Best regards,
Yuxiang Ni
Yes you cannot install numpy in ironpython as far as I am aware. You could run a Cpython programme as a separate process with the subprocess module but the interface is a little tricky and you lose some time with startup.
And do you need to traverse all the values (e.g. to operate on all of them) or can you break out of the loop once you find a particular value (e.g. once you find the one you are looking for?)
In the latter case, using for iValue in Dict.itervalues() and then using break once youâve found your object will save you time. itervalues() saves you memory as well relative to .values()
Hi Dancergraham,
Thank you so much.I have once intalled Cpython to speed up,but it could not import ghpython packages.The most effect method I want is to import some functions like numba.jit to make codes quicker.Checking the program,I will change .values() into .itervalues() as you recommend and break out of the loop if necessary.
Much appreciated,
Yuxiang Ni
Rhino/Gh are using IronPython, because both are using âRhinocommonâ a C# library (which again accesses C++ libraries). IronPython is basically dot.net with Python Syntax, useful if you deal with dot.net libs.
Numpy is not supported for IronPython. Youâll need to use an equivalent dot.net library like âMath.Netâ.
That also means CPython component does not support calling Rhinocommon and as such cannot access its functionality.
Anyway I doubt its your calculation which takes 10 minutes to perform. If you post code, we can have a look at it. But without any clue about the problem, its impossible to give you advice about speed improvements. Currently it seems you are rather looking for micro-optimization which isnât helpful. Often problems are on completely different spots.
Hi Tom,
Thanks for your detailed reply from my bottom of my heart.Your answers make me understand much more
about Ghpython as well as CPython,and your guess is right.Itâs very nice for you,but the calculating time is about 10 seconds not 10 minutes.Thread package may help to save the time as far as I know.My program not only needs the ghpython codes but also the rhino3D model to accomplish the perform.I will be very appreciated if you may give me your email.My codes is aimed to slove position between plans.Focusing on centerpoints of plans,I carefully study the relationship and find that the position between one and the other is an approximate polyline which I name as âTrajectoryâ.So the program is to construct the trajectories and
unionboolean them together,after which find one point on the unioned trajectory as a target centerpoint and move the next plan to it.Creat such a loop until the plans run out or cannot find a point on the unioned polyline.
Here are my main lines and the steps.Dict_UnionTraCursSta is a dictionary to store the trajectories between each other.I have defined several functions myself like Func_JudgeLength,Func_TraCur,SouthLineSelf,SouthLineWorld,Func_TraUniBooPts,Func_ConfirmPlan,whose respective functions are like their names.
Best wishes,
Yuxiang Ni
The input parameters are:
List Access:Angle_input,Pt_inputidex,Curve_RBHigh,Curve_RBMid,Curve_RBLow,Plan_High,Plan_Mid,Plan_Low,List_PlanExistence;
Item Access:Num_DivUniTra
The outcome parameters are:
a,b
Dict_PlanStandby,Dict_PlanExistence,Dict_RB,Dict_Plan,Dict_PlanData,Dict_UnionTraCursSta,Dict_PlanDataArea,Dict_PtCenOri = {},{},{},{},{},{},{},{}#Dict_Plan = {0;[HighArea1,HighArea2],1:[Midarea1,MidArea2],2:[LowArea1,LowArea2]}
for iHigh in xrange(len(Curve_RBHigh)):
Dict_RB.setdefault(0,{})[iHigh]=Curve_RBHigh[iHigh]
for iMid in xrange(len(Curve_RBMid)):
Dict_RB.setdefault(1,{})[iMid]=Curve_RBMid[iMid]
for iLow in xrange(len(Curve_RBLow)):
Dict_RB.setdefault(2,{})[iLow]=Curve_RBLow[iLow]
Dict_SunDis = {0:[45,45,45],1:[35,25,25],2:[20,15,10]}#0-High,1-Mid,2-Low,"0:[30,30,30]"means"High:[High,Mid,Low]"
Dict_HorDis= {0:[13,13,13],1:[13,8,8],2:[13,6,6]}#Num_column:[Raw_0,Raw_1,Raw_2]
for m in xrange(len(List_Standby)):
Dict_PlanStandby[m] = List_Standby[m]
for n in xrange(len(List_PlanExistence)):
Dict_PlanExistence[n] = List_PlanExistence[n]
for jHigh in xrange(len(Plan_High)):
Area_PlanHigh = int(rs.CurveArea(Plan_High[jHigh])[0])
Dict_Plan.setdefault(0,{})[jHigh] = Area_PlanHigh
Dict_PlanDataArea[jHigh] = Area_PlanHigh#Dict_PlanDataArea is used to judge which the Plan_Input is
Dict_PlanData[jHigh] = Plan_High[jHigh]#Dict_PlanData is used to prepare for the Dict_UnionTraCursSta
for jMid in xrange(len(Plan_Mid)):
Area_PlanMid = int(rs.CurveArea(Plan_Mid[jMid])[0])
Dict_Plan.setdefault(1,{})[jMid] = Area_PlanMid
Dict_PlanDataArea[len(Plan_High)+jMid] = Area_PlanMid
Dict_PlanData[len(Plan_High)+jMid] = Plan_Mid[jMid]
for jLow in xrange(len(Plan_Low)):
Area_PlanLow = int(rs.CurveArea(Plan_Low[jLow])[0])
Dict_Plan.setdefault(2,{})[jLow] = Area_PlanLow#Dict_Plan is used to judge the High/Mid/Low of RB and so on
Dict_PlanDataArea[len(Plan_High)+len(Plan_Mid)+jLow] = Area_PlanLow#Dict_PlanDataArea is used to find the key via area
Dict_PlanData[len(Plan_High)+len(Plan_Mid)+jLow] = Plan_Low[jLow]#Dict_PlanData is used to construct n*n trajectories
#8.2.Construct the n*n trajectories named as Dict_UnionTraCursSta
for iValue in xrange(len(Dict_PlanData)):#As the Plan_Base
Dict_PtCenOri[iValue] = rs.CurveAreaCentroid(Dict_PlanData.values()[iValue])[0]
for jValue in xrange(len(Dict_PlanData)):#As the Plan_Input
Length_ijSta = Func_JudgeLength(Dict_RB,Dict_SunDis,Dict_HorDis,Dict_Plan,Dict_PlanData.values()[iValue],Dict_PlanData.values()[jValue])#Length_ijSta[3] is the RedBoundary
Tra_CurSingleSta = Func_TraCur(Dict_PlanData.values()[iValue],Dict_PlanData.values()[jValue],0,Length_ijSta[0],Length_ijSta[1],Length_ijSta[2],Length_ijSta[3])
Dict_UnionTraCursSta.setdefault(iValue,{})[jValue]=Tra_CurSingleSta
#10.Main program:Fistly,find the correct trajectory via Key_Input and Key_Base;Secondly,move the Tra to the Plan_Base one by one;Thirdly,union all of the Tras
#Fourthly,judge whether the Plan_input is overflow based on the pts on UnionTraCurs
Dict_KeyExi,Dict_KeySta,Dict_UpdateTemp = {},{},{}
for i in xrange(len(Dict_PlanStandby)):
Dict_UnionTraCurs = {}#Store the trajectory
Area_PlanSta = int(rs.CurveArea(Dict_PlanStandby.values()[i])[0])
Key_Input = {vSta:kSta for kSta,vSta in copy.deepcopy(Dict_PlanDataArea).iteritems()}[Area_PlanSta]
Pt_CenterSta = rs.CurveAreaCentroid(Dict_PlanStandby.values()[i])[0]#Pt_CenterSta help move Plan_Standby to move to Pts[Pt_inputidex]
for j in xrange(len(Dict_PlanExistence)):
Area_PlanExi = int(rs.CurveArea(Dict_PlanExistence.values()[j])[0])
Pt_jCenterBase = rs.CurveAreaCentroid(Dict_PlanExistence.values()[j])[0]
Key_Base = {vExi:kExi for kExi,vExi in copy.deepcopy(Dict_PlanDataArea).iteritems()}[Area_PlanExi]
Cur_TraOri = Dict_UnionTraCursSta[Key_Base][Key_Input]#Fistly,find the Trajectory between NO.i and NO.j
Line_rot0 = SouthLineSelf(Dict_PlanExistence.values()[j])#Calculate the angle of the Plan_base to rotate the Dict_Trajectory
rs.ReverseCurve(Line_rot0)
Line_rotbase0 = SouthLineWorld(Dict_PlanExistence.values()[j])
Angle_rot0 = rs.Angle2(Line_rot0,Line_rotbase0)[0]
if ghcomp.CurveClosestPoint(rs.CurveEndPoint(Line_rot0),Line_rotbase0)[2] < ghcomp.CurveClosestPoint(rs.CurveStartPoint(Line_rot0),Line_rotbase0)[2]:
Angle_rot0 = Angle_rot0*(-1)
Cur_TraTemp = rs.CopyObject(Cur_TraOri,rs.VectorCreate(Pt_jCenterBase,Dict_PtCenOri.values()[Key_Base]))
Tra_SingleFin = rs.RotateObject(Cur_TraTemp,Dict_PtCenOri.values()[Key_Base],Angle_rot0)#Secondly,copy Cur_TraOri and move it to the Pt(named as Dict_PtCenOri.itervalues()[Key_Base])
Dict_UnionTraCurs[j] = Tra_SingleFin
if len(Dict_PlanExistence) == 1:
UnionTraCurs = Dict_UnionTraCurs.values()
if len(Dict_PlanExistence) > 1:
UnionTraCurs = rs.CurveBooleanUnion(Dict_UnionTraCurs.values())#Thirdly,union all of the Tras
for key,value in Dict_Plan.iteritems():
if int(rs.CurveArea(Dict_PlanStandby.values()[i])[0]) in value.itervalues():
Curve_RedBoundaryFin = Dict_RB[key].values()
Dict_PtsFinal = Func_TraUniBooPts(UnionTraCurs,Num_DivUniTra,Dict_PlanStandby.values()[i],Curve_RedBoundaryFin)#Func_TraUniBooPts return a dictionary
if Dict_PtsFinal:#Fourthly,judge whether the Plan_input is overflow
Plan_FinalInput = Func_ConfirmPlan(Dict_PlanStandby.values()[i],Angle_input[i],Dict_PtsFinal.values(),Pt_inputidex[i])
Dict_UpdateTemp[1000+i] = Plan_FinalInput#Just be different
Dict_PlanExistence.update(Dict_UpdateTemp)
else:
break
if len(List_PlanExistence)+len(List_Standby) == len(Dict_PlanExistence):
a = True
else:a = False
b = Dict_PlanExistence.values()
Hi,
You are very frequently using a range constructor where the following method may be quicker, clearer and more âpythonicâ, for instance in your first loop :
for m, standby in enumerate(List_Standby):
Dict_PlanStandby[m] = standby
This avoids repeatedly looking up the same values, particularly in the longer loops or those which run many times
Also I may be missing something but couldnât you simplify Dict_PlanExistence.values()[j]
to Dict_PlanExistence[j]
?
This is much quicker as it is a hash table lookup whereas your method involves creating a list on each loop. I imagine this runs a lot of times as it is in your nested i, j loop.
Hi,
Many thanks for your kind reply.I will carefully optimize the codes as your suggestions and study more about python in depth.The .itervalues() you recommend do speed up successfully.Sincerely thanks again.
Best regards,
Yuxiang Ni
This thread on the old forum also has some (perhaps unexpected) tips on how to speed up GHPython components. Mainly related to typehints and inputting/outputting large lists, not so much the actual Python code itself:
Hi,
Thanks for your reply.I will study them carefully.
Best wishes,
Yuxiang Ni