Exemplo n.º 1
0
def turtle_interception(sectors,
                        scene_geometry,
                        energy,
                        output_by_triangle=False,
                        convUnit=0.01):
    """ 
    Calls Caribu for differents energy sources

    :Parameters:
    ------------
    - `sectors` (int)
    - `scene_geometry`
    - `energy` (float)
        e.g. Meteorological mean variables at the global scale, per square meter. Could be:
            - 'PAR' : Quantum PAR (ppfd) in micromol.m-2.sec-1
            - 'Pluie' : Precipitation (mm)
    - 'output_by_triangle' (bool)
        Default 'False'. Choose if return is made by id of geometry or by triangle
    - 'convUnit' (float)
        Default '0.01'. Conversion factor to get meter from scene length unit.

    :Returns:
    ---------
    - 'out_moy' (dict)
        Meteorological variable at the leaf scale
    - 'out_tri' (dict) [optional]
        Meteorological variable at the leaf scale
    """
    energy_scaled = float(energy) * convUnit**2
    energie, emission, direction, elevation, azimuth = turtle.turtle(
        sectors=sectors, energy=energy_scaled)
    sources = list(zip(energie, direction))
    return run_caribu(sources,
                      scene_geometry,
                      output_by_triangle=output_by_triangle)
Exemplo n.º 2
0
def turtle_interception(sectors, scene_geometry, energy, output_by_triangle = False, convUnit = 0.01):
    """ 
    Calls Caribu for differents energy sources

    :Parameters:
    ------------
    - `sectors` (int)
    - `scene_geometry`
    - `energy` (float)
        e.g. Meteorological mean variables at the global scale, per square meter. Could be:
            - 'PAR' : Quantum PAR (ppfd) in micromol.m-2.sec-1
            - 'Pluie' : Precipitation (mm)
    - 'output_by_triangle' (bool)
        Default 'False'. Choose if return is made by id of geometry or by triangle
    - 'convUnit' (float)
        Default '0.01'. Conversion factor to get meter from scene length unit.

    :Returns:
    ---------
    - 'out_moy' (dict)
        Meteorological variable at the leaf scale
    - 'out_tri' (dict) [optional]
        Meteorological variable at the leaf scale
    """
    energy_scaled = float(energy) * convUnit**2
    energie, emission, direction, elevation, azimuth = turtle.turtle(sectors=sectors, energy=energy_scaled) 
    sources = zip(energie,direction)
    return run_caribu(sources, scene_geometry, output_by_triangle=output_by_triangle)
