def test_run_monochrome(): pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] sensors = {'solem': [[(0, 0, 2), (1, 0, 2), (0, 1, 2)], [(1, 0, 2), (1, 1, 2), (0, 1, 2)]], 'kipp': [[(0, 0, 3), (1, 0, 3), (0, 1, 3)]]} pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain) # raycasting out, agg = cscene.run(direct=True, infinite=False, sensors=sensors) assert len(out) == 1 assert len(out[cscene.default_band]['Eabs']) == 2 assert len(out[cscene.default_band]['Eabs']['lower']) == 2 assert len(out[cscene.default_band]['Eabs']['upper']) == 1 assert len(out[cscene.default_band]['sensors']['Ei']) == 2 # radiosity out, agg = cscene.run(direct=False, infinite=False) assert len(out) == 1 assert len(out[cscene.default_band]['Eabs']) == 2 assert len(out[cscene.default_band]['Eabs']['lower']) == 2 assert len(out[cscene.default_band]['Eabs']['upper']) == 1 # mixed radiosity out, agg = cscene.run(direct=False, infinite=True) assert len(out) == 1 assert len(out[cscene.default_band]['Eabs']) == 2 assert len(out[cscene.default_band]['Eabs']['lower']) == 2 assert len(out[cscene.default_band]['Eabs']['upper']) == 1 return out, agg
def test_run_polychrome(): pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] sensors = { 'solem': [[(0, 0, 2), (1, 0, 2), (0, 1, 2)], [(1, 0, 2), (1, 1, 2), (0, 1, 2)]], 'kipp': [[(0, 0, 3), (1, 0, 3), (0, 1, 3)]] } pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} opt = { 'par': { 'lower': (0.1, ), 'upper': (0.1, ) }, 'nir': { 'lower': (0.5, ), 'upper': (0.5, ) } } domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain, opt=opt) # raycasting out, agg = cscene.run(direct=True, infinite=False, sensors=sensors) assert 'par' in out.keys() assert 'nir' in out.keys() assert len(out['par']['Eabs']) == 2 assert len(out['par']['Eabs']['lower']) == 2 assert len(out['nir']['Eabs']) == 2 assert out['par']['Eabs']['upper'][0] != out['nir']['Eabs']['upper'][0] # radiosity out, agg = cscene.run(direct=False, infinite=False) assert 'par' in out.keys() assert 'nir' in out.keys() assert len(out['par']['Eabs']) == 2 assert len(out['par']['Eabs']['lower']) == 2 assert len(out['nir']['Eabs']) == 2 assert out['par']['Eabs']['upper'][0] != out['nir']['Eabs']['upper'][0] # mixed radiosity out, agg = cscene.run(direct=False, infinite=True) assert 'par' in out.keys() assert 'nir' in out.keys() assert len(out['par']['Eabs']) == 2 assert len(out['par']['Eabs']['lower']) == 2 assert len(out['nir']['Eabs']) == 2 assert out['par']['Eabs']['upper'][0] != out['nir']['Eabs']['upper'][0] return out, agg
def illuminate(scene, light=None, pattern=None, scene_unit='cm', north=0): """Illuminate scene Args: scene: the scene (plantgl) light: lights. If None a vertical light is used pattern: the toric canopy pattern. If None, no pattern is used scene_unit: string indicating length unit in the scene (eg 'cm') north: the angle (deg, positive clockwise) from X+ to North (default: 0) Returns: """ infinite = False if pattern is not None: infinite = True if light is not None: light = light_sources(*light, orientation=north) cs = CaribuScene(scene, light=light, scene_unit=scene_unit, pattern=pattern) raw, agg = cs.run(direct=True, simplify=True, infinite=infinite) return cs, raw['Ei'], pandas.DataFrame(agg)
def illuminate(g, isolated=True, density=9, clear_sky=False, daydate=_daydate, longitude=_longitude, latitude=_latitude, altitude=_altitude, timezone=_timezone): """ Illuminate a plant Args: isolated : is the plant isolated or within a canopy ? clear_sky: use clear_sky (homogeneous sky is used otherwise) irradiance: (float) sum of horizontal irradiance of all sources. If None diffuse horizontal clear_sky irradiance are used for clear_sky type and 20% attenuated clear_sky global horizontal irradiances are used for soc and uoc types. dates: A pandas datetime index (as generated by pandas.date_range). If None, hourly values for daydate are used. daydate: (str) yyyy-mm-dd (not used if dates is not None). longitude: (float) in degrees latitude: (float) in degrees altitude: (float) in meter timezone:(str) the time zone (not used if dates are already localised) Returns: elevation (degrees), azimuth (degrees, from North positive clockwise), and horizontal irradiance of sources """ if not clear_sky: light = light_sources(*sky_sources()) else: sun, sky = sun_sky_sources(daydate=daydate, longitude=longitude, latitude=latitude, altitude=altitude, timezone=timezone, normalisation=1) light = light_sources(*sun) + light_sources(*sky) inter_row = 80 inter_plant = 1. / density / (inter_row / 100.) * 100 pattern = (-0.5 * inter_row, -0.5 * inter_plant, 0.5 * inter_row, 0.5 * inter_plant) cs = CaribuScene(g, light=light, pattern=pattern, scene_unit='cm') raw, agg = cs.run(direct=True, simplify=True, infinite=not isolated) return cs, raw, agg
def illuminate(g, isolated=True): light = light_sources(*sky_sources()) # density =9 pl/m2 density = 9 inter_row = 80 inter_plant = 1. / density / (inter_row / 100.) * 100 pattern = (-0.5 * inter_row, -0.5 * inter_plant, 0.5 * inter_row, 0.5 * inter_plant) cs = CaribuScene(g, light=light, pattern=pattern, scene_unit='cm') raw, agg = cs.run(direct=True, simplify=True, infinite=not isolated) return cs, raw, agg
def run_caribu(sources, scene, opticals='stem', optical_properties=None, output_by_triangle=False, domain=None, zsoil=None): """ Calls Caribu for differents energy sources :Parameters: ------------ - `sources` (int) - `scene` : any scene format accepted by CaribuScene. This will be cast to a list of plantGL shapes - opticals : a list of optical property labels ('leaf', 'soil', 'stem', 'ear' or 'awn') for all shapes in scene. If a shorter opticale list is provided, it will be recycled to match eength of shape list - `optical_properties`: a filename (*.opt). - `output_by_triangle` (bool) Default 'False'. Return is done by id of geometry. If 'True', return is done by triangle. :Returns: --------- - 'out_moy' (dict) A dict of intercepted variable (energy) per id - 'out_tri' (dict) only if output_by_triangle = True, return a tuple (out_moy, out_tri) A dict of intercepted variable (energy) per triangle """ raise DeprecationWarning('This function is deprecated, use CaribuScene / caribu_star instead') from alinea.caribu.label import simple_canlabel from alinea.caribu.file_adaptor import read_opt, build_materials n, soil_reflectance, po = read_opt(optical_properties) if not isinstance(opticals, list): opticals = [opticals] if len(opticals) < len(scene): opticals = opticals * (len(scene) / len(opticals)) + [opticals[i] for i in range(len(scene) % len(opticals))] labels = [simple_canlabel(opt) for opt in opticals] materials = build_materials(labels, po, soil_reflectance) band = CaribuScene.default_band c_scene = CaribuScene(scene=scene, light=sources, pattern=domain, opt={band: materials}, soil_reflectance={band: soil_reflectance}) ifty = False if domain is not None: ifty = True # if zsoil is not None: # idmap_soil = c_scene.addSoil(zsoil=zsoil) # idmap.update(idmap_soil) raw, aggregated = c_scene.run(direct=True, infinite=ifty, simplify=True) if output_by_triangle: out = raw else: out = aggregated return out
def test_run_polychrome(): pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] sensors = {'solem': [[(0, 0, 2), (1, 0, 2), (0, 1, 2)], [(1, 0, 2), (1, 1, 2), (0, 1, 2)]], 'kipp': [[(0, 0, 3), (1, 0, 3), (0, 1, 3)]]} pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} opt = {'par': {'lower': (0.1,), 'upper': (0.1,)}, 'nir': {'lower': (0.5,), 'upper': (0.5,)}} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain, opt=opt) # raycasting out, agg = cscene.run(direct=True, infinite=False,sensors=sensors) assert 'par' in out.keys() assert 'nir' in out.keys() assert len(out['par']['Eabs']) == 2 assert len(out['par']['Eabs']['lower']) == 2 assert len(out['nir']['Eabs']) == 2 assert out['par']['Eabs']['upper'][0] != out['nir']['Eabs']['upper'][0] # radiosity out, agg = cscene.run(direct=False, infinite=False) assert 'par' in out.keys() assert 'nir' in out.keys() assert len(out['par']['Eabs']) == 2 assert len(out['par']['Eabs']['lower']) == 2 assert len(out['nir']['Eabs']) == 2 assert out['par']['Eabs']['upper'][0] != out['nir']['Eabs']['upper'][0] # mixed radiosity out, agg = cscene.run(direct=False, infinite=True) assert 'par' in out.keys() assert 'nir' in out.keys() assert len(out['par']['Eabs']) == 2 assert len(out['par']['Eabs']['lower']) == 2 assert len(out['nir']['Eabs']) == 2 assert out['par']['Eabs']['upper'][0] != out['nir']['Eabs']['upper'][0] return out, agg
def test_unit(): # scene in meter pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain) out, agg = cscene.run(direct=True, infinite=False, simplify=True) assert_almost_equal(sum(out['area']['lower']), 1, 0) assert_almost_equal(sum(out['Ei']['upper']), 1, 0) # same scene but now in centimeter pts_1 = [(0, 0, 0), (100, 0, 0), (0, 100, 0)] pts_2 = [(0, 0, 1e-3), (1, 0, 1e-3), (0, 1, 1e-3)] pts_3 = [(100, 0, 0), (100, 100, 0), (0, 100, 0)] pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 100, 100) cscene = CaribuScene(pyscene, pattern=domain, scene_unit='cm') out, agg = cscene.run(direct=True, infinite=False, simplify=True) assert_almost_equal(sum(out['area']['lower']), 1, 0) assert_almost_equal(sum(out['Ei']['upper']), 1, 0)
def test_display(): # standard scene pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain) cscene.plot(display=False) out, agg = cscene.run(direct=True, infinite=False, simplify=True) cscene.plot(agg['Ei'], display=False) cscene.plot(out['Ei'], display=False) # include null triangle pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 0, 0), (0, 1, 0)] pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain) out, agg = cscene.run(direct=True, infinite=False, simplify=True) cscene.plot(out['Ei'], display=False)
def illuminate(scene, sky=None, sun=None, pattern=None): if sky is None and sun is None: sky = sky_sources() light = [] if sky is not None: light += light_sources(*sky) if sun is not None: light += light_sources(*sun) infinite = False if pattern is not None: infinite = True cs = CaribuScene(scene, light=light, scene_unit='cm', pattern=pattern) raw, agg = cs.run(direct=True, simplify=True, infinite=infinite) return cs, raw, agg
def test_run_monochrome(): pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] sensors = { 'solem': [[(0, 0, 2), (1, 0, 2), (0, 1, 2)], [(1, 0, 2), (1, 1, 2), (0, 1, 2)]], 'kipp': [[(0, 0, 3), (1, 0, 3), (0, 1, 3)]] } pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain) # raycasting out, agg = cscene.run(direct=True, infinite=False, sensors=sensors) assert len(out) == 1 assert len(out[cscene.default_band]['Eabs']) == 2 assert len(out[cscene.default_band]['Eabs']['lower']) == 2 assert len(out[cscene.default_band]['Eabs']['upper']) == 1 assert len(out[cscene.default_band]['sensors']['Ei']) == 2 # radiosity out, agg = cscene.run(direct=False, infinite=False) assert len(out) == 1 assert len(out[cscene.default_band]['Eabs']) == 2 assert len(out[cscene.default_band]['Eabs']['lower']) == 2 assert len(out[cscene.default_band]['Eabs']['upper']) == 1 # mixed radiosity out, agg = cscene.run(direct=False, infinite=True) assert len(out) == 1 assert len(out[cscene.default_band]['Eabs']) == 2 assert len(out[cscene.default_band]['Eabs']['lower']) == 2 assert len(out[cscene.default_band]['Eabs']['upper']) == 1 return out, agg
def test_aggregation(): # simple case pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain) out, agg = cscene.run(direct=True, infinite=False, simplify=True) assert_almost_equal(agg['area']['lower'], 1, 0) assert_almost_equal(agg['Ei']['lower'], 0.5, 1) assert_almost_equal(agg['Ei']['upper'], 1, 0) # pts3 now define a null triangle pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 0, 0), (0, 1, 0)] pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain) out, agg = cscene.run(direct=True, infinite=False, simplify=True) assert_almost_equal(agg['area']['lower'], 0.5, 0) assert_almost_equal(agg['Ei']['lower'], 0, 1) assert_almost_equal(agg['Ei']['upper'], 1, 0)
def test_soil(): pts_1 = [(0, 0, 0), (1, 0, 0), (0, 1, 0)] pts_2 = [(0, 0, 1e-5), (1, 0, 1e-5), (0, 1, 1e-5)] pts_3 = [(1, 0, 0), (1, 1, 0), (0, 1, 0)] pyscene = {'lower': [pts_1, pts_3], 'upper': [pts_2]} domain = (0, 0, 1, 1) cscene = CaribuScene(pyscene, pattern=domain, soil_mesh=1) out, agg = cscene.run(direct=True, infinite=False, simplify=True) assert_almost_equal(agg['area']['lower'], 1, 0) assert_almost_equal(agg['Ei']['lower'], 0.5, 1) assert_almost_equal(agg['Ei']['upper'], 1, 0) assert len(cscene.soil) == 2 assert len(cscene.soil_raw[cscene.default_band]['Ei']) == 2 soil = cscene.soil_aggregated[cscene.default_band] assert_almost_equal(soil['Ei'], 0, 1) assert_almost_equal(soil['area'], 1, 1)
def _caribu_call(scene, directions, opt=None, domain=None, convUnit=None): """ adaptor for backward compatibility of macros calling caribu """ energie, emission, direction, elevation, azimuth = turtle(sectors=str(directions), energy=1) sources = zip(energie, direction) c_scene = CaribuScene(scene=scene, light=sources, opt=opt, pattern=domain) if convUnit is not None: c_scene.conv_unit = convUnit ifty = False if domain is not None: ifty = True raw, aggregated = c_scene.run(direct=True, infinite=ifty, simplify=True) return c_scene, raw, aggregated
def hsCaribu(mtg, unit_scene_length, geometry='geometry', opticals='opticals', consider=None, source=None, direct=True, infinite=False, nz=50, ds=0.5, pattern=None, soil_reflectance=0.15): """Calculates intercepted and absorbed irradiance flux densities by the plant canopy. Args: mtg (MTG): plant Multiscale Tree Graph unit_scene_length (str): the unit of length used for scene coordinate and for pattern (should be one of `CaribuScene.units` default) geometry (str): the name of the property to use for computing scene geometry from the mtg opticals (str): the name of the property to use for caribu optical properties consider (list(int)): vertices to be considered for the computation, if None (default) all vertices with a geometry are considered source (list): a tuple of tuples, giving energy unit and sky coordinates, if None, a unit zenital source is used direct: see :func:`runCaribu` from `CaribuScene` package infinite: see :func:`runCaribu` from `CaribuScene` package nz: see :func:`runCaribu` from `CaribuScene` package ds: see :func:`runCaribu` from `CaribuScene` package pattern: see :func:`runCaribu` from `CaribuScene` package soil_reflectance (float): [-] the reflectance of the soil (between 0 and 1) Returns: mtg object with the incident irradiance (`Ei`) and absorbed irradiance (`Eabs`), both in [umol m-2 s-1], attached to mtg vertices as properties. Notes: `Ei` and `Eabs` units are returned in [umol m-2 s-1] **REGARDLESS** of the `unit_scence_length` type. """ assert geometry in mtg.property_names() assert opticals in mtg.property_names() # Currently used as a dummy variable wave_band = 'SW' if source is None: source = [(1, (0, 0, -1))] # Hack : would be much better to have geometry as a caribuscene args directly geom0 = mtg.property(geometry) geometry0 = {} remove_geometry = 'geometry' not in mtg.property_names() if consider is not None: geom0 = {k: v for k, v in mtg.property(geometry).items()} mtg.properties()[geometry] = { k: v for k, v in mtg.property(geometry).items() if k in consider } if geometry != 'geometry' and 'geometry' in mtg.property_names(): geometry0 = {k: v for k, v in mtg.property('geometry').items()} mtg.properties()['geometry'] = mtg.property(geometry) caribu_scene = None # Use a try/except/finally block to allow restoring geometry if block fails try: # Run caribu only if irradiance is greater that 0 if sum([x[0] for x in source]) == 0.: mtg.properties()['Ei'] = {k: 0. for k in mtg.property('geometry')} mtg.properties()['Eabs'] = { k: 0. for k in mtg.property('geometry') } else: # Attaching optical properties to each organ of the plant mock-up opts = {wave_band: mtg.property(opticals)} # Setup CaribuScene caribu_scene = CaribuScene( mtg, light=source, opt=opts, soil_reflectance={wave_band: soil_reflectance}, scene_unit=unit_scene_length, pattern=pattern) # Run caribu raw, aggregated = caribu_scene.run(direct=direct, infinite=infinite, d_sphere=ds, layers=nz, split_face=False) # Attaching output to MTG mtg.properties()['Ei'] = aggregated[wave_band]['Ei'] mtg.properties()['Eabs'] = aggregated[wave_band]['Eabs'] except: pass finally: mtg.properties()[geometry] = geom0 if remove_geometry: mtg.remove_property('geometry') else: if len(geometry0) > 0: mtg.properties()['geometry'] = geometry0 return mtg, caribu_scene
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