示例#1
0
def incline_leaf(shape, inclin, relative_angle=True):
    """ transform a xysr tuple representing leaf shape to get a given angle at leaf base.
     - angle the desired angle (deg)
     - if relative_angle == True, angle is interpreted as a multiplier to original shape angle
     """
    Linc = inclin
    x, y = shape[0], shape[1]
    init_angle = pgl.angle((x[1] - x[0], y[1] - y[0]), (0, 1))

    if relative_angle:
        angle = Linc * init_angle
        angle = min(pi, angle)
    else:
        angle = radians(Linc)

    rotation_angle = init_angle - angle

    # rotation of the midrib
    cos_a = cos(rotation_angle)
    sin_a = sin(rotation_angle)

    x1 = x[0] + cos_a * x - sin_a * y
    y1 = y[0] + sin_a * x + cos_a * y
    leaf = x1, y1, shape[2], shape[3]

    return leaf
示例#2
0
def incline_leaf(shape, inclin, relative_angle = True):
    """ transform a xysr tuple representing leaf shape to get a given angle at leaf base.
     - angle the desired angle (deg)
     - if relative_angle == True, angle is interpreted as a multiplier to original shape angle
     """   
    Linc = inclin
    x, y = shape[0], shape[1]
    init_angle = pgl.angle((x[1]-x[0], y[1]-y[0]),(0,1))

    if relative_angle:
        angle = Linc * init_angle
        angle = min(pi, angle)
    else:
        angle = radians(Linc)
    
    rotation_angle = init_angle - angle

    # rotation of the midrib
    cos_a = cos(rotation_angle); sin_a = sin(rotation_angle)

    x1 = x[0] + cos_a*x - sin_a*y
    y1 = y[0] + sin_a*x + cos_a*y
    leaf= x1, y1, shape[2], shape[3]
    
    return leaf
示例#3
0
    def _mesh(self, leaf_rank, seed, total_length, length, s_base, s_top, radius_max, *args):
        
        db = self.database
        rank_max = max(map(int,db.keys()))
        rank = leaf_rank
        rank = min(rank, rank_max)
        #choisi la liste de leaves du rang, ou rang + 1 si clef absente ourag -1 ou liste vide sinon
        leaves = db.get(str(rank), db.get(str(rank+1), db.get(str(rank-1), [])))
        n = len(leaves)
        if n == 0:
            dbk = ' '.join(db.keys())
            raise AdelParameterisationError("Leaf curvature index %d not found in database, available indices are:\n%s"%(rank,dbk))

        if self.seed is None:
            random.seed(seed)
        else: 
            random.seed(self.seed)

        if args and len(args) > 1 and args[1] >= 0:
            i = args[1] - 1 #R index starts at 1
        else:
            i = random.randint(0,n-1)
            
        leaf = leaves[i]

        # Rotation of the midrib of the leaf to set the insertion angle a relative fraction of the angle (reference beeing the  vertical)
        if args and args[0] >= 0:
            Linc = args[0]
            x, y = leaf[0], leaf[1]
            init_angle = pgl.angle((x[1]-x[0], y[1]-y[0]),(0,1))

            if self.relative_angle:
                angle = Linc * init_angle
                angle = min(math.pi, angle)
            else:
                angle = math.radians(Linc)
            
            rotation_angle = init_angle - angle

            # rotation of the midrib
            cos_a = cos(rotation_angle); sin_a = sin(rotation_angle)

            x1 = x[0] + cos_a*x - sin_a*y
            y1 = y[0] + sin_a*x + cos_a*y

            leaf = (x1, y1) + leaf[2:]

        leaf_mesh = fitting.mesh4(leaf, total_length, length, s_base, s_top, radius_max)
        if leaf_mesh:
            pts, ind = leaf_mesh
            if len(ind) < 2:
                mesh = None
            else:
                mesh = fitting.plantgl_shape(pts, ind)
        else:
            mesh = None

        return mesh
示例#4
0
 def _set_axis(self, axis):
     """Property helper method.
     """
     if axis != self._axis:
         self._axis = axis
         rotation_axis = pgl.cross(pgl.Vector3.OZ, self._axis)
         rotation_angle = pgl.angle(self._axis, pgl.Vector3.OZ)
         self.rotated.axis = rotation_axis
         self.rotated.angle = rotation_angle