Exemplo n.º 3
0
def irradiance_distribution(meteo,
                            geo_location,
                            irradiance_unit,
                            time_zone='Europe/Paris',
                            turtle_sectors='46',
                            turtle_format='uoc',
                            sun2scene=None,
                            rotation_angle=0.,
                            icosphere_level=None):
    """Calculates irradiance distribution over a semi-hemisphere surrounding the plant [umol m-2 s-1].

    Args:
        meteo (DataFrame): meteo data having the following columns:
            time (datetime): UTC time
            Tac (float): [°C] air temperature
            hs (float): (%) air relative humidity
            Rg or PPFD (float): respectively global [W m-2] or photosynthetic photon flux density [umol m-2 s-1]
            u (float): [m s-1] wind speed
            Ca (float): [ppm] CO2 concentration in the air
            Pa (float): [kPa] atmospheric pressure
        geo_location: tuple of (latitude [°], longitude [°], elevation [°])
        irradiance_unit (str): unit of the irradiance flux density,
            one of ('Rg_Watt/m2', 'RgPAR_Watt/m2', 'PPFD_umol/m2/s')
        time_zone (str): a 'pytz.timezone' (e.g. 'Europe/Paris')
        turtle_sectors (str): number of turtle sectors (see :func:`turtle` from `sky_tools` package)
        turtle_format (str): format irradiance distribution, could be 'soc', or 'uoc'
            (see :func:`turtle` from `sky_tools` package for details)
        sun2scene (pgl.scene): if provided, a sun object (sphere) is added to it
        rotation_angle (float): [°] counter clockwise azimuth between the default X-axis direction (South) and real
            direction of X-axis
        icosphere_level (int): the level of refinement of the dual icosphere
            (see :func:`alinea.astk.icosphere.turtle_dome` for details)

    Returns:
        [umol m-2 s-1] tuple of tuples, cumulative irradiance flux densities distributed across the semi-hemisphere
            surrounding the plant
        (float) [-] diffuse-to-total irradiance ratio

    Notes:
        meteo data can consist of only one line (single event) or multiple lines.
            In the latter case, this function returns accumulated irradiance throughtout the entire periode with sun
            positions corresponding to each time step.


    TODO: replace by the icosphere procedure

    """
    diffuse_ratio = []
    nrj_sum = 0
    for idate, date in enumerate(meteo.index):

        if irradiance_unit.split('_')[0] == 'PPFD':
            energy = meteo.loc[date, :].PPFD
        else:
            try:
                energy = meteo.loc[date, :].Rg
            except:
                raise TypeError(
                    "'irradiance_unit' must be one of the following 'Rg_Watt/m2', 'RgPAR_Watt/m2' or'PPFD_umol/m2/s'."
                )

        # First check: convert irradiance to W m-2 (Spitters method always gets energy flux as Rg Watt m-2)
        corr = e_conv_Wm2(irradiance_unit)
        energy = energy * corr

        # Second check: Convert to UTC datetime
        latitude, longitude, elevation = [geo_location[x] for x in range(3)]
        temperature = meteo.Tac.values[0]
        date_utc, lst = local2solar(date, latitude, longitude, time_zone,
                                    temperature)
        doy_utc = date_utc.timetuple().tm_yday
        hour_utc = date_utc.hour + date_utc.minute / 60.
        # R: Attention, ne renvoie pas exactement le même RdRsH que celui du noeud 'spitters_horaire' dans topvine.
        diffuse_ratio_hourly = RdRsH(energy, doy_utc, hour_utc, latitude)
        diffuse_ratio.append(diffuse_ratio_hourly * energy)
        nrj_sum += energy

        # Third and final check: it is always desirable to get energy as PPFD
        energy = energy * (0.48 * 4.6)

        irradiance_diff = diffuse_ratio_hourly * energy
        irradiance_dir = (1 - diffuse_ratio_hourly) * energy

        # diffuse irradiance
        if not icosphere_level:
            energy2, emission, direction, elevation, azimuth = turtle.turtle(
                sectors=turtle_sectors,
                format=turtle_format,
                energy=irradiance_diff)
        else:
            vert, fac = ico.turtle_dome(icosphere_level)
            direction = ico.sample_faces(vert, fac, iter=None,
                                         spheric=False).values()
            direction = [idirect[0] for idirect in direction]
            direction = map(lambda x: tuple(list(x[:2]) + [-x[2]]), direction)

        sky = list(
            zip(
                len(direction) * [irradiance_diff / len(direction)],
                direction))

        # direct irradiance
        sun = Gensun.Gensun()(Rsun=irradiance_dir,
                              DOY=doy_utc,
                              heureTU=hour_utc,
                              lat=latitude)
        sun = GetLightsSun.GetLightsSun(sun)
        sun_data = [(float(sun.split()[0]), (float(sun.split()[1]),
                                             float(sun.split()[2]),
                                             float(sun.split()[3])))]

        # diffuse irradiance (distributed over a dome) + direct irradiance (localized as point source(s))
        source = sky.__add__(sun_data)
        source = [list(isource) for isource in source]

        try:
            for j in range(len(source) - 1):
                source_cum[j][0] += source[j][0]
            source_cum.append(source[-1])
        except NameError:
            source_cum = []
            for isource in source:
                source_cum.append([isource[0], isource[1]])

        if date == meteo.index[-1]:
            source_cum = [tuple(isource) for isource in source_cum]

    # Rotate irradiance sources to cope with plant row orientation
    if rotation_angle != 0.:
        v_energy = [vec[0] for vec in source_cum]
        v_coord = [
            tuple(
                vector_rotation(vec[1], (0., 0., 1.), deg2rad(rotation_angle)))
            for vec in source_cum
        ]
        source_cum = zip(v_energy, v_coord)

    # Add Sun to an existing pgl.scene
    if sun2scene != None:
        xSun, ySun, zSun = -500. * array(
            [source_cum[-1][1][i] for i in range(3)])
        if zSun >= 0:
            ss = Translated(xSun, ySun, zSun, Sphere(20))
            sun = Shape(ss, Material('yellow', Color3(255, 255, 0)))
            sun2scene.add(sun)
        Viewer.display(sun2scene)

    # Diffuse_ratio mean
    if nrj_sum > 0:
        diffuse_ratio = sum(diffuse_ratio) / nrj_sum
    else:
        diffuse_ratio = 1

    # Filter black sources up to the penultimate (hsCaribu expect at least one source)
    source_cum = [v for v in source_cum if v[0] > 0]
    if len(source_cum) == 0:  # night
        source_cum = [(0, (0, 0, -1))]

    return source_cum, diffuse_ratio
