예제 #1
0
def test_as_scene_mesh():
    spc = SurfacicPointCloud(0, 0, 0, 1)
    sc = spc.as_scene_mesh()
    assert 0 in sc
    v, f, = sc[0]
    assert len(f) == 1
    assert len(v) == 3
예제 #2
0
def test_data_frame():
    spc = SurfacicPointCloud(0, 0, 0, 1)
    df = spc.as_data_frame()
    assert df.shape == (1, 8)
    spc.properties.update({'a_property': {0: 3}})
    df = spc.as_data_frame()
    assert df.shape == (1, 9)
예제 #3
0
def test_as_triangle_scene():
    spc = SurfacicPointCloud(0, 0, 0, 1)
    sc = spc.as_triangle_scene()
    assert 0 in sc
    triangles = sc[0]
    assert len(triangles) == 1
    pts = triangles[0]
    assert len(pts) == 3
    assert len(pts[0]) == 3
예제 #4
0
def test_spc_instantiation():
    spc = SurfacicPointCloud(0, 0, 0, 1)
    for w in ('x', 'y', 'z', 'area', 'shape_id', 'normals', 'properties',
              'size'):
        assert hasattr(spc, w)
    spc = SurfacicPointCloud(100, 100, 100, 10000, scene_unit='cm')
    assert spc.x == spc.y == spc.z == spc.area == 1  # m2

    faces = (range(3), )
    vertices = ((0, 0, 0), (1, 0, 0), (0, 1, 0))
    sc = {'0': (vertices, faces)}
    spc = SurfacicPointCloud.from_scene_mesh(sc)
    assert spc.area == 0.5
    numpy.testing.assert_array_equal(spc.normals, ((0, 0, 1), ))
예제 #5
0
def test_bbox():
    faces = ((0, 1, 2), (0, 2, 0), (0, 1, 3))
    vertices = ((0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1))
    sc = {'0': (vertices, faces)}
    spc = SurfacicPointCloud.from_scene_mesh(sc)
    expected = ((0.0, 0.0, 0.0), [1. / 3] * 3)
    numpy.testing.assert_almost_equal(spc.bbox(), expected)
예제 #6
0
def test_subset():
    faces = ((0, 1, 2), (0, 2, 3), (0, 1, 3))
    vertices = ((0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1))
    sc = {
        1: (vertices, (faces[1], )),
        2: (vertices, [faces[i] for i in (0, 2)])
    }
    spc = SurfacicPointCloud.from_scene_mesh(sc)
    sub = spc.subset(point_id=1)
    assert len(sub.as_data_frame() == 1)
    sub = spc.subset(shape_id=2)
    assert len(sub.as_data_frame() == 2)
예제 #7
0
def test_sky_source_type():
    # small Horizontal surface in  big voxel
    spc = SurfacicPointCloud(0.5, 0.5, 0.5, area=0.1, normals=[(0, 0, 1)])
    # sun_source
    ratp = RatpScene(spc, resolution=(1, 1, 1), rsoil=0, nbinclin=90)
    dfsun = ratp.do_irradiation(sun_sources=([90], [0], [1]))
    dfsky = ratp.do_irradiation(sky_sources=([90], [0], [1]))
    assert dfsky.PAR.values > dfsun.PAR.values
    dfscat = ratp.do_irradiation(sun_sources=([90], [0], [1]),
                                 sky_sources=([90], [0], [0]),
                                 scattering_indicatrix=[1])
    numpy.testing.assert_almost_equal(dfsky.PAR.values,
                                      dfscat.PAR.values,
                                      decimal=2)
예제 #8
0
def test_inclinations():
    faces = ((0, 1, 2), (0, 2, 3), (0, 1, 3))
    vertices = ((0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1))
    sc = {
        1: (vertices, (faces[1], )),
        2: (vertices, [faces[i] for i in (0, 2)])
    }
    spc = SurfacicPointCloud.from_scene_mesh(sc)
    df = spc.inclinations()
    inc = {
        g: x.to_dict('list')['inclination']
        for g, x in df.groupby('shape_id')
    }
    numpy.testing.assert_array_equal(inc[1], [90.0])
    numpy.testing.assert_array_equal(inc[2], [0.0, 90.0])
예제 #9
0
def test_serialisation():
    spc = SurfacicPointCloud(0, 0, 0, 1)
    try:
        tmpdir = tempfile.mkdtemp()
        path = os.path.join(tmpdir, 'test.csv')
        spc.save(path)
        spc2 = SurfacicPointCloud.load(path)
        assert spc.x == spc2.x
        numpy.testing.assert_almost_equal(spc.normals, spc2.normals)

        spc.properties.update({'a_property': {0: 3}})
        spc.save(path)
        spc2 = SurfacicPointCloud.load(path)
        assert 'a_property' in spc2.properties
        for k in spc.properties['a_property']:
            assert k in spc2.properties['a_property']
    except Exception as e:
        raise e
    finally:
        os.remove(path)
        os.rmdir(tmpdir)
