def __init__(self, G=None, vis=True, anim=False, head='BC',nCranes=2,series=None, bundler=False, twigCrack=False, observer=False): SimExtend.__init__(self,G, vis, anim, animDelay=1.2,series=series) #does some common stuff, e.g. seed #if no file to read the simulationsparameters from: setDefaultThinningParams(self.G.simParam) #sets the parameters to default values if not self.G.terrain: self.G.areaPoly=[(0,0), (25,0), (25,40), (0,40)] #default for thinning files. self.G.terrain=Terrain(G=self.G) self.G.terrain.readTrees(thinning=True) craneMax=self.G.simParam['maxCraneLength'] startPos=[random.uniform(craneMax, 25-craneMax), -4] self.m=ThinningMachine(name="thinny", sim=self, G=self.G, head=head, nCranes=nCranes,startPos=startPos, bundler=bundler,twigCrack=twigCrack) self.treeStats() #do some statistics on the trees self.activate(self.m,self.m.run()) if observer: self.o=Observer(name="obsy", sim=self, G=self.G) self.activate(self.o, self.o.run()) self.simulate(until=10000) #some simulation information: if observer: self.timeStats() """ print self.o.tstep*sum([c[1] for c in self.o.lAMoni]), 'left head active time via monitor' print self.o.tstep*sum([c[1] for c in self.o.lWBMoni]), 'left head waiting for Bundler' print self.stats['oneCraneWorkTime'], 'one crane work time' print self.stats['oneCraneWaitDriverTime'], 'one crane wait for driver time' if self.m.hasBundler: print self.stats['oneCraneWaitBundlerTime'], 'one crane wait for bundler time' if len(self.m.heads)==2: print self.o.tstep*sum([c[1] for c in self.o.rAMoni]), 'right head active time via monitor' print self.o.tstep*sum([c[1] for c in self.o.rWBMoni]), 'right head waiting for Bundler' print self.stats['twoCranesWorkTime'], 'two cranes work time' print self.stats['twoCranesWaitDriverTime'], 'two cranes wait for driver time' if self.m.hasBundler: print self.stats['twoCranesWaitBundlerTime'], 'two cranes wait for bundler time' """ self.stats['productivity']=len(self.m.trees)/self.now()*3600 self.stats['outTake']=100*len(self.m.trees)/float(len(self.G.terrain.trees)) self.stats['groundAreaRatio']=sum([t.dbh**2*pi*0.25 for t in self.m.trees])/max(1,sum([t.dbh**2*pi*0.25 for t in self.G.terrain.trees])) print "Simulation ended. Productivity: %.1f trees/hour. %.1f %% of the trees were harvested"%(len(self.m.trees)/self.now()*3600, self.stats['outTake']) print "average trees per corridor: %f average log weight in corridor: %f trees in main road: %f"%(self.avTreesPerCorr, self.avCorrTreeWeight, self.treesPerRoad) self.setQueuePerc() print self.getGeneralStatsString() if self.p: #plot self.p.terminate() if vis: plt.show()
class ThinningSim(SimExtend): """ class for a single simulation with a 1a or 2a thinning machine """ def __init__(self, G=None, vis=True, anim=False, head='BC',nCranes=2,series=None, bundler=False, twigCrack=False, observer=False): SimExtend.__init__(self,G, vis, anim, animDelay=1.2,series=series) #does some common stuff, e.g. seed #if no file to read the simulationsparameters from: setDefaultThinningParams(self.G.simParam) #sets the parameters to default values if not self.G.terrain: self.G.areaPoly=[(0,0), (25,0), (25,40), (0,40)] #default for thinning files. self.G.terrain=Terrain(G=self.G) self.G.terrain.readTrees(thinning=True) craneMax=self.G.simParam['maxCraneLength'] startPos=[random.uniform(craneMax, 25-craneMax), -4] self.m=ThinningMachine(name="thinny", sim=self, G=self.G, head=head, nCranes=nCranes,startPos=startPos, bundler=bundler,twigCrack=twigCrack) self.treeStats() #do some statistics on the trees self.activate(self.m,self.m.run()) if observer: self.o=Observer(name="obsy", sim=self, G=self.G) self.activate(self.o, self.o.run()) self.simulate(until=10000) #some simulation information: if observer: self.timeStats() """ print self.o.tstep*sum([c[1] for c in self.o.lAMoni]), 'left head active time via monitor' print self.o.tstep*sum([c[1] for c in self.o.lWBMoni]), 'left head waiting for Bundler' print self.stats['oneCraneWorkTime'], 'one crane work time' print self.stats['oneCraneWaitDriverTime'], 'one crane wait for driver time' if self.m.hasBundler: print self.stats['oneCraneWaitBundlerTime'], 'one crane wait for bundler time' if len(self.m.heads)==2: print self.o.tstep*sum([c[1] for c in self.o.rAMoni]), 'right head active time via monitor' print self.o.tstep*sum([c[1] for c in self.o.rWBMoni]), 'right head waiting for Bundler' print self.stats['twoCranesWorkTime'], 'two cranes work time' print self.stats['twoCranesWaitDriverTime'], 'two cranes wait for driver time' if self.m.hasBundler: print self.stats['twoCranesWaitBundlerTime'], 'two cranes wait for bundler time' """ self.stats['productivity']=len(self.m.trees)/self.now()*3600 self.stats['outTake']=100*len(self.m.trees)/float(len(self.G.terrain.trees)) self.stats['groundAreaRatio']=sum([t.dbh**2*pi*0.25 for t in self.m.trees])/max(1,sum([t.dbh**2*pi*0.25 for t in self.G.terrain.trees])) print "Simulation ended. Productivity: %.1f trees/hour. %.1f %% of the trees were harvested"%(len(self.m.trees)/self.now()*3600, self.stats['outTake']) print "average trees per corridor: %f average log weight in corridor: %f trees in main road: %f"%(self.avTreesPerCorr, self.avCorrTreeWeight, self.treesPerRoad) self.setQueuePerc() print self.getGeneralStatsString() if self.p: #plot self.p.terminate() if vis: plt.show() def timeStats(self): """ observe that this method performs the statcalculations on the times and sets the values to self.s.stats""" noCWforBundler=0 noCWforBundlerTwo=0 if self.m.hasBundler: self.stats['bundlingTime']=self.o.tstep*sum([c[1] for c in self.o.bundlerActiveMoni])# 'active bundler time via monitor' else: self.stats['bundlingTime']=0 if len(self.m.heads)==1: self.stats['oneCraneWorkTime']=self.o.tstep*sum([c[1] for c in self.o.lAMoni]) self.stats['oneCraneWaitDriverTime']=self.o.tstep*sum([c[1] for c in self.o.lWDMoni]) self.stats['oneCraneWaitBundlerTime']=self.o.tstep*sum([c[1] for c in self.o.lWBMoni]) self.stats['twoCranesWorkTime']=0 self.stats['twoCranesWaitDriverTime']=0 self.stats['twoCranesWaitBundlerTime']=0 for i in range(len(self.o.lWBMoni)-1): if self.o.lWBMoni[i][1]==0 and self.o.lWBMoni[i+1][1]==1: noCWforBundler+=1 self.stats['noCraneWaitings']=noCWforBundler self.stats['noCraneWaitingsTwo']=noCWforBundlerTwo elif len(self.m.heads)==2: for i in range(len(self.o.lWBMoni)-1): if self.o.lWBMoni[i][1]==0 and self.o.lWBMoni[i+1][1]==1: noCWforBundler+=1 if self.o.rWBMoni[i][1]==0 and self.o.rWBMoni[i+1][1]==1: noCWforBundler+=1 self.stats['noCraneWaitings']=noCWforBundler lAMoni=np.array(self.o.lAMoni) rAMoni=np.array(self.o.rAMoni) #t=lAMoni[:,[0]]#takes the times into one array addedActivity=lAMoni[:,[1]]+rAMoni[:,[1]] addedActivityTwo=copy.deepcopy(addedActivity) for i in range(len(addedActivity)): if addedActivity[i]==2: addedActivity[i]=0 if addedActivityTwo[i]==1: addedActivityTwo[i]=0 elif addedActivityTwo[i]==2: addedActivityTwo[i]=1 self.stats['oneCraneWorkTime']=float(self.o.tstep*sum(addedActivity)) self.stats['twoCranesWorkTime']=float(self.o.tstep*sum(addedActivityTwo)) lWDMoni=np.array(self.o.lWDMoni) rWDMoni=np.array(self.o.rWDMoni) addedWD=lWDMoni[:,[1]]+rWDMoni[:,[1]] addedWDTwo=copy.deepcopy(addedWD) for i in range(len(addedWD)): if addedWD[i]==2: addedWD[i]=0 if addedWDTwo[i]==1: addedWDTwo[i]=0 elif addedWDTwo[i]==2: addedWDTwo[i]=1 self.stats['oneCraneWaitDriverTime']=float(self.o.tstep*sum(addedWD)) self.stats['twoCranesWaitDriverTime']=float(self.o.tstep*sum(addedWDTwo)) lWBMoni=np.array(self.o.lWBMoni) rWBMoni=np.array(self.o.rWBMoni) addedWB=lWBMoni[:,[1]]+rWBMoni[:,[1]] addedWBTwo=copy.deepcopy(addedWB) for i in range(len(addedWB)): if addedWB[i]==2: addedWB[i]=0 if addedWBTwo[i]==1: addedWBTwo[i]=0 elif addedWBTwo[i]==2: addedWBTwo[i]=1 for i in range(len(addedWBTwo)-1): if addedWBTwo[i]==0 and addedWBTwo[i+1]==1: noCWforBundlerTwo+=1 self.stats['noCraneWaitingsTwo']=noCWforBundlerTwo self.stats['oneCraneWaitBundlerTime']=float(self.o.tstep*sum(addedWB)) self.stats['twoCranesWaitBundlerTime']=float(self.o.tstep*sum(addedWBTwo)) else: raise Exception('Some error in number of heads in timeStats()') def treeStats(self): """ calculates some statistics.. should maybe be done in terrain class instead? """ trees=float(len(self.G.terrain.trees)) self.saveGeneralStats("stand no", self.G.terrain.treeFile, "-") #see simSeries for how it works.. self.saveGeneralStats("trees", trees, "-") if trees==0: return None self.saveGeneralStats("pine percentage", 100*len([t for t in self.G.terrain.trees if t.specie=='pine'])/trees, "%") self.saveGeneralStats("spruce percentage", 100*len([t for t in self.G.terrain.trees if t.specie=='spruce'])/trees, "%") self.saveGeneralStats("leaf tree percentage", 100*len([t for t in self.G.terrain.trees if t.specie=='leaf'])/trees, "%") treeDensity=trees/self.G.terrain.area self.saveGeneralStats("tree density", treeDensity, "trees/m2") mLogs=len(self.m.mainRoadTrees) mNum=0 cLogs=len(self.m.corridorTrees) cNum=0 for r in self.m.roadList: if r.radius>2*self.m.craneMaxL/2.+2: #main road. mNum+=1 else: cNum+=1 self.cNum=cNum self.mNum=mNum self.mLogs=mLogs self.cLogs=cLogs cWeight=sum([t.logWeight for w in self.m.corridorTrees ]) mWeight=sum([t.logWeight for w in self.m.corridorTrees ]) print "number of main roads:", mNum, "number of corridors:", cNum if cNum==0: self.avTreesPerCorr=0 else: self.avTreesPerCorr=cLogs/float(cNum) self.treesPerRoad=mLogs if cLogs==0: self.avCorrTreeWeight=0 else: self.avCorrTreeWeight=cWeight/float(cNum) if mLogs==0: self.avRoadTreeWeight=0 else: self.avRoadTreeWeight=mWeight/float(mNum) #the cumulative sum #clustering... see Clark and Evans 1954 rexp=0.5*1/(sqrt(treeDensity)) #expected r robs=0 for t in self.G.terrain.trees: tmp=[] R=5 while len(tmp)==0 and R<sqrt(self.G.terrain.area): #in 99.9% of the cases, this loop only runs once. #we are not using self.G.terrain.trees for speedup reasons. tmp=self.G.terrain.GetTrees(t.pos, R) R+=2 if len(tmp)==0: self.saveGeneralStats("clustering agg. index", "no trees", "trees/m2") break shortest=1e10 for treeTmp in tmp: if treeTmp==t: continue #same tree d=fun.getDistance(t.pos, treeTmp.pos) if d<shortest: shortest=d if shortest==1e10: raise Exception('could not find shortest tree...') robs+=shortest robs/=trees print "rexp:", rexp, "robs.", robs aggregationIndex=robs/rexp self.saveGeneralStats("clustering agg. index", aggregationIndex, "-") def plotMoni(self, ax, number): tcap=50 tmin=-0.1 if self.now()<tcap: t=tcap else: if self.now()-tmin>400: tmin=self.now()-400 t=self.now() if number==1: #plot driver activity driver=self.m.driver moni=driver.actMon if len(moni)>0: ax.plot(moni.tseries(),moni.yseries(), drawstyle='steps-post') ax.axis([tmin, t, -0.1, 1.2]) ax.grid(True) ax.set_ylabel('Working pattern') ax.set_yticks((0, 1))#, ('idle', 'busy'))#, color = 'k') elif number==2: #plot driver waiting queue moni=self.m.driver.waitMon if len(moni)>0: maxt=int(max(moni.yseries())) ticks=[] for i in range(maxt+1): ticks.append(i) ax.set_yticks(tuple(ticks)) ax.plot(moni.tseries(),moni.yseries(), drawstyle='steps-post') ax.axis([tmin, t, -0.1, max(moni.yseries())+0.1]) ax.grid(True) ax.set_ylabel('Wait queue for driver.') elif number==3: #plot trees planted moni=self.m.treeMoni #trees planted if len(moni)>0: ax.plot(moni.tseries(),moni.yseries(), drawstyle='steps-post') ax.axis([-0.1, t, -0.1, (max(moni.yseries())+1)]) ax.grid(True) ax.set_xlabel('time(s)') ax.set_ylabel('trees harvested') return ax