示例#5
0
 def _set_axis( self, axis ):
     """Property helper method.
     """
     if axis != self._axis:
         self._axis = axis
         rotation_axis = pgl.cross( pgl.Vector3.OZ, self._axis )
         rotation_angle = pgl.angle( self._axis, pgl.Vector3.OZ )
         self.rotated.axis = rotation_axis
         self.rotated.angle = rotation_angle
示例#6
0
    def __init__(self,
                 pos=ASHAPE3D_STANDARD_POS,
                 axis=ASHAPE3D_STANDARD_AXIS,
                 roll=ASHAPE3D_STANDARD_ROLL,
                 scale=ASHAPE3D_STANDARD_SCALE,
                 material=ASHAPE3D_STANDARD_MATERIAL,
                 geometry=None,
                 **keys):
        """Default constructor.
        
        Parameters:
            pos : Vector3 convertable
                pos of the object (look below),
            axis : Vector3 convertable
                main axis of the object, should be defined to describe the rotation. The Z of the primitive geometry
                would point to axis,
            roll : Real
                Property: rotation of the object around main axis,
            scale :  Vector3 convertable
                to use while resizing the object. While scaling the Z corresponds to main axis of the object,
            material : pgl.Material
                describes the appearance of the object,
            geometry : pgl.Geometry
                describes the geometry of the object.
        """
        if not geometry:
            raise Exception("AShape3D: geometry not defined.")
        self.geometry = geometry
        #TODO check for custom rotation, scale, transformation objects (shared between shapes)
        self.scaled = pgl.Scaled(scale, self.geometry)

        # roll related
        self._roll = roll  #: to keep internal roll
        self.rolled = pgl.AxisRotated(pgl.Vector3.OZ, self._roll, self.scaled)

        # axis related (even the object which do not have intuitive axis need to have predefined axis
        self._axis = axis  #: to keep internal axis vector
        rotation_axis = pgl.cross(pgl.Vector3.OZ, self._axis)
        rotation_angle = pgl.angle(self._axis, pgl.Vector3.OZ)
        self.rotated = pgl.AxisRotated(rotation_axis, rotation_angle,
                                       self.rolled)

        # position related
        self.translated = pgl.Translated(pos, self.rotated)

        # apperance related
        self.shape = pgl.Shape(self.translated, material)
示例#7
0
    def __init__( self, pos=ASHAPE3D_STANDARD_POS,  axis=ASHAPE3D_STANDARD_AXIS, roll=ASHAPE3D_STANDARD_ROLL,
                 scale=ASHAPE3D_STANDARD_SCALE, material=ASHAPE3D_STANDARD_MATERIAL, geometry=None, **keys ):
        """Default constructor.
        
        Parameters:
            pos : Vector3 convertable
                pos of the object (look below),
            axis : Vector3 convertable
                main axis of the object, should be defined to describe the rotation. The Z of the primitive geometry
                would point to axis,
            roll : Real
                Property: rotation of the object around main axis,
            scale :  Vector3 convertable
                to use while resizing the object. While scaling the Z corresponds to main axis of the object,
            material : pgl.Material
                describes the appearance of the object,
            geometry : pgl.Geometry
                describes the geometry of the object.
        """
        if not geometry:
            raise Exception( "AShape3D: geometry not defined." )
        self.geometry = geometry
        #TODO check for custom rotation, scale, transformation objects (shared between shapes)
        self.scaled = pgl.Scaled( scale, self.geometry )

        # roll related        
        self._roll = roll #: to keep internal roll
        self.rolled = pgl.AxisRotated(pgl.Vector3.OZ, self._roll, self.scaled)

        # axis related (even the object which do not have intuitive axis need to have predefined axis
        self._axis = axis #: to keep internal axis vector
        rotation_axis = pgl.cross( pgl.Vector3.OZ, self._axis )
        rotation_angle = pgl.angle( self._axis, pgl.Vector3.OZ )
        self.rotated = pgl.AxisRotated( rotation_axis, rotation_angle, self.rolled )
        
        # position related
        self.translated = pgl.Translated( pos, self.rotated )
        
        # apperance related
        self.shape = pgl.Shape( self.translated, material )