예제 #10
0
def test_sources():
    # small Horizontal surface in  big voxel
    spc = SurfacicPointCloud(0.5, 0.5, 0.5, area=0.1, normals=[(0, 0, 1)])
    # nearly horizontal square, zenith light
    ratp = RatpScene(spc, resolution=(1, 1, 1), rsoil=0, nbinclin=90)
    dfv = ratp.do_irradiation(sun_sources=([90], [0], [1]))
    numpy.testing.assert_almost_equal(dfv.PAR.values, 0.96, decimal=2)
    # zenith light, irrad=10
    dfv = ratp.do_irradiation(sun_sources=([90], [0], [10]))
    numpy.testing.assert_almost_equal(dfv.PAR.values, 9.66, decimal=2)
    # inclined light
    dfv = ratp.do_irradiation(sun_sources=([45], [0],
                                           [numpy.sin(numpy.radians(45))]))
    numpy.testing.assert_almost_equal(dfv.PAR.values, 0.69, decimal=2)
    # inclined + vertical light
    dfv = ratp.do_irradiation(sun_sources=([45, 90], [0, 0],
                                           [numpy.sin(numpy.radians(45)), 1]))
    numpy.testing.assert_almost_equal(dfv.PAR.values, 1.66, decimal=2)
    # vertical surface, zenith light
    vd = [0] * 89 + [1]
    vh = [1] + [0] * 89
    dfv = ratp.do_irradiation(sun_sources=([90], [0], [1]), distinc=[vd])
    numpy.testing.assert_almost_equal(dfv.PAR.values, 0.008, decimal=3)
    # vertical surface, near horizontal light
    dfv = ratp.do_irradiation(sun_sources=([1], [0],
                                           [numpy.sin(numpy.radians(1))]),
                              distinc=[vd])
    numpy.testing.assert_almost_equal(dfv.PAR.values, 0.63, decimal=2)

    # Test Orientation
    # Three filled voxels with lad heterogeneity along X+ (North/South)
    spc = SurfacicPointCloud([0.5, 1.5, 2.5], [0.5] * 3, [0.5] * 3,
                             [0.1, 0.1, 100])
    ratp = RatpScene(spc,
                     resolution=(1, 1, 1),
                     rsoil=0,
                     rleaf=0,
                     nbinclin=90,
                     distinc=[vd],
                     mu=1)
    # radiant source coming from X+
    dfv = ratp.do_irradiation(sun_sources=([1], [0],
                                           [numpy.sin(numpy.radians(1))]))
    v1 = dfv.loc[dfv.jx == 1, 'PAR'].values
    # source coming from X-
    dfv = ratp.do_irradiation(sun_sources=([1], [180],
                                           [numpy.sin(numpy.radians(1))]))
    v2 = dfv.loc[dfv.jx == 1, 'PAR'].values
    # compare irrad on central voxel
    assert v2 > v1
    # perpendicular source coming from Y-
    dfv = ratp.do_irradiation(sun_sources=([1], [90],
                                           [numpy.sin(numpy.radians(1))]))
    numpy.testing.assert_almost_equal(dfv.loc[dfv.jx == 1, 'PAR'].values,
                                      dfv.loc[dfv.jx == 0, 'PAR'].values,
                                      decimal=2)
    # Test left-right / East-West
    # a scene with high lad on Y- (east), north being towards X+
    spc = SurfacicPointCloud([0.5] * 3, [0.5, 1.5, 2.5], [0.5] * 3,
                             [100, 0.1, 0.1])
    ratp = RatpScene(spc,
                     resolution=(1, 1, 1),
                     rsoil=0,
                     rleaf=0,
                     nbinclin=90,
                     distinc=[vd],
                     mu=1)
    # radiant source coming from east (north, positive clockwise convention)
    dfv = ratp.do_irradiation(sun_sources=([1], [90],
                                           [numpy.sin(numpy.radians(1))]))
    v1 = dfv.loc[dfv.jy == 1, 'PAR'].values
    # source coming from west
    dfv = ratp.do_irradiation(sun_sources=([1], [-90],
                                           [numpy.sin(numpy.radians(1))]))
    v2 = dfv.loc[dfv.jy == 1, 'PAR'].values
    assert v2 > v1
    # a scene with high lad on X+ (east), north being towards Y+
    spc = SurfacicPointCloud([0.5, 1.5, 2.5], [0.5] * 3, [0.5] * 3,
                             [0.1, 0.1, 100])
    ratp = RatpScene(spc,
                     resolution=(1, 1, 1),
                     rsoil=0,
                     rleaf=0,
                     nbinclin=90,
                     distinc=[vd],
                     mu=1,
                     orientation=-90)
    # radiant source coming from east (north, positive clockwise convention)
    dfv = ratp.do_irradiation(sun_sources=([1], [90],
                                           [numpy.sin(numpy.radians(1))]))
    v1 = dfv.loc[dfv.jx == 1, 'PAR'].values
    # source coming from west
    dfv = ratp.do_irradiation(sun_sources=([1], [-90],
                                           [numpy.sin(numpy.radians(1))]))
    v2 = dfv.loc[dfv.jx == 1, 'PAR'].values
    assert v2 > v1