Exemplo n.º 4
0
def form_factors_simplified(g,
                            pattern=None,
                            infinite=False,
                            leaf_lbl_prefix='L',
                            turtle_sectors='46',
                            icosphere_level=3,
                            unit_scene_length='cm'):
    """Computes sky and soil contribution factors (resp. k_sky and k_soil) to the energy budget equation.
    Both factors are calculated and attributed to each element of the scene.

    Args:
        g: a multiscale tree graph object
        pattern (tuple): 2D Coordinates of the domain bounding the scene for its replication.
            (xmin, ymin, xmax, ymax) scene is not bounded along z axis.
            Alternatively a *.8 file.
            if `None` (default), scene is not repeated
        infinite (bool): Whether the scene should be considered as infinite
            (see :func:`runCaribu` from `CaribuScene` package)
        leaf_lbl_prefix (str): the prefix of the leaf label
        turtle_sectors (str): number of turtle sectors
            (see :func:`turtle` from `sky_tools` package)
        icosphere_level (int): the level of refinement of the dual icosphere
            (see :func:`alinea.astk.icosphere.turtle_dome` for details)
        unit_scene_length (str): the unit of length used for scene coordinate and for pattern
            (should be one of `CaribuScene.units` default)

    Returns:


    Notes:
        This function is a simplified approximation of the form factors matrix which is calculated by the
            function :func:`form_factors_matrix`. The canopy is turned upside-down and light is projected in each
            case to estimate the respective contribution of the sky ({z}>=0) and soil ({z}<=0) to energy budget
            calculations. This is printed as pirouette-cacahuete in the console!
        When **icosphere_level** is defined, **turtle_sectors** is ignored.

    """
    geom = g.property('geometry')
    label = g.property('label')
    opts = {
        'SW': {
            vid: ((0.001, 0) if label[vid].startswith(leaf_lbl_prefix) else
                  (0.001, ))
            for vid in geom
        }
    }
    if not icosphere_level:
        energy, emission, direction, elevation, azimuth = turtle.turtle(
            sectors=turtle_sectors, format='uoc', energy=1.)
    else:
        vert, fac = ico.turtle_dome(icosphere_level)
        direction = ico.sample_faces(vert, fac, iter=None,
                                     spheric=False).values()
        direction = [i[0] for i in direction]
        direction = map(lambda x: tuple(list(x[:2]) + [-x[2]]), direction)

    caribu_source = zip(len(direction) * [1. / len(direction)], direction)
    k_soil, k_sky, k_leaves = {}, {}, {}

    for s in ('pirouette', 'cacahuete'):
        print '... %s' % s
        if s == 'pirouette':
            scene = pgl_scene(g, flip=True)
        else:
            scene = pgl_scene(g)

        caribu_scene = CaribuScene(scene,
                                   light=caribu_source,
                                   opt=opts,
                                   scene_unit=unit_scene_length,
                                   pattern=pattern)

        # Run caribu
        raw, aggregated = caribu_scene.run(direct=True,
                                           infinite=infinite,
                                           split_face=False,
                                           simplify=True)

        if s == 'pirouette':
            k_soil_dict = aggregated['Ei']
            max_k_soil = float(max(k_soil_dict.values()))
            k_soil = {
                vid: k_soil_dict[vid] / max_k_soil
                for vid in k_soil_dict
            }
        elif s == 'cacahuete':
            k_sky_dict = aggregated['Ei']
            max_k_sky = float(max(k_sky_dict.values()))
            k_sky = {vid: k_sky_dict[vid] / max_k_sky for vid in k_sky_dict}

    for vid in aggregated['Ei']:
        k_leaves[vid] = max(0., 2. - (k_soil[vid] + k_sky[vid]))

    return k_soil, k_sky, k_leaves