def arrange_leaf(leaf, stem_diameter=0, inclination=1, relative=True):
    """Arrange a leaf to be placed along a stem with a given inclination.

    Args:
        leaf: a x, y, s, r tuple describing leaf shape
        stem_diameter: the diameter of the sem at the leaf insertion point
        inclination: if relative=False, the leaf basal inclination (deg). A
        multiplier to leaf basal inclination angle otherwise
        relative: (bool) controls the meaning of inclination parameter

    Returns:
        a modified x, y, s, r tuple

    """

    x, y, s, r = map(numpy.array, leaf)
    if relative and inclination == 1:
        x1, y1 = x, y
    else:
        basal_inclination = pgl.angle((x[1] - x[0], y[1] - y[0]), (0, 1))

        if relative:
            angle = inclination * basal_inclination
            angle = min(pi, angle)
        else:
            angle = radians(inclination)

        rotation_angle = basal_inclination - angle

        # rotation of the midrib
        cos_a = cos(rotation_angle)
        sin_a = sin(rotation_angle)

        x1 = x[0] + cos_a * x - sin_a * y
        y1 = y[0] + sin_a * x + cos_a * y
    leaf = x1 + stem_diameter / 2., y1, s, r

    return leaf
示例#9
0
def ucinsertionangle(uc, m):
    ucldir = ucdir(uc, m)
    ucpdir = ucdir(m.parent(uc), m)
    if ucldir is None or ucpdir is None: return None
    return degrees(angle(ucldir, ucpdir))
示例#10
0
    def __call__(self, g, v, turtle):
        geometry = g.property('geometry')
        # 1. retrieve the node
        n = g.node(v)
        axis = n.complex_at_scale(scale=2).label
        az_axis = n.complex_at_scale(scale=2).azimuth
        prev_axis = turtle.context.get("axis", axis)
        metamer = n.complex_at_scale(scale=3)

        # Go to plant position if first plant element
        if n.parent() is None:  #this is a new plant base
            p = n.complex_at_scale(scale=1)
            if 'position' in p.properties():
                #print p.label, 'moving to ', p.position
                turtle.move(map(float, p.position))
            else:
                turtle.move(0, 0, 0)
            #initial position to be compatible with canMTG positioning
            turtle.setHead(0, 0, 1, -1, 0, 0)
            if 'azimuth' in p.properties():
                turtle.rollR(p.azimuth)
            #print prev_axis, 'stop'
            #print 'new MS start'
            turtle.context.update({
                'MS_top': turtle.getFrame(),
                'tiller_base': turtle.getFrame(),
                'top': turtle.getFrame(),
                'is_axis_first_StemElement': True
            })

        if axis != prev_axis:
            if metamer.edge_type() == '+':
                turtle.context['is_axis_first_StemElement'] = True
                if prev_axis == 'MS':
                    #this is the begining of the first tiller
                    #print axis, 'start'
                    #top of mainstem saved
                    turtle.context['MS_top'] = turtle.context['top']
                    turtle.context['tiller_base'] = turtle.context['top']
                else:
                    # this is a new tiller attached to the same point thatn the previous tiller
                    #print prev_axis, 'stop'
                    #print axis, 'start'
                    # return to tilller base
                    turtle.context['top'] = turtle.context['tiller_base']
            else:  #this is the continuation of MS
                #print prev_axis, 'stop'
                #print axis, 'continue'
                turtle.context['top'] = turtle.context['MS_top']

        #hypothesis that inclin is to be applied at the base of the visible elements
        #if n.offset > 0:
        #    turtle.f(n.offset)
        turtle.setFrame(turtle.context['top'])
        #incline turtle at the base of stems,
        if n.label.startswith('Stem'):
            inclin = float(n.inclination) if n.inclination else 0.
            azim = float(n.azimuth) if n.azimuth else 0.
            if inclin:
                #print 'node', n._vid, 'inclin', inclin
                # incline along curent azimuth for ramification (tiller bases) or plant base
                if turtle.context['is_axis_first_StemElement']:
                    #print 'axis',axis, 'prev_axis', prev_axis,' node ', n._vid, 'edge', n.edge_type(),'up before inclin ', turtle.getUp(), 'inclin', inclin
                    if prev_axis != 'MS':  #new tiller attached to the same position than the firt
                        turtle.rollR(az_axis)
                        turtle.context['tiller_base'] = turtle.getFrame()
                    turtle.down(inclin)
                    turtle.context['is_axis_first_StemElement'] = False
                    #print 'up after inclin', turtle.getUp()
                # if not incline towardss vertical
                else:
                    up = turtle.getUp()
                    zleft = turtle.getLeft()[2]
                    turtle.rollToVert()
                    #print 'up after rollToVert', turtle.getUp()
                    angle = degrees(pgl.angle(up, turtle.getUp()))
                    dzl = zleft - turtle.getLeft()[2]
                    turtle.down(inclin)
                    #replace turtle in original azimuth plane
                    #print 'angle ', angle, 'dzl', dzl
                    if dzl < 0:
                        angle = -angle
                    turtle.rollR(-angle)
            if azim:
                #print 'node', n._vid, 'azim ', azim
                turtle.rollR(azim)

        if n.label.startswith('Leaf') or n.label.startswith('Stem'):
            # update geometry of elements
            mesh = None
            if n.length > 0:
                mesh = compute_element(n, self.leaves, self.classic)
            if mesh:
                n.geometry = turtle.transform(mesh,
                                              face_up=self.face_up
                                              and n.label.startswith('Leaf'))
                n.anchor_point = turtle.getPosition()
            else:
                if v in geometry:  # delete existing geometry
                    geometry.pop(v)
        # 3. Update the turtle and context
        turtle.setId(v)
        if n.label.startswith('Stem'):
            if n.length > 0:
                turtle.f(n.length)
            turtle.context.update({'top': turtle.getFrame()})
        if n.label.startswith('Leaf'):
            if n.lrolled > 0:
                turtle.f(n.lrolled)
                turtle.context.update({'top': turtle.getFrame()})
        turtle.context.update({'axis': axis})