예제 #11
0
    def __init__(self,
                 scene=None,
                 grid=None,
                 entities=None,
                 rleaf=0.15,
                 rsoil=0.2,
                 nbinclin=9,
                 orientation=0,
                 localisation='Montpellier',
                 scene_unit='m',
                 mu=None,
                 distinc=None,
                 **grid_kwds):
        """
        Initialise a RatpScene.

        Arguments:
        scene: a pyratp.interface.surfacic_point_cloud or a plantgl.Scene or a
        {shape_id: vertices, faces} scene mesh dict encoding the 3D scene
        grid: a pyratp.interface.smart_grid instance encoding the voxel grid.
         If None (default), the grid is adjusted to fit the input scene.
        entities: a {shape_id: entity} dict defining entities in the scene. If
         None (default), all shapes are considered as members of the same entity
        rleaf: leaf reflectance or a {entity: leaf_reflectance} property dict.
        rsoil: soil reflectance
        nbinclin: the number of angular classes for leaf angle distribution
        orientation (float): the angle (deg, positive clockwise) from X+ to
         North (default: 0)
        localisation : a string referencing a city of the localisation database
         (class variable), or a dict{'longitude':longitude, 'latitude':latitude}
        scene_unit: a string indicating unit used for scene coordinates
        mu : a list of clumping indices, indexed by density.If None (default)
         clumping is automatically evaluated using clark-evans method.
        distinc: a list of list giving the frequency of the nbinclin leaf angles
         classes (from horizontal to vertical) per entity in the canopy.
         If None (default), distinc is computed automatically from the scene

        Other named args to this function are used for controlling grid shape
        when grid=None

        """

        # scene_box will be used to construct grid, if grid is None
        scene_box = ((0, 0, 0), (1, 1, 1))

        if scene is None:
            scene = {'plant': unit_square_mesh()}

        if isinstance(scene, SurfacicPointCloud):
            self.scene = scene
            self.scene_mesh = scene.as_scene_mesh()
            if grid is None:
                scene_box = scene.bbox()
        elif is_pgl_scene(scene):
            self.scene_mesh = pgls.as_scene_mesh(scene)
            self.scene = SurfacicPointCloud.from_scene_mesh(
                self.scene_mesh, scene_unit=scene_unit)
            if grid is None:
                scene_box = pgls.bbox(scene, scene_unit)
        else:
            try:
                self.scene_mesh = scene
                self.scene = SurfacicPointCloud.from_scene_mesh(
                    scene, scene_unit=scene_unit)
                if grid is None:
                    vertices, faces = zip(*scene.values())
                    vertices = reduce(lambda pts, new: pts + list(new),
                                      vertices, [])
                    x, y, z = zip(*vertices)
                    scene_box = ((min(x), min(y), min(z)), (max(x), max(y),
                                                            max(z)))
            except Exception as details:
                print details
                raise ValueError(
                    "Unrecognised scene format: should be one of pgl.Scene, "
                    "SurfacicPointCloud or {sh_id:(vertices, faces)} dict")

        if grid is None:
            self.smart_grid = SmartGrid(scene_box=scene_box, **grid_kwds)
        elif isinstance(grid, SmartGrid):
            self.smart_grid = grid
        else:
            raise ValueError('Unrecognised grid format: should be None or a '
                             'SmartGrid instance')

        if entities is None:
            entities = {sh_id: 'default' for sh_id in self.scene_mesh}
        self.entities = entities
        # RATP entity code starts at 1
        ent = list(set(self.entities.values()))
        self.entity_map = dict(zip(ent, range(1, len(ent) + 1)))
        self.entity_code = numpy.array(
            [self.entity_map[entities[sh]] for sh in self.scene.shape_id])

        if not isinstance(rleaf, dict):
            # if not hasattr(rleaf, '__len__'):
            #     rleaf = [rleaf]
            rleaf = {'default': rleaf}
        self.rleaf = {self.entity_map[k]: rleaf[k] for k in self.entity_map}

        if not hasattr(rsoil, '__len__'):
            rsoil = [rsoil]
        self.rsoil = rsoil

        self.orientation = orientation

        if not isinstance(localisation, dict):
            try:
                localisation = RatpScene.localisation_db[localisation]
            except KeyError:
                print 'Warning : localisation', localisation, \
                    'not found in database, using default localisation', \
                    RatpScene.localisation_db.iter().next()
                localisation = RatpScene.localisation_db.itervalues().next()
        self.localisation = localisation

        if mu is None:
            mu = self.clumping()
            print(' '.join(['clumping evaluated:'] + [str(m) for m in mu]))
        self.set_clumping(mu)

        if distinc is None:
            distinc = self.inclination_distribution(nbinclin)
        self.set_inclin(distinc)

        self.ratp_grid, self.grid_indices = self.grid()