def removeOverlaps(self): if not self.allowOverlaps: theGarden=self if theGarden.showProgressBar: print "***Removing overlapping objects***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 for obj in theGarden.soil[:]: ###seeds and or stems that overlap are violating physics. ##Rules about overlapping objects: #####1.) If 2 objects overlap, the more massive object remains. #####2.) If 2 seeds overlap and they have the same mass, the oldest seed remains. objectList=theGarden.checkForOverlap(obj) for overlappingObject in objectList: if obj.massTotal>overlappingObject.massTotal: overlappingObject.causeOfDeath="crushed" theGarden.kill(overlappingObject) break elif obj.massTotal<overlappingObject.massTotal: obj.causeOfDeath="crushed" theGarden.kill(obj) break elif obj.massTotal==overlappingObject.massTotal: if obj.timePlanted>overlappingObject.timePlanted: obj.causeOfDeath="overlap violation" theGarden.kill(obj) break else: obj.causeOfDeath="overlap violation" theGarden.kill(overlappingObject) break if theGarden.showProgressBar: i=i+1 theProgressBar.update(i)
def removeOverlaps(self): if not self.allowOverlaps: theGarden = self if theGarden.showProgressBar: print "***Removing overlapping objects***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") i = 0 for obj in theGarden.soil[:]: ###seeds and or stems that overlap are violating physics. ##Rules about overlapping objects: #####1.) If 2 objects overlap, the more massive object remains. #####2.) If 2 seeds overlap and they have the same mass, the oldest seed remains. objectList = theGarden.checkForOverlap(obj) for overlappingObject in objectList: if obj.massTotal > overlappingObject.massTotal: overlappingObject.causeOfDeath = "crushed" theGarden.kill(overlappingObject) break elif obj.massTotal < overlappingObject.massTotal: obj.causeOfDeath = "crushed" theGarden.kill(obj) break elif obj.massTotal == overlappingObject.massTotal: if obj.timePlanted > overlappingObject.timePlanted: obj.causeOfDeath = "overlap violation" theGarden.kill(obj) break else: obj.causeOfDeath = "overlap violation" theGarden.kill(overlappingObject) break if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i)
def checkDistanceMortality(self): if self.allowDistanceFromMother and self.janzenConnell > 0.0: theGarden = self if theGarden.showProgressBar: print "***Checking for mortality due to proximity to mother...***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") #print "Name : Distance : Chance" for obj in theGarden.soil[:]: if not obj.isSeed: twoPi = 2.0 * 3.14 stddev = self.janzenConnell theAvg = 0.0 theDistance = geometry_utils.distBetweenPoints( obj.motherPlant.x, obj.motherPlant.y, obj.x, obj.y) if theDistance > 0.0: theExponent = -(((theDistance - theAvg)**2.0) / ((2.0 * stddev)**2.0)) theDeathChance = ((1 / (stddev * (twoPi**0.5))) * 2.71)**theExponent #print "%s : %s :%s" % (obj.name, theDistance, theDeathChance) tooBad = random.random() if tooBad < theDeathChance: obj.causeOfDeath = "experimental death due to distance from mother" theGarden.kill(obj) if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i)
def checkSenescence(self): if self.allowSlowGrowthDeath: theGarden=self if theGarden.showProgressBar: print "***Checking for too slow growth...***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 for obj in theGarden.soil[:]: if not obj.isSeed and obj.maxAvgHeightGrowthRate>0.0: #only look at growth if the object is a plant, not a seed. fractOfMaxHeightGrowth=obj.avgHeightGrowthRate/obj.maxAvgHeightGrowthRate if obj.randomSlowGrowth>fractOfMaxHeightGrowth or theGarden.randomSlowGrowth>fractOfMaxHeightGrowth: #the garden defines a value at which plants will start to stochastically die #each species also defines a value at which that species will start to stochastically die #this way the garden can have a 'bad' environment that triggers problems earlier than a species might define #to simulate a virus or something. tooBad=random.random() theRegion=theGarden if len(obj.subregion)>0: #if there are multiple regions, only the most recently made one is used. theRegion=obj.subregion[-1] chanceOfDeath=theRegion.randomDeath if tooBad<=chanceOfDeath: obj.causeOfDeath="growth too slow" theGarden.kill(obj) if theGarden.showProgressBar: i=i+1 theProgressBar.update(i)
def checkSenescence(self): if self.allowSlowGrowthDeath: theGarden = self if theGarden.showProgressBar: print "***Checking for too slow growth...***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") i = 0 for obj in theGarden.soil[:]: if not obj.isSeed and obj.maxAvgHeightGrowthRate > 0.0: #only look at growth if the object is a plant, not a seed. fractOfMaxHeightGrowth = obj.avgHeightGrowthRate / obj.maxAvgHeightGrowthRate if obj.randomSlowGrowth > fractOfMaxHeightGrowth or theGarden.randomSlowGrowth > fractOfMaxHeightGrowth: #the garden defines a value at which plants will start to stochastically die #each species also defines a value at which that species will start to stochastically die #this way the garden can have a 'bad' environment that triggers problems earlier than a species might define #to simulate a virus or something. tooBad = random.random() theRegion = theGarden if len(obj.subregion) > 0: #if there are multiple regions, only the most recently made one is used. theRegion = obj.subregion[-1] chanceOfDeath = theRegion.randomDeath if tooBad <= chanceOfDeath: obj.causeOfDeath = "growth too slow" theGarden.kill(obj) if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i)
def removeEulerGreenhillViolaters(self): if not self.allowEulerGreenhillViolations: theGarden=self if theGarden.showProgressBar: print "***Checking for Greenhill-Euler violations...***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 for obj in theGarden.soil[:]: if theGarden.checkEulerGreenhillViolation(obj)==1: obj.causeOfDeath="violated Euler-Greenhill" theGarden.kill(obj) if theGarden.showProgressBar: i=i+1 theProgressBar.update(i)
def removeEulerGreenhillViolaters(self): if not self.allowEulerGreenhillViolations: theGarden = self if theGarden.showProgressBar: print "***Checking for Greenhill-Euler violations...***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") i = 0 for obj in theGarden.soil[:]: if theGarden.checkEulerGreenhillViolation(obj) == 1: obj.causeOfDeath = "violated Euler-Greenhill" theGarden.kill(obj) if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i)
def removeOffWorldViolaters(self): if not self.allowOffWorld: theGarden=self if theGarden.showProgressBar: print "***Removing plants growing off world...***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 ###see if plants or seeds extend over the edge of the world ### if so, kill them off for obj in theGarden.soil[:]: if theGarden.outOfBounds(obj)==1: obj.causeOfDeath="stem off world" theGarden.kill(obj) if theGarden.showProgressBar: i=i+1 theProgressBar.update(i)
def removeOffWorldViolaters(self): if not self.allowOffWorld: theGarden = self if theGarden.showProgressBar: print "***Removing plants growing off world...***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") i = 0 ###see if plants or seeds extend over the edge of the world ### if so, kill them off for obj in theGarden.soil[:]: if theGarden.outOfBounds(obj) == 1: obj.causeOfDeath = "stem off world" theGarden.kill(obj) if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i)
def causeRandomDeath(self): if self.allowRandomDeath: theGarden=self if theGarden.showProgressBar: print "***A time to die...***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 for obj in theGarden.soil[:]: tooBad=random.random() theRegion=theGarden if len(obj.subregion)>0: #if there are multiple regions, only the most recently made one is used. theRegion=obj.subregion[-1] if tooBad<theRegion.randomDeath: obj.causeOfDeath="random death" theGarden.kill(obj) if theGarden.showProgressBar: i=i+1 theProgressBar.update(i)
def causeRandomDeath(self): if self.allowRandomDeath: theGarden = self if theGarden.showProgressBar: print "***A time to die...***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") i = 0 for obj in theGarden.soil[:]: tooBad = random.random() theRegion = theGarden if len(obj.subregion) > 0: #if there are multiple regions, only the most recently made one is used. theRegion = obj.subregion[-1] if tooBad < theRegion.randomDeath: obj.causeOfDeath = "random death" theGarden.kill(obj) if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i)
def checkDistanceMortality(self): if self.allowDistanceFromMother: theGarden=self if theGarden.showProgressBar: print "***Checking for mortality due to proximity to mother...***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") #print "Name : Distance : Chance" for obj in theGarden.soil[:]: if not obj.isSeed: twoPi=2.0*3.14 stddev=0.9 theAvg=0.0 theDistance=geometry_utils.distBetweenPoints(obj.motherPlant.x, obj.motherPlant.y, obj.x, obj.y) if theDistance>0.0: theExponent=-(((theDistance-theAvg)**2.0)/((2.0*stddev)**2.0)) theDeathChance=((1/(stddev*(twoPi**0.5)))*2.71)**theExponent #print "%s : %s :%s" % (obj.name, theDistance, theDeathChance) tooBad=random.random() if tooBad<theDeathChance: obj.causeOfDeath="experimental death due to distance from mother" theGarden.kill(obj) if theGarden.showProgressBar: i=i+1 theProgressBar.update(i)
def determineShade(theGarden): if theGarden.showProgressBar: print "***Generating lists of overlapping plants. This could take a while...***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") i = 0 ###populate the overlap list theIndex = 0 for plantOne in theGarden.soil: if plantOne.isSeed == 0 or (plantOne.isSeed and plantOne.minimumLightForGermination > 0.0): plantOne.overlapList = [] plantOne.areaCovered = 0.0 plantOne.colourLeaf[2] = 1.0 ###the following might be able to be used to speed things up #for overlappingItem in plantOne.overlapList: # if not overlappingItem in theGarden.soil or not overlappingItem.z>plantOne.z: # ###make sure the overlapping item is still alive # ###and that overlapping item is still taller # plantOne.overlapList.remove(overlappingItem) ###need to insert something so tallest plant looks at all the other plants of exactly the same size ###if they are the same size and overlapping, they need to share shading for plantTwo in range(theIndex): plantTwo = theGarden.soil[plantTwo] ###is plant two overlapping you? overlapStatus = geometry_utils.checkOverlap( plantOne.x, plantOne.y, plantOne.r, plantTwo.x, plantTwo.y, plantTwo.r) if overlapStatus > 0: if not plantTwo in plantOne.overlapList: if not plantTwo == plantOne: plantOne.overlapList.append(plantTwo) ###sort the overlap list by height of the plants. Ordered shortest to tallest plantOne.overlapList = list_utils.sort_by_attr( plantOne.overlapList, "heightStem") ###flip the list so it's ordered tallest to shortest plantOne.overlapList.reverse() theIndex = theIndex + 1 if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i) ###take the overlap list and start dropping photons onto it. if theGarden.showProgressBar: print "***Determining shading. This could take a while...***" theProgressBar = progressBarClass.progressbarClass( len(theGarden.soil), "*") i = 0 for plant in theGarden.soil: if plant.isSeed == 0 or (plant.isSeed and plant.minimumLightForGermination > 0.0): fractionExposed = 1.0 if len(plant.subregion) > 0: theRegion = plant.subregion[-1] else: theRegion = theGarden if len(plant.overlapList) > 0: thePlantAreaTotal = geometry_utils.areaCircle(plant.r) if thePlantAreaTotal == 0.0: print "name:%s r:%f isSeed:%i massSeed:%f massTotal:%f" % ( plant.name, plant.r, plant.isSeed, plant.massSeed, plant.massTotal) if len( plant.overlapList ) == 1: ###if you are covered by just 1 other, do a direct calc overPlant = plant.overlapList[0] areaCovered = geometry_utils.areaOverlappingCircles( plant.x, plant.y, plant.r, overPlant.x, overPlant.y, overPlant.r) areaCovered = areaCovered - (areaCovered * plantTwo.canopyTransmittance) thePlantAreaExposed = thePlantAreaTotal - areaCovered #plant.areaCovered=areaCovered fractionExposed = thePlantAreaExposed / thePlantAreaTotal #fractionExposed=fractionExposed*theGarden.lightIntensity #try and take into account overall world light intensity fractionExposed = fractionExposed * theRegion.lightIntensity #try and take into account overall world light intensity thePlantAreaExposed = thePlantAreaTotal * fractionExposed plant.areaCovered = thePlantAreaTotal - thePlantAreaExposed elif len(plant.overlapList ) > 1: ###if you are covered by 2, use monte-carlo numbPhotons = int(thePlantAreaTotal) if numbPhotons == 0: numbPhotons = 1 numbPhotons = numbPhotons * 100 if numbPhotons > 750: #we don't need monster numbers numbPhotons = 750 hitCount = 0 for photon in range(numbPhotons): #####consider moving this to geometry_utils ###pick uniformly distributed point in a circle randr = (random.random() * (plant.r - 0) ) + 0 #random between 0 and the radius twoPi = math.pi * 2 randAngle = random.random() * twoPi #randr =math.sqrt(randr) #if you don't use sqrt, you get clustering in the center randr = randr**0.5 #if you don't use sqrt, you get clustering in the center photonX = (randr * math.cos(randAngle)) + plant.x photonY = (randr * math.sin(randAngle)) + plant.y ###### for overPlant in plant.overlapList: if not photonX == "gone": if geometry_utils.pointInsideCircle( overPlant.x, overPlant.y, overPlant.r, photonX, photonY): randomValue = random.random() if randomValue > overPlant.canopyTransmittance: ###these points are where the overlap is photonX = "gone" break if not photonX == "gone": hitCount = hitCount + 1 if numbPhotons == 0: fractionExposed = 0.0 else: fractionExposed = float(hitCount) / float(numbPhotons) #fractionExposed=fractionExposed*theGarden.lightIntensity #try and take into account overall world light intensity fractionExposed = fractionExposed * theRegion.lightIntensity #try and take into account overall world light intensity thePlantAreaExposed = thePlantAreaTotal * fractionExposed plant.areaCovered = thePlantAreaTotal - thePlantAreaExposed else: #if you are not covered at all thePlantAreaTotal = geometry_utils.areaCircle(plant.r) fractionExposed = 1.0 #fractionExposed=fractionExposed*theGarden.lightIntensity #try and take into account overall world light intensity fractionExposed = fractionExposed * theRegion.lightIntensity #try and take into account overall world light intensity thePlantAreaExposed = thePlantAreaTotal * fractionExposed plant.areaCovered = thePlantAreaTotal - thePlantAreaExposed ###now change the colour accordingly plant.colourLeaf[2] = fractionExposed if theGarden.showProgressBar: i = i + 1 theProgressBar.update(i)
def main(): #why do only these need to be reminded they are global? global simulationFile global theWorldSize global startPopulationSize global seedPlacement global sList #Import Psyco if possible try: import psyco psyco.log() psyco.full() except ImportError: pass CFDGtext="" #################################### ###experiments in importing events import yaml if os.path.exists(eventFile): print "***Loading event file: %s***" % (eventFile) theFile=open(eventFile) eventData=yaml.load(theFile) theFile.close eventTimes=eventData.keys() else: eventTimes=[] ##################################### if debug==1: print "***debug is on***" theGarden= worldBasics.garden() theGarden.platonicSeeds={} theGarden.theRegions=[] #### #########Check for multiple species. If none, use default fileList=os.listdir("Species") ymlList=[] pythonList=[] useDefaultYml=True print "***Checking for species...***" for file in fileList: theExtension=os.path.splitext(file)[1] if theExtension==".yml": #add this file to the list of yaml files ymlList.append(file) useDefaultYml=False elif theExtension==".py": #this might be override info for a species #add this file to the list of species python files #this isn't implemented pythonList.append(file) fileList=[] ########## if resumeSim==1 and not simulationFile=="": simulationFile=open(simulationFile, 'r') theGarden=pickle.load(simulationFile) simulationFile.close() theWorldSize=theGarden.theWorldSize print "***Resuming Simulation: %s as %s***" % (theGarden.name, simulationName) theGarden.name=simulationName startPopulationSize=theGarden.numbPlants ##this should reload species data. ###Important if you want to compare runs if reloadSpeciesData==1: ###fileLoc will be different for each species eventually fileLoc="SERA_Data/Default_species.txt" for item in theGarden.soil: item.importPrefs(fileLoc) else: theGarden.makePlatonicSeedDict(ymlList, Species1) print "***Species loaded.***" theGarden.name=simulationName theGarden.theWorldSize=theWorldSize print "***Beginning Simulation: %s***" % (simulationName) theGarden.showProgressBar=showProgressBar print " World size: %ix%i" % (theWorldSize, theWorldSize) print " Maximum population size will be: %i" % (maxPopulation) print " and" print " Running simulation for %i cycles" % (maxCycles) print " (whichever comes first)" print " Starting population size: %i" % (startPopulationSize) if theGarden.carbonAllocationMethod==0: print " Plants will allocate carbon to stem and leaf using methods defined by the species." else: print " All plants will allocate carbon to stem and leaf using method %i" % (theGarden.carbonAllocationMethod) print "" if produceGraphics==1: print " Graphical output will be produced." if theView==1: print " Graphical output will be a bottom-up view." elif theView==2: print " Graphical output will be a top-down view." elif theView==3: print " Graphical output will be a side-view." elif theView==12: print " Graphical output will be a combination bottom-up and top-down view." elif theView==21: print " Graphical output will be a combination top-down and bottom-up view." elif theView==23: print " Graphical output will be a combined top-down and side view." elif theView==13: print " Graphical output will be a combined bottom-up and side view." elif theView==123: print " Graphical output will be a combination bottom-up, top-down and side view." if produceVideo==1: print " Graphical output will include a %s frame/second video." % (framesPerSecond) ###I think this is where to start the times to repeat bit for x in range(timesToRepeat): ###make necessary directories outputDirectory="Output-"+simulationName+"/" outputDirectory=makeDirectory(outputDirectory) if produceGraphics==1 or produceDXFGraphics==1: outputGraphicsDirectory = outputDirectory +"Graphics/" makeDirectory(outputGraphicsDirectory) if produceDXFGraphics==1: outputDXFGraphicsDirectory = outputGraphicsDirectory +"DXF/" makeDirectory(outputDXFGraphicsDirectory) ####SUPER IMPORTANT!!!! ####DON'T USE SPACES IN DIR NAMES! ####COMMAND LINES HATE THAT SHIT if theView==1: outputGraphicsDirectory = outputGraphicsDirectory +"bottom-up/" makeDirectory(outputGraphicsDirectory) elif theView==2: outputGraphicsDirectory = outputGraphicsDirectory +"top-down/" makeDirectory(outputGraphicsDirectory) elif theView==3: outputGraphicsDirectory = outputGraphicsDirectory +"side/" makeDirectory(outputGraphicsDirectory) elif theView==12: outputGraphicsDirectory = outputGraphicsDirectory +"combined-bottom-top/" makeDirectory(outputGraphicsDirectory) elif theView==21: outputGraphicsDirectory = outputGraphicsDirectory +"combined-top-bottom/" makeDirectory(outputGraphicsDirectory) elif theView==13: outputGraphicsDirectory = outputGraphicsDirectory +"combined-bottom-side/" makeDirectory(outputGraphicsDirectory) elif theView==23: outputGraphicsDirectory = outputGraphicsDirectory +"combined-top-side/" makeDirectory(outputGraphicsDirectory) elif theView==123: outputGraphicsDirectory = outputGraphicsDirectory +"combined-bottom-top-side/" makeDirectory(outputGraphicsDirectory) if not archive=="n": saveDirectory = outputDirectory+"Save_points/" makeDirectory(saveDirectory) if not saveData=="n": dataDirectory = outputDirectory+"Simulation_data/" makeDirectory(dataDirectory) makeDirectory(dataDirectory+"Seeds/") makeDirectory(dataDirectory+"Plants/") makeDirectory(dataDirectory+"Corpses/") if resumeSim==0: #2008.11.06 Moved a huge block of code related to placing seeds to vworldr.py theGarden.placeSeed(seedPlacement, sList, startPopulationSize, useDefaultYml, ymlList) if produceGraphics and CFDGtext=="": CFDGtext=outputGraphics.initCFDGText(theGarden, theView, percentTimeStamp, 50.0) ####### cycleNumber=0 print "\n***Running simulation.***" if not showProgressBar and not runningInNodeBox: theProgressBar= progressBarClass.progressbarClass(maxCycles,"*") #why -1? because index 0. So if total=100, 0-99. #print "Cycle, plant age, Mass Stem, Mass Leaf, # Seeds, Mass all Seeds, Radius Stem, Radius Leaf, Height Plant, areaPhoto, new mass" while (theGarden.numbPlants<=maxPopulation and cycleNumber<=maxCycles) and (theGarden.numbPlants+theGarden.numbSeeds)>0: ################################################################################### ####Experimental scripting event stuff # if cycleNumber in eventTimes: # for aItem in eventData[cycleNumber]: # for aKey in aItem.keys(): # if aKey=="Garden": # if debug==1: print "debug: A garden related event has been triggered." # theDict=aItem[aKey][0] # gardenAttrs=theDict.keys() # for theGardenAttr in gardenAttrs: # setattr(theGarden, theGardenAttr, theDict[theGardenAttr]) # gardenAttrs="" elif aKey=="Killzone" or aKey=="Safezone": if debug==1: print "debug: generation of a zone event has been triggered." theDict=aItem[aKey][0] # zoneAttrs=theDict.keys() zoneX=float(theDict['x']) zoneY=float(theDict['y']) zoneSize=float(theDict['size']) zoneShape=theDict['shape'] if zoneShape not in ['circle','square']: print "***WARNING: improper zone shape defined. Defaulting to square.***" zoneShape='square' zoneTarget=theDict['target'] if zoneTarget not in ['all','plants','seeds']: print "***WARNING: improper zone target defined. Defaulting to all.***" zoneTarget='all' if zoneShape=='circle': killThese=[] for theObject in theGarden.soil: if theObject.isSeed: r=theObject.radiusSeed else: r=theObject.radiusStem theResult=geometry_utils.checkOverlap(theObject.x, theObject.y, r, zoneX, zoneY, zoneSize) if theResult>0 and aKey=='Killzone': if zoneTarget=='all' or (theObject.isSeed and zoneTarget=='seeds') or (not theObject.isSeed and zoneTarget=='plants'): killThese.append(theObject) elif aKey=='Safezone': if theResult==0: killThese.append(theObject) elif theResult>0: if (theObject.isSeed and zoneTarget=='plants') or (not theObject.isSeed and zoneTarget=='seeds'): killThese.append(theObject) for theObject in killThese: theObject.causeOfDeath="zone" theGarden.kill(theObject) elif aKey=="Seed": if debug==1: print "debug: A seeding related event has been triggered." # theDict=aItem[aKey][0] # seedingInfo=theDict.keys() # for infoItem in seedingInfo: if infoItem=="number" and not seedPlacement=="fromFile": startPopulationSize=theDict[infoItem] if infoItem=="species": sList=theDict[infoItem] if sList=="random": sList=[] if infoItem=="placement": seedPlacement=theDict[infoItem] if seedPlacement=="hexagon": seedPlacement="hex" #just make sure it is consistant if os.path.isfile(seedPlacement): theFile=open(seedPlacement) try: sList=theFile.readlines() finally: theFile.close() sList=checkSeedPlacementList(sList) startPopulationSize=len(sList) seedPlacement="fromFile" if not seedPlacement=="fromFile" and not sList==[]: newList=[] for j in range(startPopulationSize): newList.append(sList) #print sList sList=newList newList=[] #print sList theGarden.placeSeed(seedPlacement, sList, startPopulationSize, useDefaultYml, ymlList) elif aKey=="Region": if debug: print "debug: Region event detected..." theDict=aItem[aKey][0] regionAttrs=theDict.keys() theRegionName=str(theDict['name']) if debug: print "debug: Region %s event detected." % (theRegionName) regionNames=[] for i in theGarden.theRegions: regionNames.append(i.name) if theRegionName in regionNames: for j in theGarden.theRegions: if j.name==theRegionName: theRegion=j break for aAttr in regionAttrs: if not getattr(theRegion,aAttr,"does not exist")==theDict[aAttr]: if debug: print "debug: Region %s has had a change in one or more attributes." % (theRegionName) updatePlants=True break #if (not theRegion.size==theDict["size"]) or (not theRegion.x==theDict["x"]) or (not theRegion.y==theDict["y"]) or (not theRegion.shape==theDict["shape"]): # if debug:print "debug: a region has changed shape, size or location" # updatePlants=True ##now just read in the values# if debug: print "debug: Updating attributes for region %s." % (theRegionName) for theRegionAttr in regionAttrs: # setattr(theRegion, theRegionAttr, theDict[theRegionAttr]) # if updatePlants: if debug:print "debug: updating plants with changed region info" for aPlant in theGarden.soil: plantX=aPlant.x plantY=aPlant.y if theRegion.shape=='square': inSubregion=geometry_utils.pointInsideSquare(theRegion.x, theRegion.y, theRegion.size, plantX, plantY) elif theRegion.shape=='circle': #size needs to be radius but region defines diameter inSubregion=geometry_utils.pointInsideCircle(theRegion.x, theRegion.y, theRegion.size/2.0, plantX, plantY) if inSubregion: if not theRegion in aPlant.subregion: aPlant.subregion.append(theRegion) #print "\nX: %f Y: %f In region: %s" % (plantX, plantY, newRegion) #print theRegion.size else: newRegion=worldBasics.garden() newRegion.name=theRegionName ###these are default values### newRegion.x=0.0 # newRegion.y=0.0 # newRegion.worldSize=1.0 # newRegion.shape='square' # ############################## ##now just read in the values# if debug: print "debug: Making attributes for region" for theRegionAttr in regionAttrs: # setattr(newRegion, theRegionAttr, theDict[theRegionAttr]) # theGarden.theRegions.append(newRegion) for aPlant in theGarden.soil: plantX=aPlant.x plantY=aPlant.y if newRegion.shape=='square': inSubregion=geometry_utils.pointInsideSquare(newRegion.x, newRegion.y, newRegion.size, plantX, plantY) elif newRegion.shape=='circle': #size needs to be radius but region defines diameter inSubregion=geometry_utils.pointInsideCircle(newRegion.x, newRegion.y, newRegion.size/2.0, plantX, plantY) if inSubregion: if not newRegion in aPlant.subregion: aPlant.subregion.append(newRegion) #print "\nX: %f Y: %f In region: %s" % (plantX, plantY, newRegion) newRegion="" theDict=[]#just clear this to free up the memory ################################################################################### theGarden.cycleNumber=cycleNumber if not showProgressBar and not runningInNodeBox: theProgressBar.update(cycleNumber) #print "%i, %i, %f, %f, %i, %f, %f, %f, %f, %f, %f" % (cycleNumber-1, theGarden.soil[0].age, theGarden.soil[0].massStem, theGarden.soil[0].massLeaf, len(theGarden.soil[0].seedList), theGarden.soil[0].massSeedsTotal, theGarden.soil[0].radiusStem, theGarden.soil[0].radiusLeaf, theGarden.soil[0].heightStem+theGarden.soil[0].heightLeafMax, theGarden.soil[0].areaPhotosynthesis, theGarden.soil[0].massFixed) ###START OF SEEING CHANGES TO SPECIES FOLDER #########Check for multiple species. If none, use default fileList=os.listdir("Species") #print fileList #ymlList=[] #print "***Checking for species...***" #for file in fileList: # theExtension=os.path.splitext(file)[1] # if theExtension==".yml": # #add this file to the list of yaml files # ymlList.append(file) # useDefaultYml=False #fileList=[] ########## if debug==1: print "number of plants: "+str(theGarden.numbPlants) if debug==1: print "number of seeds: "+str(theGarden.numbSeeds) #generate graphics if requested if produceDXFGraphics: theData=vdxfGraphics.makeDXF(theGarden) theFileName= simulationName+str(cycleNumber) vdxfGraphics.writeDXF(outputDXFGraphicsDirectory, theFileName, theData) if produceGraphics: theData=outputGraphics.makeCFDG(theView, CFDGtext, theGarden, cycleNumber) if webOutput==0: if theView==1: cfdgFileName= simulationName +"-bottom-"+str(cycleNumber) elif theView==2: cfdgFileName= simulationName +"-top-"+str(cycleNumber) elif theView==3: cfdgFileName= simulationName +"-side-"+str(cycleNumber) elif theView==12: cfdgFileName= simulationName +"-bottom-top-"+str(cycleNumber) elif theView==21: cfdgFileName= simulationName +"-top-bottom-"+str(cycleNumber) elif theView==13: cfdgFileName= simulationName +"-bottom-side-"+str(cycleNumber) elif theView==23: cfdgFileName= simulationName +"-top-side-"+str(cycleNumber) elif theView==123: cfdgFileName= simulationName +"-bottom-top-side"+str(cycleNumber) outputGraphics.writeCFDG(outputGraphicsDirectory, cfdgFileName, theData) else: cfdgFileName= simulationName outputGraphics.writeCFDG(outputGraphicsDirectory, cfdgFileName, theData) outputGraphics.outputPNGs(outputGraphicsDirectory, webDirectory) #outputGraphics.deleteCFDGFiles(outputGraphicsDirectory) ###go through the soil list and germinate seed or grow plant if theGarden.showProgressBar: print"***Allowing plants a turn to grow***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") theBar=0 for obj in theGarden.soil[:]: if obj.isSeed: obj.germinate(theGarden) else: obj.growPlant(theGarden) if theGarden.showProgressBar: theBar=theBar+1 theProgressBar.update(theBar) ###deal with violaters of basic physics theGarden.causeRandomDeath() theGarden.checkSenescence() theGarden.removeOffWorldViolaters() theGarden.removeEulerGreenhillViolaters() theGarden.removeOverlaps() ###sort the garden.soil by height of the plants.Ordered shortest to tallest theGarden.soil= list_utils.sort_by_attr(theGarden.soil, "heightStem") ###flip the list so it's ordered tallest to shortest theGarden.soil.reverse() ###work out shading worldBasics.determineShade(theGarden) ###Calculate the amount of carbon each plant will have to start the next turn if theGarden.showProgressBar: print "***Calculating new mass from photosynthesis***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 for plant in theGarden.soil[:]: if plant.isSeed==False: plant.massFixed=plant.calcNewMassFromLeaf(theGarden) if plant.massFixed==-1.0: plant.causeOfDeath="lack of light" theGarden.kill(plant) else: plant.massFixedRecord.append(plant.massFixed) while len(plant.massFixedRecord)>plant.numYearsGrowthMemory: plant.massFixedRecord.pop(0) if theGarden.showProgressBar: i=i+1 theProgressBar.update(i) if archive=="a": fileName=simulationName+'-'+str(cycleNumber)+'.pickle' saveSimulationPoint(saveDirectory, fileName, theGarden) if saveData=="a": fileName=simulationName+'-'+str(cycleNumber)+'.csv' saveDataPoint(dataDirectory, fileName, theGarden) #print theGarden.deathNote theGarden.deathNote=[] cycleNumber= cycleNumber+1 ###pause if you're making web graphic #if webOutput==1: # time.sleep(5) if archive=="e": fileName=simulationName+'-'+str(cycleNumber)+'.pickle' saveSimulationPoint(saveDirectory, fileName, theGarden) if saveData=="e": fileName=simulationName+'-'+str(cycleNumber)+'.csv' saveDataPoint(dataDirectory, fileName, theGarden) if produceStats: #print dataDirectory theArgument="-n '%s' -fs" % (dataDirectory+"Seeds/") print "***sending to Extract: %s" % (theArgument) os.system("python SERA_Data/vextract.py %s" % (theArgument)) theArgument="-n '%s' -fs" % (dataDirectory+"Plants/") print "***sending to Extract: %s" % (theArgument) os.system("python SERA_Data/vextract.py %s" % (theArgument)) theArgument="-n '%s' -fs" % (dataDirectory+"Corpses/") print "***sending to Extract: %s" % (theArgument) os.system("python SERA_Data/vextract.py %s" % (theArgument)) ###final graphics calls if produceGraphics==1 and webOutput==0: print "Producing PNG files..." outputGraphics.outputPNGs(outputGraphicsDirectory, outputGraphicsDirectory) if produceGraphics==1 and deleteCfdgFiles==1 and webOutput==0: print "Deleting .cfdg files..." outputGraphics.deleteCFDGFiles(outputGraphicsDirectory) ###only try and make a video if it is wanted and if pngs were made if produceVideo and produceGraphics and webOutput==0: print "Producing MOV file..." outputGraphics.outputMOV(outputGraphicsDirectory, simulationName, framesPerSecond) print "*****Simulation Complete*****" #print theGarden.deathNote #clear the values theGarden.soil=[] theGarden.deathNote=[] theGarden.cycleNumber=0 for aRegion in theGarden.theRegions: aRegion.size=0.0
def determineShade(theGarden): if theGarden.showProgressBar: print "***Generating lists of overlapping plants. This could take a while...***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 ###populate the overlap list theIndex=0 for plantOne in theGarden.soil: if plantOne.isSeed==0 or (plantOne.isSeed and plantOne.minimumLightForGermination>0.0): plantOne.overlapList=[] plantOne.areaCovered=0.0 plantOne.colourLeaf[2]= 1.0 ###the following might be able to be used to speed things up #for overlappingItem in plantOne.overlapList: # if not overlappingItem in theGarden.soil or not overlappingItem.z>plantOne.z: # ###make sure the overlapping item is still alive # ###and that overlapping item is still taller # plantOne.overlapList.remove(overlappingItem) ###need to insert something so tallest plant looks at all the other plants of exactly the same size ###if they are the same size and overlapping, they need to share shading for plantTwo in range(theIndex): plantTwo=theGarden.soil[plantTwo] ###is plant two overlapping you? overlapStatus=geometry_utils.checkOverlap(plantOne.x, plantOne.y, plantOne.r, plantTwo.x, plantTwo.y, plantTwo.r) if overlapStatus>0: if not plantTwo in plantOne.overlapList: if not plantTwo==plantOne: plantOne.overlapList.append(plantTwo) ###sort the overlap list by height of the plants. Ordered shortest to tallest plantOne.overlapList = list_utils.sort_by_attr(plantOne.overlapList, "heightStem") ###flip the list so it's ordered tallest to shortest plantOne.overlapList.reverse() theIndex=theIndex+1 if theGarden.showProgressBar: i=i+1 theProgressBar.update(i) ###take the overlap list and start dropping photons onto it. if theGarden.showProgressBar: print "***Determining shading. This could take a while...***" theProgressBar= progressBarClass.progressbarClass(len(theGarden.soil),"*") i=0 for plant in theGarden.soil: if plant.isSeed==0 or (plant.isSeed and plant.minimumLightForGermination>0.0): fractionExposed=1.0 if len(plant.subregion)>0: theRegion=plant.subregion[-1] else: theRegion=theGarden if len(plant.overlapList)>0: thePlantAreaTotal=geometry_utils.areaCircle(plant.r) if thePlantAreaTotal==0.0: print "name:%s r:%f isSeed:%i massSeed:%f massTotal:%f"%(plant.name, plant.r, plant.isSeed, plant.massSeed, plant.massTotal) if len(plant.overlapList)==1: ###if you are covered by just 1 other, do a direct calc overPlant =plant.overlapList[0] areaCovered=geometry_utils.areaOverlappingCircles(plant.x, plant.y, plant.r, overPlant.x, overPlant.y, overPlant.r) areaCovered=areaCovered-(areaCovered*plantTwo.canopyTransmittance) thePlantAreaExposed=thePlantAreaTotal-areaCovered #plant.areaCovered=areaCovered fractionExposed= thePlantAreaExposed/thePlantAreaTotal #fractionExposed=fractionExposed*theGarden.lightIntensity #try and take into account overall world light intensity fractionExposed=fractionExposed*theRegion.lightIntensity #try and take into account overall world light intensity thePlantAreaExposed= thePlantAreaTotal*fractionExposed plant.areaCovered=thePlantAreaTotal-thePlantAreaExposed elif len(plant.overlapList)>1: ###if you are covered by 2, use monte-carlo numbPhotons=int(thePlantAreaTotal) if numbPhotons==0: numbPhotons=1 numbPhotons= numbPhotons*100 if numbPhotons>750: #we don't need monster numbers numbPhotons=750 hitCount=0 for photon in range(numbPhotons): #####consider moving this to geometry_utils ###pick uniformly distributed point in a circle randr=(random.random()*(plant.r-0))+0 #random between 0 and the radius twoPi=math.pi*2 randAngle=random.random()*twoPi #randr =math.sqrt(randr) #if you don't use sqrt, you get clustering in the center randr =randr**0.5 #if you don't use sqrt, you get clustering in the center photonX = (randr*math.cos(randAngle))+plant.x photonY = (randr*math.sin(randAngle))+plant.y ###### for overPlant in plant.overlapList: if not photonX=="gone": if geometry_utils.pointInsideCircle(overPlant.x, overPlant.y, overPlant.r, photonX, photonY): randomValue=random.random() if randomValue > overPlant.canopyTransmittance: ###these points are where the overlap is photonX="gone" break if not photonX=="gone": hitCount=hitCount+1 if numbPhotons ==0: fractionExposed=0.0 else: fractionExposed=float(hitCount)/float(numbPhotons) #fractionExposed=fractionExposed*theGarden.lightIntensity #try and take into account overall world light intensity fractionExposed=fractionExposed*theRegion.lightIntensity #try and take into account overall world light intensity thePlantAreaExposed= thePlantAreaTotal*fractionExposed plant.areaCovered=thePlantAreaTotal-thePlantAreaExposed else: #if you are not covered at all thePlantAreaTotal=geometry_utils.areaCircle(plant.r) fractionExposed=1.0 #fractionExposed=fractionExposed*theGarden.lightIntensity #try and take into account overall world light intensity fractionExposed=fractionExposed*theRegion.lightIntensity #try and take into account overall world light intensity thePlantAreaExposed= thePlantAreaTotal*fractionExposed plant.areaCovered=thePlantAreaTotal-thePlantAreaExposed ###now change the colour accordingly plant.colourLeaf[2]= fractionExposed if theGarden.showProgressBar: i=i+1 theProgressBar.update(i)
def placeSeed(self, seedPlacement, sList, startPopulationSize, useDefaultYml, ymlList): theGarden=self #print sList #This block of code came from the main SERA.py. Moved and working on 2008.11.06 to allow for calling during simulation runs at #not just at the start. if theGarden.cycleNumber<1: print "***Generating and placing seeds.***" ###initialize progress bar### if theGarden.showProgressBar or theGarden.cycleNumber<1: theProgressBar= progressBarClass.progressbarClass(startPopulationSize-1,"*") #why -1? because index 0. So if total=100, 0-99. if seedPlacement=="square" or seedPlacement=="hex": seedDistance=geometry_utils.placePointsInGrid(startPopulationSize, theGarden.theWorldSize) prevX=-theGarden.theWorldSize/2.0 prevY= theGarden.theWorldSize/2.0 if seedPlacement=="hex": currentRow=0 prevX= prevX-(seedDistance/2.0) prevY= prevY+(seedDistance/2.0) if seedPlacement=="defined" or len(sList)>0: theIndex=0 #print sList for i in range(startPopulationSize): countToGerm=0 theSpeciesFile="" if debug1 and startPopulationSize==1: x=0 y=0 elif len(sList)>0: if seedPlacement=="fromFile": x=sList[i][1] y=sList[i][2] countToGerm=sList[i][3] #radius of canopy would be sList[i][4]. Unused, but in place to be built on if sList[i][0] in ymlList: theSpeciesFile=sList[i][0] else: print "\nWARNING: The desired species %s was not found. \nA random species will be used.\n" % (sList[i][0]) else: if sList[i] in ymlList: theSpeciesFile=sList[i] if seedPlacement=="fromFile": x=sList[i][1] y=sList[i][2] countToGerm=sList[i][3] #radius of canopy would be sList[i][4]. Unused, but in place to be built on elif seedPlacement=="random": x=random.randrange(-(theGarden.theWorldSize/2),(theGarden.theWorldSize/2))+random.random() y=random.randrange(-(theGarden.theWorldSize/2),(theGarden.theWorldSize/2))+random.random() elif seedPlacement=="square" or seedPlacement=="hex": x=prevX+seedDistance y=prevY-seedDistance if x+seedDistance>=(theGarden.theWorldSize/2.0): prevX=-theGarden.theWorldSize/2.0 if seedPlacement=="hex": if currentRow==0: currentRow=1 else: currentRow=0 prevX= prevX-(seedDistance/2.0) prevY= prevY-seedDistance else: prevX=x #print theSpeciesFile if useDefaultYml==False or theSpeciesFile=="": #print "not default species" if theSpeciesFile=="" or theSpeciesFile=="_random_": whichSpecies=random.randint(0,len(ymlList)-1)##pick from the species randomly fileLoc= "Species/"+ymlList[whichSpecies] theSpeciesFile=ymlList[whichSpecies] #print theSpeciesFile if theGarden.platonicSeeds.has_key(theSpeciesFile): platonicSeed=theGarden.platonicSeeds[theSpeciesFile] theSeed=copy.deepcopy(platonicSeed) #else: # print "something is very wrong." else: #if there are no species listed, use the default species. theSeed=Species1() theSeed=theGarden.plantSeed(theSeed) #print theSeed.subregion #now set some attributes theSeed.timeCreation=time.time() theSeed.countToGerm=countToGerm theSeed.x=x theSeed.y=y #this is just to get the properties calculated.Give the seed the max seed mass #bootstrap the seed theSeed.massSeed=theSeed.massSeedMax #convert mass to volume and the get the radius j= theSeed.massSeed/theSeed.densitySeed #this is volume in m^3 j=j/(4.0/3.0) j=j/(math.pi) j=math.pow(j, 1.0/3.0) theSeed.radiusSeed=j theSeed.z= theSeed.radiusSeed theSeed.r= theSeed.radiusSeed #theSeed.growSeedOnPlant(theSeed.massSeedMax) #print "#######" #print theSeed.__class__().name #print "#######" #update the progress meter if theGarden.showProgressBar or theGarden.cycleNumber<1: theProgressBar.update(i)
def placeSeed(self, seedPlacement, sList, startPopulationSize, useDefaultYml, ymlList): theGarden = self #print sList #This block of code came from the main SERA.py. Moved and working on 2008.11.06 to allow for calling during simulation runs at #not just at the start. if theGarden.cycleNumber < 1: print "***Generating and placing seeds.***" ###initialize progress bar### if theGarden.showProgressBar or theGarden.cycleNumber < 1: theProgressBar = progressBarClass.progressbarClass( startPopulationSize - 1, "*") #why -1? because index 0. So if total=100, 0-99. if seedPlacement == "square" or seedPlacement == "hex": seedDistance = geometry_utils.placePointsInGrid( startPopulationSize, theGarden.theWorldSize) prevX = -theGarden.theWorldSize / 2.0 prevY = theGarden.theWorldSize / 2.0 if seedPlacement == "hex": currentRow = 0 prevX = prevX - (seedDistance / 2.0) prevY = prevY + (seedDistance / 2.0) if seedPlacement == "defined" or len(sList) > 0: theIndex = 0 #print sList for i in range(startPopulationSize): countToGerm = 0 theSpeciesFile = "" if debug1 and startPopulationSize == 1: x = 0 y = 0 elif len(sList) > 0: if seedPlacement == "fromFile": x = sList[i][1] y = sList[i][2] countToGerm = sList[i][3] #radius of canopy would be sList[i][4]. Unused, but in place to be built on if sList[i][0] in ymlList: theSpeciesFile = sList[i][0] else: print "\nWARNING: The desired species %s was not found. \nA random species will be used.\n" % ( sList[i][0]) else: if sList[i] in ymlList: theSpeciesFile = sList[i] if seedPlacement == "fromFile": x = sList[i][1] y = sList[i][2] countToGerm = sList[i][3] #radius of canopy would be sList[i][4]. Unused, but in place to be built on elif seedPlacement == "random": x = random.randrange( -(theGarden.theWorldSize / 2), (theGarden.theWorldSize / 2)) + random.random() y = random.randrange( -(theGarden.theWorldSize / 2), (theGarden.theWorldSize / 2)) + random.random() elif seedPlacement == "square" or seedPlacement == "hex": x = prevX + seedDistance y = prevY - seedDistance if x + seedDistance >= (theGarden.theWorldSize / 2.0): prevX = -theGarden.theWorldSize / 2.0 if seedPlacement == "hex": if currentRow == 0: currentRow = 1 else: currentRow = 0 prevX = prevX - (seedDistance / 2.0) prevY = prevY - seedDistance else: prevX = x #print theSpeciesFile if useDefaultYml == False or theSpeciesFile == "": #print "not default species" if theSpeciesFile == "" or theSpeciesFile == "_random_": whichSpecies = random.randint( 0, len(ymlList) - 1) ##pick from the species randomly fileLoc = "Species/" + ymlList[whichSpecies] theSpeciesFile = ymlList[whichSpecies] #print theSpeciesFile if theGarden.platonicSeeds.has_key(theSpeciesFile): platonicSeed = theGarden.platonicSeeds[theSpeciesFile] theSeed = copy.deepcopy(platonicSeed) #else: # print "something is very wrong." else: #if there are no species listed, use the default species. theSeed = Species1() theSeed = theGarden.plantSeed(theSeed) #print theSeed.subregion #now set some attributes theSeed.timeCreation = time.time() theSeed.countToGerm = countToGerm theSeed.x = x theSeed.y = y #this is just to get the properties calculated.Give the seed the max seed mass #bootstrap the seed theSeed.massSeed = theSeed.massSeedMax #convert mass to volume and the get the radius j = theSeed.massSeed / theSeed.densitySeed #this is volume in m^3 j = j / (4.0 / 3.0) j = j / (math.pi) j = math.pow(j, 1.0 / 3.0) theSeed.radiusSeed = j theSeed.z = theSeed.radiusSeed theSeed.r = theSeed.radiusSeed #theSeed.growSeedOnPlant(theSeed.massSeedMax) #print "#######" #print theSeed.__class__().name #print "#######" #update the progress meter if theGarden.showProgressBar or theGarden.cycleNumber < 1: theProgressBar.update(i)
#!/usr/bin/env python