""" Gather different strategies for modeling dispersal of fungus propagules.
示例#12
0
文件: symbol.py 项目: rbarillot/adel
    def _mesh(self, leaf_rank, seed, total_length, length, s_base, s_top,
              radius_max, *args):

        db = self.database
        rank_max = max(map(int, db.keys()))
        rank = leaf_rank
        rank = min(rank, rank_max)
        #choisi la liste de leaves du rang, ou rang + 1 si clef absente ourag -1 ou liste vide sinon
        leaves = db.get(str(rank),
                        db.get(str(rank + 1), db.get(str(rank - 1), [])))
        n = len(leaves)
        if n == 0:
            dbk = ' '.join(db.keys())
            raise AdelParameterisationError(
                "Leaf curvature index %d not found in database, available indices are:\n%s"
                % (rank, dbk))

        if self.seed is None:
            random.seed(seed)
        else:
            random.seed(self.seed)

        if args and len(args) > 1 and args[1] >= 0:
            i = args[1] - 1  #R index starts at 1
        else:
            i = random.randint(0, n - 1)

        leaf = leaves[i]

        # Rotation of the midrib of the leaf to set the insertion angle a relative fraction of the angle (reference beeing the  vertical)
        if args and args[0] >= 0:
            Linc = args[0]
            x, y = leaf[0], leaf[1]
            init_angle = pgl.angle((x[1] - x[0], y[1] - y[0]), (0, 1))

            if self.relative_angle:
                angle = Linc * init_angle
                angle = min(math.pi, angle)
            else:
                angle = math.radians(Linc)

            rotation_angle = init_angle - angle

            # rotation of the midrib
            cos_a = cos(rotation_angle)
            sin_a = sin(rotation_angle)

            x1 = x[0] + cos_a * x - sin_a * y
            y1 = y[0] + sin_a * x + cos_a * y

            leaf = (x1, y1) + leaf[2:]

        leaf_mesh = fitting.mesh4(leaf, total_length, length, s_base, s_top,
                                  radius_max)
        if leaf_mesh:
            pts, ind = leaf_mesh
            if len(ind) < 2:
                mesh = None
            else:
                mesh = fitting.plantgl_shape(pts, ind)
        else:
            mesh = None

        return mesh
示例#13
0
    def disperse(self, g, dispersal_units, time_control = None):
        """ Compute distribution of dispersal units by rain splash.
        
        1. Upward dispersal:
        For each source of dispersal units, create a semi-sphere of dispersal 
        normal to the surface of source leaf. In the semi-sphere, target 
        leaves are sorted according to the distance from the source.                
        Then distribute dispersal units from the closer target to the more far.
        The number of dispersal units by target leaf is computed as in Robert et al. 2008
        
        2. Downward dispersal:
        Get leaves in a cylinder whose dimensions are related to the dimesions
        of the semi-sphere in step 1. Then distribute dispersal units from top to bottom.
        
        Parameters
        ----------
        g: MTG
            MTG representing the canopy (and the soil)
        dispersal_units : dict
            Dispersal units emitted by the lesions on leaves
            
        Returns
        -------
        deposits : dict
            Dispersal units deposited on new position on leaves
        """
        try:
            dt = time_control.dt
        except:
            dt = 1
        
        deposits = {}
        if dt>0:
            from alinea.astk.plantgl_utils import get_area_and_normal
            from alinea.alep.architecture import get_leaves
            from openalea.plantgl import all as pgl
            from collections import OrderedDict
            from math import exp, pi, cos, sin, tan
            from random import shuffle
            import numpy as np
            from copy import copy
            
            dmax = self.distance_max
            tesselator = pgl.Tesselator()
            bbc = pgl.BBoxComputer(tesselator)
            leaves = get_leaves(g, label=self.label)
            centroids = g.property('centroid')
            geometries = g.property('geometry')
            _, norm = get_area_and_normal(geometries)
            areas = g.property('area')          
            
            def centroid(vid):
                if is_iterable(geometries[vid]):
                    bbc.process(pgl.Scene(geometries[vid]))
                else:
                    bbc.process(pgl.Scene([pgl.Shape(geometries[vid])]))
                center = bbc.result.getCenter()
                centroids[vid] = center
            
            for source, dus in dispersal_units.iteritems():
                nb_tri = len(norm[source])
                borders = np.linspace(0,1,num=nb_tri)
                
                dus_by_tri = {k:filter(lambda x: borders[k]<x.position[0]<=borders[k+1], dus) 
                                for k in range(nb_tri-1)
                                if len(filter(lambda x: borders[k]<x.position[0]<=borders[k+1], dus))>0.}
                
                for k,v in dus_by_tri.iteritems():
                    source_normal = norm[source][k]
                    
                    ## UPWARD ##
                    # All leaves except the source are potential targets
                    targets = list(leaf for leaf in leaves if leaf in geometries.iterkeys())
                    targets.remove(source)
                    
                    # Compute centroids
                    centroid(source)
                    for vid in targets:
                        centroid(vid)
                    
                    # Sort the vids based on the direction 
                    # TODO : modify source angle
                    Origin = centroids[source]
                    vects = {vid:(centroids[vid]-Origin) for vid in targets 
                            if (centroids[vid]-Origin)*source_normal >= 0}
                    
                    # Sort the vids based on the distance
                    distances = {vid:pgl.norm(vects[vid]) for vid in vects if pgl.norm(vects[vid])<dmax}
                    distances = OrderedDict(sorted(distances.iteritems(), key=lambda x: x[1]))
                    
                    # Distribute the dispersal units
                    if len(distances.values())>0:
                        shuffle(v)
                        n = len(v)
                        sphere_area = 2*pi*distances.values()[-1]**2
                        for leaf_id in distances:
                            area_factor = areas[leaf_id]/sphere_area
                            distance_factor = exp(-self.k * distances[leaf_id])
                            qc = min(n, (n * area_factor * distance_factor))
                            
                            deposits[leaf_id] = v[:int(qc)]
                            del v[:int(qc)]
                            # if len(dus) < 1 or len(deposits[leafid]) < 1:
                            if len(v) < 1:
                                for d in v:
                                    d.disable()
                                # break
                    
                    ## DOWNWARD ##
                    vects2 = {vid:(centroids[vid]-Origin) for vid in targets if not vid in vects}
                    projection = {}

                    alpha = pgl.angle(source_normal, (1,0,0))
                    if alpha>=pi/2. or (alpha<pi/2. and source_normal[2]>=0):
                        alpha+=pi/2.
                    beta = pgl.angle(source_normal, (0,0,1))
                    a = dmax
                    b = dmax*cos(beta)
                    
                    for leaf in vects2:
                        if (centroids[leaf]-Origin)*(source_normal[0], source_normal[1], 0) >= 0:
                            # Big side of the projection semi circle
                            copy_centroid = copy(centroids[leaf])
                            copy_origin = copy(Origin)
                            copy_centroid[2] = 0.
                            copy_origin[2] = 0.
                            if pgl.norm(copy_centroid-copy_origin) < dmax:
                                projection[leaf] = vects2[leaf]
                        else:
                            # Small side of the projection semi ellipse
                            x = vects2[leaf][0]
                            y = vects2[leaf][1]
                            x2 = x*cos(alpha)+y*sin(alpha)
                            y2 = -x*sin(alpha)+y*cos(alpha)
                            if (x2**2)/(a**2) + (y2**2)/(b**2) < 1 :
                                projection[leaf] = vects2[leaf]
                    projection = OrderedDict(sorted(projection.items(), key=lambda x:x[1][2], reverse=True))
                    
                    if len(projection)>0:
                        shuffle(v)
                        n = len(v)
                        n_big = int(n*(beta+pi/2.)/pi)
                        n_small = n - n_big
                        for leaf in projection:
                            copy_centroid = copy(centroids[leaf])
                            copy_origin = copy(Origin)
                            copy_centroid[2] = 0.
                            copy_origin[2] = 0.
                            if (centroids[leaf]-Origin)*(source_normal[0],source_normal[1],0) >= 0:
                                area_factor = areas[leaf]/(pi*dmax**2/2.)
                                dist = pgl.norm(copy_centroid-copy_origin)
                                distance_factor = exp(-self.k * dist)
                                qc = min(n_big, (n_big * area_factor * distance_factor))
                                g.node(leaf).color = (0, 180, 0)
                            else:
                                area_factor = areas[leaf]/(pi*a*b/2.)
                                dist = pgl.norm(copy_centroid-copy_origin)/abs(cos(pgl.angle(source_normal, (1,0,0))+pi/2.))
                                distance_factor = exp(-self.k * dist)
                                qc = min(n_small, (n_small * area_factor * distance_factor))
                                g.node(leaf).color = (0, 0, 180)
                                # import pdb
                                # pdb.set_trace()
                            deposits[leaf] = v[:int(qc)]
                            del v[:int(qc)]
                            
                    for leaf in distances:
                        g.node(leaf).color = (180, 0, 0)
                    
                    # Temp
                    # from alinea.adel.mtg_interpreter import plot3d
                    # from openalea.plantgl.all import Viewer
                    # g.node(source).color=(230, 62, 218)
                    # scene = plot3d(g)
                    # Viewer.display(scene)
                    # import pdb
                    # pdb.set_trace()
        return deposits
示例#14
0
    def disperse(self, g, dispersal_units, time_control = None):
        """ Compute dispersal of spores of powdery mildew by wind in a cone.
        
        For each source of dispersal units, create a cone of dispersal 
        in which target leaves are sorted:
        1. according to the wind direction
        2. according to the angle a0
        3. according to the distance from the source
        
        Then distribute dispersal units from the closer target to the more far.
        The number of dispersal units by target leaf is computed as in
        Calonnec et al. 2008.
        
        Parameters
        ----------
        g: MTG
            MTG representing the canopy (and the soil)
        dispersal_units : dict
            Dispersal units emitted by the lesions on leaves
            
        Returns
        -------
        deposits : dict
            Dispersal units deposited on new position on leaves
        """
        try:
            dt = time_control.dt
        except:
            dt = 1
        
        deposits = {}
        if dt > 0:
            from alinea.alep.architecture import get_leaves
            from openalea.plantgl import all as pgl
            from random import shuffle
            from math import degrees, exp, tan, pi, radians
            from collections import OrderedDict
            geometries = g.property('geometry')
            centroids = g.property('centroid')
            areas = g.property('area')
            wind_directions = g.property('wind_direction')
            tesselator = pgl.Tesselator()
            bbc = pgl.BBoxComputer(tesselator)
        
            leaves = get_leaves(g, label=self.label)

            def centroid(vid):
                if is_iterable(geometries[vid]):
                    bbc.process(pgl.Scene(geometries[vid]))
                else:
                    bbc.process(pgl.Scene([pgl.Shape(geometries[vid])]))
                center = bbc.result.getCenter()
                centroids[vid] = center
            
            def area(vid):
                # areas[vid] = pgl.surface(geometries[vid][0])*1000
                areas[vid] = pgl.surface(geometries[vid][0])

            for source, dus in dispersal_units.iteritems():
                # TODO: Special computation for interception by source leaf
                
                # All other leaves are potential targets
                targets = list(leaf for leaf in leaves if leaf in geometries.iterkeys())
                targets.remove(source)
                
                # Compute centroids
                centroid(source)
                for vid in targets:
                    centroid(vid)
                    # surface(vid)

                # Sort the vids based on the direction 
                Origin = centroids[source]
                vects = {vid:(centroids[vid]-Origin) for vid in targets 
                        if (centroids[vid]-Origin)*wind_directions[source] >= 0}
                
                # Sort the vids based on the angle                
                angles = {vid:degrees(pgl.angle(vect, wind_directions[source])) 
                          for vid, vect in vects.iteritems()
                          if degrees(pgl.angle(vect, wind_directions[source]))<= self.a0}
                
                # Sort the vids based on the distance
                distances = {vid:pgl.norm(vects[vid]) for vid in angles}
                distances = OrderedDict(sorted(distances.iteritems(), key=lambda x: x[1]))
                               
                # Beer law inside cone to take into account leaf coverage
                shuffle(dus)
                n = len(dus)

                if len(distances.values())>0:
                    for leaf in distances:
                        # qc = min(n, (n * (areas[leaf]/self.reduction) * 
                             # exp(-self.cid * distances[leaf]) * 
                             # (self.a0 - angles[leaf])/self.a0))
                        surf_base_cone = pi*(tan(radians(self.a0))*distances[leaf])**2
                        area_factor = min(1, areas[leaf]/surf_base_cone)
                        # import pdb
                        # pdb.set_trace()
                        qc = min(n, (n * area_factor * 
                             exp(-self.cid * distances[leaf]) * 
                             (self.a0 - angles[leaf])/self.a0))
                        
                        # if qc < 1:
                            # for d in dus:
                                # d.disable()
                            # break
                                            
                        deposits[leaf] = dus[:int(qc)]
                        del dus[:int(qc)]
                        # if len(dus) < 1 or len(deposits[leaf]) < 1:
                        if len(dus) < 1:
                            for d in dus:
                                d.disable()
                            break
                        
        return deposits
示例#15
0
def wind_speed_on_leaf(wind_speed=0.,
                       leaf_height=0.,
                       canopy_height=0.,
                       lai=0.,
                       lc=0.2,
                       cd=0.3,
                       is_in_rows=True,
                       row_direction=(1, 0, 0),
                       wind_direction=(1, 0, 0),
                       param_reduc=0.5):
    """ Calculate the wind speed on a given leaf according to its height in the canopy.
    
    This very simple model makes the assumption that the canopy is completely homogeneous.
    The particular case of interrows is not treated. Also it does not take into account
    the wind direction.
    
    The equation comes from appendix C in the following article:
    TUZET, A., PERRIER, A. and LEUNING, R. (2003), 
    A coupled model of stomatal conductance, photosynthesis and transpiration.
    Plant, Cell and Environment, 26: 1097-1116. doi: 10.1046/j.1365-3040.2003.01035.x
   
    link : http://onlinelibrary.wiley.com/doi/10.1046/j.1365-3040.2003.01035.x/abstract

    Parameters
    ----------
    wind_speed: float
        Wind speed (in m.s-1)
    leaf_height: float
        Leaf height in the canopy (in m)
    canopy_heigth: float
        Height of the highest leaf (in m)
    lai: float
        Leaf Area Index of the canopy (in m2 of leaf / m2 of ground)
    lc: float
        Canopy mixing length (in m)
    cd: float
        Leaf drag coefficient (dimensionless)
    is_in_rows: True or False
        Indicate if there are rows between plants
    row_direction: tuple(x,y,z)
        Direction of vine rows
    wind_direction: tuple(x,y,z)
        Wind direction   
    param_reduc: float
        Maximal reduction of eta for winds parallels to row direction
        
    Returns
    -------
    wind_speed_on_leaf: float
        Wind speed on the given leaf
    """
    from math import exp
    from openalea.plantgl import all as pgl

    eta = canopy_height * ((cd * lai / canopy_height) / (2 * lc**2))**(1. / 3)

    if is_in_rows:
        angle = degrees(pgl.angle(row_direction, wind_direction))
        reduction = param_reduc * (1 - angle / 90)
        return wind_speed * exp(
            max(0., eta - reduction) * ((leaf_height / canopy_height) - 1))
    else:
        return wind_speed * exp(eta * ((leaf_height / canopy_height) - 1))
示例#16
0
""" Gather different strategies for modeling dispersal of fungus propagules.