Пример #1
0
 def stem_example_rtp(self):
     """ an example used in the tests below, a main stem with laterals """
     self.plant = pb.Organism(
     )  # store organism (not owned by Organ, or OrganRandomParameter)
     p0 = pb.StemRandomParameter(self.plant)
     p0.name, p0.subType, p0.la, p0.lb, p0.lmax, p0.ln, p0.r, p0.dx = "main", 1, 1, 10, 100, (
         89. / 19.), 1, 0.5
     p0.successor = [3]
     p0.successorP = [1.]
     p1 = pb.StemRandomParameter(self.plant)
     p1.name, p1.subType, p1.la, p1.ln, p1.r, p1.dx = "lateral", 3, 25, 0, 2, 0.1
     self.p0, self.p1 = p0, p1  # needed at later point
     self.plant.setOrganRandomParameter(
         p0)  # the organism manages the type parameters and takes ownership
     self.plant.setOrganRandomParameter(p1)
     # TODO (first node is not set, if seed is used)
     self.plant.setOrganRandomParameter(pb.SeedRandomParameter(self.plant))
     self.seed = pb.Seed(
         self.plant)  # store parent (not owned by child Organ)
     #
     param0 = p0.realize()  # set up stem by hand (without a stem system)
     param0.la, param0.lb = 0, 0  # its important parent has zero length, otherwise creation times are messed up
     parentstem = pb.Stem(1, param0, True, True, 0., 0.,
                          pb.Vector3d(0, 0, -1), 0, 0, False,
                          0)  # takes ownership of param0
     parentstem.setOrganism(self.plant)
     parentstem.addNode(pb.Vector3d(0, 0, -3),
                        0)  # there is no nullptr in Python
     self.parentstem = parentstem  # store parent (not owned by child Organ)
     #
     self.stem = pb.Stem(self.plant, p0.subType, pb.Vector3d(0, 0, -1), 0,
                         self.parentstem, 0, 0)
     self.stem.setOrganism(self.plant)
Пример #2
0
    def test_leaf(self):
        """ leaf without lateral leafs """
        ons = pb.Matrix3d(pb.Vector3d(0., 0., 1.), pb.Vector3d(0., 1., 0.), pb.Vector3d(1., 0., 0.))
        plant = pb.Plant()  # store organism (not owned by Organ, or OrganRandomParameter)
        p0 = pb.LeafRandomParameter(plant)
        p0.name, p0.subType, p0.la, p0.lb, p0.lmax, p0.ln, p0.r, p0.dx = "leaf", 1, 3.5, 1., 7.5, 3, 1, 0.1   
          
        phi = np.array([-90, -45, 0., 45, 90]) / 180. * np.pi
        l = np.array([3, 2.2, 1.7, 2, 3.5])
        N = 100  # N is rather high for testing
        p0.createLeafRadialGeometry(phi, l, N)            
#         y = np.array([-3, -3 * 0.7, 0., 3.5 * 0.7, 3.5])
#         l = np.array([0., 2.2 * 0.7, 1.7, 1.8 * 0.7, 0.])
#         N = 105  # N is rather high for testing
#         p0.createLeafGeometry(y, l, N)   
               
        plant.setOrganRandomParameter(p0)  # the organism manages the type parameters and takes ownership        
        plant.setOrganRandomParameter(pb.SeedRandomParameter(plant))       
        # because we cannot pass a nullptr to pb.Leaf(...) L48
        param0 = p0.realize()  # set up leaf by hand (without a leaf syleaf)
        param0.la, param0.lb = 0, 0  # its important parent has zero length, otherwise creation times are messed up
        parentleaf = pb.Leaf(1, param0, True, True, 0., 0., ons, 0, False, 0)  # takes ownership of param0
        parentleaf.setOrganism(plant)     
        parentleaf.addNode(pb.Vector3d(0, 0, -3), 0)  # there is no nullptr in Python   

        leaf = pb.Leaf(plant, p0.subType, ons, 0, parentleaf , 0)
        leaf.setOrganism(plant)
        leaf.simulate(7)
        vp.plot_leaf(leaf)
Пример #3
0
 def test_constructors(self):
     """ tests two kinds of constructors and copy"""
     self.root_example_rrp()
     # 1. constructor from scratch
     param = self.p0.realize()
     root = pb.Root(1, param, True, True, 0., 0., pb.Vector3d(0, 0, -1), 0,
                    0, False, 0)
     root.setOrganism(self.plant)
     root.addNode(pb.Vector3d(0, 0, -3),
                  0)  # parent must have at least one nodes
     # 2. used in simulation (must have parent, since there is no nullptr in Pyhton)
     root2 = pb.Root(self.plant, self.p1.subType, pb.Vector3d(0, 0, -1), 0,
                     root, 0, 0)
     root.addChild(root2)
     # 3. deep copy (with a factory function)
     plant2 = pb.Organism()
     root3 = root.copy(plant2)
     self.assertEqual(
         str(root), str(root3),
         "deep copy: the root string representations shold be equal")
     self.assertIsNot(root.getParam(), root3.getParam(),
                      "deep copy: roots have same specific parameter set"
                      )  # type OrganSpecificParameter
     self.assertEqual(str(root.param()), str(root3.param()),
                      "deep copy: roots have different parameter values"
                      )  # type RootSpecificParameter
Пример #4
0
    def root_example_rrp(self):
        """ an example used in the tests below, a main root with laterals """
        self.plant = pb.Organism(
        )  # store organism (not owned by Organ, or OrganRandomParameter)
        p0 = pb.RootRandomParameter(self.plant)
        p0.name, p0.subType, p0.la, p0.lb, p0.lmax, p0.ln, p0.r, p0.dx = "taproot", 1, 10., 1., 100., 1., 1.5, 0.5
        p0.successor = [2]
        p0.successorP = [1.]
        p1 = pb.RootRandomParameter(self.plant)
        p1.name, p1.subType, p1.lmax, p1.r, p1.dx = "lateral", 2, 25., 2., 0.1
        self.p0, self.p1 = p0, p1  # needed at later point
        self.plant.setOrganRandomParameter(
            p0)  # the organism manages the type parameters and takes ownership
        self.plant.setOrganRandomParameter(p1)
        srp = pb.SeedRandomParameter(self.plant)
        self.plant.setOrganRandomParameter(srp)

        param0 = p0.realize()  # set up root by hand (without a root system)
        param0.la, param0.lb = 0, 0  # its important parent has zero length, otherwise creation times are messed up
        parentroot = pb.Root(1, param0, True, True, 0., 0.,
                             pb.Vector3d(0, 0, -1), 0, 0, False,
                             0)  # takes ownership of param0
        parentroot.setOrganism(self.plant)
        parentroot.addNode(pb.Vector3d(0, 0, -3),
                           0)  # there is no nullptr in Python

        self.parentroot = parentroot  # store parent (not owned by child Organ)
        self.root = pb.Root(self.plant, p0.subType, pb.Vector3d(0, 0, -1), 0,
                            self.parentroot, 0, 0)
        self.root.setOrganism(self.plant)
Пример #5
0
    def test_sequential(self):
        """ tests if the the organ tree can be represented in a seqential list"""
        self.hand_example()
        self.add_nodes()  # only organs with number of nodes > 1 are considered
        ring = pb.Organ(self.human1, self.thumb, 0, 0, 4, self.ons, 0)  # add a ring to the thumb
        self.thumb.addChild(ring)
        ring.addNode(pb.Vector3d(0, -1, 1.6), self.thumb.getNodeId(1), 4)
        ring.addNode(pb.Vector3d(0, -1, 1.6), 4)
        organs = self.hand.getOrgans()
Пример #6
0
    def hand_example(self):
        """ an example used in the tests below, a hand with two fingers """
        self.human1 = pb.Organism()  # same example as in test_constructor ...
        otp = pb.OrganRandomParameter(self.human1)
        self.human1.setOrganRandomParameter(otp)
        op = otp.realize()
        self.hand = pb.Organ(self.human1.getOrganIndex(), op, True, True, 0, 15., pb.Vector3d(0., 0., 1.), 0., 0, False, 0)
        self.hand.setOrganism(self.human1)
        self.thumb = pb.Organ(self.human1, self.hand, 0, 0, 4, pb.Vector3d(0., 0., 1.), 0., 0)  # delayedfor 4 days
        self.little_finger = pb.Organ(self.human1, self.hand, 0, 0, 3, pb.Vector3d(0., 0., 1.), 0., 0)  # delayed for 3 days
        self.hand.addChild(self.thumb)
Пример #7
0
 def read_rsml(file_name:str, verbose=True):
     """ reads an RSML file and converts to MappedSegments with units [cm]
     @file_name     the file name of the rsml, including file extension (e.g. "test.rsml" ) 
     @return a CPlantBox MappedSegments object
     """
     polylines, props, funcs = rsml.read_rsml(file_name)
     bn = 0  # count base roots
     for i, _ in enumerate(polylines):
         if props["parent-poly"][i] < 0:
             bn += 1
     if bn > 1: 
         polylines, props, funcs = rsml.artificial_shoot(polylines, props, funcs)        
         if verbose: 
             print("XylemFluxPython.read_rsml: added an artificial shoot")
     nodes, segs = rsml.get_segments(polylines, props)
     radii, seg_ct, types = rsml.get_parameter(polylines, funcs, props)        
     if verbose: 
         print("XylemFluxPython.read_rsml: read rsml with", len(nodes), "nodes and", len(segs), "segments")        
     nodes = np.array(nodes)  # for slicing in the plots
     nodes2 = []  # Conversions...
     for n in nodes:
         nodes2.append(pb.Vector3d(n[0] , n[1] , n[2]))
     segs2 = []
     nodeCTs = np.zeros((len(nodes), 1))  # we need node creation times
     for i, s in enumerate(segs):
         nodeCTs[s[1]] = seg_ct[i]
         segs2.append(pb.Vector2i(int(s[0]), int(s[1])))
     radii = np.array(radii)
     types = np.array(types, dtype=np.int64) - 1  # index must start with 0
     if verbose:
         print("                           nodeCTs [{:g}, {:g}] days".format(np.min(nodeCTs), np.max(nodeCTs)))
         print("                           raddii [{:g}, {:g}] cm".format(np.min(radii), np.max(radii)))
         print("                           subTypes [{:g}, {:g}] ".format(np.min(types), np.max(types)))        
     return pb.MappedSegments(nodes2, nodeCTs, segs2, radii, types)  # root system grid
Пример #8
0
 def convert_to_xylem_flux_(self):
     """  converts the polylines to a SegmentAnalyser and a MappedSegments object, and stores max_ct   
     
     uses:
     properties["parent-poly"], properties["parent-nodes"]
     radii, cts, types                    
     """
     nodes, segs = rsml_reader.get_segments(self.polylines, self.properties)  # fetch nodes and segments
     segRadii = np.zeros((segs.shape[0], 1))  # convert to paramter per segment
     segCTs = np.zeros((segs.shape[0], 1))
     subTypes = np.zeros((segs.shape[0], 1))
     for i, s in enumerate(segs):
         segRadii[i] = self.radii[s[1]]  # seg to node index            
         segCTs[i] = self.cts[s[1]]
         subTypes[i] = self.types[s[1]]
     if np.isnan(subTypes[0]):
         subTypes = np.ones((len(segs),), dtype=np.int64)
     segs_ = [pb.Vector2i(s[0], s[1]) for s in segs]  # convert to CPlantBox types
     nodes_ = [pb.Vector3d(n[0], n[1], n[2]) for n in nodes]
     self.analyser = pb.SegmentAnalyser(nodes_, segs_, segCTs, segRadii)
     self.analyser.addData("subType", subTypes)
     ms = pb.MappedSegments(self.analyser.nodes, np.array(self.cts), segs_, np.array(segRadii), np.array(subTypes))
     self.xylem_flux = xylem_flux.XylemFluxPython(ms)
     self.base_nodes = self.get_base_node_indices_()
     self.xylem_flux.neumann_ind = self.base_nodes  # needed for suf
     self.xylem_flux.dirichlet_ind = self.base_nodes  # needed for krs
     self.base_segs = self.xylem_flux.find_base_segments()
Пример #9
0
    def test_dynamics(self):
        """ tests if nodes created in last time step are correct """  #
        self.hand_example()
        self.hand.simulate(1)
        self.add_nodes()
        n0 = self.hand.getNumberOfNodes() - self.hand.getOldNumberOfNodes()
        n1 = self.little_finger.getNumberOfNodes() - self.little_finger.getOldNumberOfNodes()
        n2 = self.thumb.getNumberOfNodes() - self.thumb.getOldNumberOfNodes()
        self.assertEqual(n0, 4, "wrong number of new nodes")
        self.assertEqual(n1, 2, "wrong number of new nodes")
        self.assertEqual(n2, 2, "wrong number of new nodes")
        self.hand.simulate(1)
        n0 = self.hand.getNumberOfNodes() - self.hand.getOldNumberOfNodes()
        n1 = self.little_finger.getNumberOfNodes() - self.little_finger.getOldNumberOfNodes()
        n2 = self.thumb.getNumberOfNodes() - self.thumb.getOldNumberOfNodes()
        self.assertEqual(n0, 0, "wrong number of new nodes")
        self.assertEqual(n1, 0, "wrong number of new nodes")
        self.assertEqual(n2, 0, "wrong number of new nodes")
        self.hand.simulate(1)
        self.little_finger.addNode(pb.Vector3d(0, 1, 1.6), 6)
        n0 = self.hand.getNumberOfNodes() - self.hand.getOldNumberOfNodes()
        n1 = self.little_finger.getNumberOfNodes() - self.little_finger.getOldNumberOfNodes()
        n2 = self.thumb.getNumberOfNodes() - self.thumb.getOldNumberOfNodes()
        self.assertEqual(n0, 0, "wrong number of new nodes")
        self.assertEqual(n1, 1, "wrong number of new nodes")
Пример #10
0
    def root_example_rrp2(self):
        """ an example used in the tests below, a main root with laterals """
        self.plant = pb.RootSystem(
        )  # store organism (not owned by Organ, or OrganRandomParameter)
        p0 = pb.RootRandomParameter(self.plant)
        p0.name, p0.subType, p0.la, p0.lb, p0.lmax, p0.ln, p0.lnk, p0.r, p0.dx, p0.dxMin = "taproot", 1, 0.95, 0.8, 10., 1.05, 0.01, 0.8, 0.25, 0.2
        p0.successor = [2]
        p0.successorP = [1.]
        p1 = pb.RootRandomParameter(self.plant)
        p1.name, p1.subType, p1.lmax, p1.r, p1.dx = "lateral", 2, 2., 2., 2.

        self.plant.setOrganRandomParameter(
            p0)  # the organism manages the type parameters and takes ownership
        self.plant.setOrganRandomParameter(p1)
        srp = pb.SeedRandomParameter(self.plant)
        self.plant.setOrganRandomParameter(srp)

        print("root p0, initial parameters: lmax = ", p0.lmax, ", lb = ",
              p0.lb, ", la = ", p0.la, ", ln = ", p0.ln)
        param0 = p0.realize()  # set up root by hand (without a root system)
        print("root p0, realized parameters: lmax = ",
              sum((sum(param0.ln), param0.lb, param0.la)), ", lb = ",
              param0.lb, ", la = ", param0.la, ", mean ln = ",
              np.mean(param0.ln))
        if ((param0.lb % p0.dx > 0) and (param0.lb % p0.dx < p0.dxMin * 0.99)):
            print("lb value does not fit with dx and dxMin")
            print(param0.lb % p0.dx)
        if ((param0.la % p0.dx > 0) and (param0.la % p0.dx < p0.dxMin * 0.99)):
            print("la value does not fit with dx and dxMin")
            print(param0.la % p0.dx)
        if (any([(lni % p0.dx > 0 and lni % p0.dx < p0.dxMin * 0.99)
                 for lni in param0.ln])):
            print("ln value does not fit with dx and dxMin")

        param0.la, param0.lb = 0, 0  # its important parent has zero length, otherwise creation times are messed up
        parentroot = pb.Root(1, param0, True, True, 0., 0.,
                             pb.Vector3d(0, 0, -1), 0, 0, False,
                             0)  # takes ownership of param0
        parentroot.setOrganism(self.plant)
        parentroot.addNode(pb.Vector3d(0, 0, -1),
                           0)  # there is no nullptr in Python

        self.parentroot = parentroot  # store parent (not owned by child Organ)
        self.root = pb.Root(self.plant, p0.subType, pb.Vector3d(0, 0, -1), 0,
                            self.parentroot, 0, 0)
        self.root.setOrganism(self.plant)
        self.p0 = p0
Пример #11
0
 def read_rsml(file_name: str):
     """ 
     Reads an RSML file and converts to MappedSegments with units [cm]
     """
     polylines, props, funcs = rsml.read_rsml(file_name)
     assert len(polylines) == len(
         props['parent-poly']
     ), "XylemFluxPython.read_rsml: wrong number of parent-poly tags"
     if not 'parent-node' in props:  # reconstruct...
         print("parse_rsml: no parent-node tag found, reconstructing...")
         props['parent-node'] = []
         for i in range(0, len(polylines)):
             if props['parent-poly'][i] >= 0:
                 pni = XylemFluxPython.connect(
                     np.array(polylines[i][0]),
                     polylines[props['parent-poly'][i]])
             else:
                 pni = -1
             # print("parent", props['parent-poly'][i], "pni", pni)
             props['parent-node'].append(pni)
     assert len(polylines) == len(
         props['parent-node']
     ), "XylemFluxPython.read_rsml: wrong number of parent-node tags"
     nodes, segs = rsml.get_segments(polylines, props)
     print("Read rsml:", len(nodes), "segs", len(segs), "segs")
     nodes2 = [pb.Vector3d(n[0], n[1], n[2])
               for n in nodes]  # convert to plantbox types
     segs2 = [pb.Vector2i(int(s[0]), int(s[1])) for s in segs]
     radii_, nodeCTs_, types_ = [], [], []
     for i, p in enumerate(polylines):
         for j in range(0, len(p)):
             if 'diameter' in funcs:
                 radii_.append(funcs['diameter'][i][j] / 2)
             else:
                 print("XylemFluxPython.read_rsml: no diameter tag found")
                 radii_.append(0.)
             if 'emergence_time' in funcs:
                 nodeCTs_.append(funcs['emergence_time'][i][j])
             else:
                 print(
                     "XylemFluxPython.read_rsml: no emergence_time tag found"
                 )
                 nodeCTs_.append(0.)
             if 'type' in funcs:
                 types_.append(funcs["type"][i][j])
             elif 'type' in props:
                 types_.append(props["type"][i])
             else:
                 print("XylemFluxPython.read_rsml: no type tag found")
                 types_.append(0)
     nodeCTs = np.array(nodeCTs_)  # creation times per node
     radii = np.zeros((len(segs), 1))  # radii per segment
     types = np.ones((len(segs), 1), dtype=np.int64)  # types per semgent
     for i, s in enumerate(segs):
         radii[i] = radii_[s[1]]
         types[i] = types_[s[1]] - 1  # index must start with 0
     return pb.MappedSegments(nodes2, nodeCTs, segs2, radii,
                              types)  # root system grid
Пример #12
0
 def add_nodes(self):
     """ used in the tests below, adds nodes to the hand example """
     self.hand.addNode(pb.Vector3d(0, 0, 0), 0)
     self.hand.addNode(pb.Vector3d(0, 0, 1.5), 0)
     self.hand.addNode(pb.Vector3d(0, -1, 1.6), 0)  # thumb
     self.hand.addNode(pb.Vector3d(0, 1, 1.6), 0)  # little finger
     thumb = self.hand.getNodeId(2)
     lf = self.hand.getNodeId(3)
     self.thumb.addNode(pb.Vector3d(0, -1, 1.6), thumb, 4)
     self.thumb.addNode(pb.Vector3d(0, -2, 2.5), 4)
     self.little_finger.addNode(pb.Vector3d(0, 1, 1.6), lf, 3)
     self.little_finger.addNode(pb.Vector3d(0, 1.7, 2.5), 3)
Пример #13
0
 def test_constructors(self):
     """ tests two kinds of constructors and copy"""
     self.stem_example_rtp()
     # 1. constructor from scratch
     param = self.p0.realize()
     stem = pb.Stem(1, param, True, True, 0., 0., pb.Vector3d(0, 0, -1), 0,
                    0, False, 0)
     stem.setOrganism(self.plant)
     stem.addNode(pb.Vector3d(0, 0, -3),
                  0)  # parent must have at least one nodes
     # 2. used in simulation (must have parent, since there is no nullptr in Pyhton)
     stem2 = pb.Stem(self.plant, self.p1.subType, pb.Vector3d(0, 0, -1), 0,
                     stem, 0, 0)
     stem.addChild(stem2)
     # 3. deep copy (with a factory function)
     plant2 = pb.Organism()
     stem3 = stem.copy(plant2)
     self.assertEqual(str(stem), str(stem3),
                      "deep copy: the organs shold be equal")
     self.assertIsNot(stem.getParam(), stem3.getParam(),
                      "deep copy: organs have same parameter set")
Пример #14
0
    def test_constructors(self):
        """ tests three different kinds of constructors """
        human1 = pb.Organism()
        otp = pb.OrganRandomParameter(human1)
        human1.setOrganRandomParameter(otp)
        op = otp.realize()
        # 1. constructor from scratch
        hand = pb.Organ(human1.getOrganIndex(), op, True, True, 0., 15., pb.Vector3d(0., 0., 1.), 0., 0, False, 0) 
        hand.setOrganism(human1)
        # 2. used in simulation (must have parent, since there is no nullptr in Pyhton)
        thumb = pb.Organ(human1, hand, 0, 0, 4, pb.Vector3d(0., 0., 1.), 0., 0)
        little_finger = pb.Organ(human1, hand, 0, 0, 3, pb.Vector3d(0., 0., 1.), 0., 0)
        hand.addChild(thumb)
        hand.addChild(little_finger)
        # 3. deep copy (with a factory function)
        human2 = pb.Organism()
        human2.setOrganRandomParameter(otp.copy(human2))
        hand2 = hand.copy(human2)
        self.assertEqual(str(hand), str(hand2), "deep copy: the organs should be equal")
        self.assertIsNot(hand.getParam(), hand2.getParam(), "deep copy: organs have same parameter set")
        self.assertEqual(str(hand.getParam()), str(hand2.getParam()), "deep copy: the different parameter set values")
        self.assertEqual(str(hand.getOrganRandomParameter()), str(hand2.getOrganRandomParameter()), "deep copy: the different random parameter set values")
Пример #15
0
    def stem_example_rtp(self, phytomereGrowth = "sequential"):
        """ an example used in the tests below, a main stem with laterals """
        self.plant = pb.Plant()  # store organism (not owned by Organ, or OrganRandomParameter)
        p0 = pb.StemRandomParameter(self.plant)
        p0.name, p0.subType, p0.la, p0.lb, p0.lmax, p0.ln, p0.r, p0.dx, p0.dxMin = "main", 1, 10., 10., 100., 1., 1.5, 1, 0.5
        p0.delayLat = 1.
        p0.delayNG = 2.
        p0.successor = [5]
        p0.successorP = [1.]

        if phytomereGrowth == "sequential":
            p0.nodalGrowth = 0
        if phytomereGrowth == "equal":
            p0.nodalGrowth = 1

        p1 = pb.StemRandomParameter(self.plant)
        p1.name, p1.subType, p1.lmax, p1.r, p1.dx, p1.dxMin = "lateral", 5, 5., 2., 1, 0.5
        self.p0, self.p1 = p0, p1  # needed at later point
        self.plant.setOrganRandomParameter(p0)  # the organism manages the type parameters and takes ownership
        self.plant.setOrganRandomParameter(p1)

        srp = pb.SeedRandomParameter(self.plant)
        self.plant.setOrganRandomParameter(srp)

        # creates seed organ (otherwise throws error in plant::simulate())
        # test == True => no need to give root parameter
        self.plant.initialize(verbose = False, test = True)

        param0 = p0.realize()  # set up stem by hand (without a stem system)
        param0.la, param0.lb = 0, 0  # its important parent has zero length, otherwise creation times are messed up
        self.ons = pb.Matrix3d(pb.Vector3d(0., 0., 1.), pb.Vector3d(0., 1., 0.), pb.Vector3d(1., 0., 0.))
        parentstem = pb.Stem(1, param0, True, True, 0., 0., self.ons, 0, False, 0)  # takes ownership of param0
        parentstem.setOrganism(self.plant)
        parentstem.addNode(pb.Vector3d(0, 0, -3), 0)  # there is no nullptr in Python
        self.parentstem = parentstem  # store parent (not owned by child Organ)
        self.stem = pb.Stem(self.plant, p0.subType, self.ons, 0, self.parentstem , 0)
        self.stem.setOrganism(self.plant)
Пример #16
0
def soil_cores(x :list, y :list, r :float, h :float):
    """
    A lsit of soil core geometries with a fixed location in the field  
 
    @param x     x coordinates of the soil cores (cm)
    @param y     y coordinates of the soil cores (cm)
    @param r     radius of the soil core (cm)
    @param h     height of the soil core (cm)
    """
    assert len(x) == len(y), "coordinate length must be equal"
    core = pb.SDF_PlantContainer(r, r, h, False)
    cores = []
    for i in range(0, len(x)):
        cores.append(pb.SDF_RotateTranslate(core, 0., pb.SDF_Axis.xaxis, pb.Vector3d(x[i], y[i], 0.)))  # just translate
    return cores;
Пример #17
0
 def get_srp(self):
     self.plant = pb.Organism()  # need to store this
     srp = pb.SeedRandomParameter(self.plant)
     srp.seedPos = pb.Vector3d(0, 0, -2)
     srp.firstB = 3  # basal
     srp.delayB = 5
     srp.maxB = 7
     srp.nC = 7
     srp.firstSB = 30  # shoot borne
     srp.delaySB = 10
     srp.delayRC = 70
     srp.nz = 0.7
     srp.maxTil = 3  # stem
     srp.simtime = 10
     self.plant.setOrganRandomParameter(srp)
     return srp
Пример #18
0
def initialize_root_systems(N :int, M :int, distN :float, distM :float):
    """ 
    Initializes M*N root systems 
        
    @param N         number of rows
    @param M         number of columns
    @param distN     distance between rows
    @param distM     distance between columns  
    @return a list of initialized root systems
    """
    allRS = []
    for i in range(0, N):
        for j in range(0, M):
            rs = pb.RootSystem()
            rs.readParameters(path + name + ".xml")
            rs.getRootSystemParameter().seedPos = pb.Vector3d(distN * i, distM * j, -3.)  # cm
            rs.initialize(False)  # verbose = False
            allRS.append(rs)
    return allRS
Пример #19
0
    def read_rsml(file_name: str, verbose=True):
        """ reads an RSML file and converts to MappedSegments with units [cm]
        @file_name     the file name of the rsml, including file extension (e.g. "test.rsml" ) 
        @return a CPlantBox MappedSegments object
        """
        polylines, props, funcs, _ = rsml.read_rsml(file_name)
        bn = 0  # count base roots
        for i, _ in enumerate(polylines):
            if props["parent-poly"][i] < 0:
                bn += 1
        if bn > 1:
            rsml.artificial_shoot(polylines, props, funcs)
            if verbose:
                print("XylemFluxPython.read_rsml: added an artificial shoot")
        nodes, segs = rsml.get_segments(polylines, props)
        if verbose:
            print("XylemFluxPython.read_rsml: read rsml with", len(nodes),
                  "nodes and", len(segs), "segments")
        nodes2 = [pb.Vector3d(n[0], n[1], n[2])
                  for n in nodes]  # Conversions to PlantBox types
        segs2 = [pb.Vector2i(int(s[0]), int(s[1])) for s in segs]

        radii, cts, types, tag_names = rsml.get_parameter(
            polylines, funcs, props)
        segRadii = np.zeros(
            (segs.shape[0], 1))  # convert to paramter per segment
        segTypes = np.zeros((segs.shape[0], 1))
        for i, s in enumerate(segs):
            segRadii[i] = radii[s[1]]  # seg to node index
            segTypes[i] = types[s[1]]

        if verbose:
            print("                           cts [{:g}, {:g}] days".format(
                np.min(cts), np.max(cts)))
            print("                           raddii [{:g}, {:g}] cm".format(
                np.min(radii), np.max(radii)))
            print("                           subTypes [{:g}, {:g}] ".format(
                np.min(types), np.max(types)))
            print()

        return pb.MappedSegments(nodes2, cts, segs2, segRadii,
                                 segTypes)  # root system grid
Пример #20
0
 def rs_example_rtp(self):
     """ an example used in some of the tests below, 100 basals with laterals """
     self.rs = pb.RootSystem()
     srp = pb.SeedRandomParameter(self.rs)
     srp.subType = 0
     srp.seedPos = pb.Vector3d(0., 0., -3.)
     srp.maxB = 100
     srp.firstB = 10
     srp.delayB = 3
     self.rs.setRootSystemParameter(srp)
     p0 = pb.RootRandomParameter(self.rs)
     p0.name, p0.subType, p0.la, p0.lmax, p0.ln, p0.r, p0.dx = "taproot", 1, 10, 101, 89. / 19., 1, 0.5
     p0.lb = 2
     p0.successor = [2]
     p0.successorP = [1.]
     p1 = pb.RootRandomParameter(self.rs)
     p1.name, p1.subType, p1.la, p1.ln, p1.r, p1.dx = "lateral", 2, 25, 0, 2, 0.1
     self.p0, self.p1, self.srp = p0, p1, srp  # Python will garbage collect them away, if not stored
     self.rs.setOrganRandomParameter(p0)  # the organism manages the type parameters
     self.rs.setOrganRandomParameter(p1)
Пример #21
0
 def read_rsml(file_name: str):
     """ 
     Reads an RSML file and converts to MappedSegments with units [cm]
     """
     polylines, props, funcs = rsml.read_rsml(file_name)
     nodes, segs = rsml.get_segments(polylines, props)
     radii, seg_ct, types = rsml.get_parameter(polylines, funcs, props)
     print("Read rsml:", len(nodes), "nodes", len(radii), "radii")
     nodes = np.array(nodes)  # for slicing in the plots
     nodes2 = []  # Conversions...
     for n in nodes:
         nodes2.append(pb.Vector3d(n[0], n[1], n[2]))
     segs2 = []
     nodeCTs = np.zeros((len(nodes), 1))  # we need node creation times
     for i, s in enumerate(segs):
         nodeCTs[s[1]] = seg_ct[i]
         segs2.append(pb.Vector2i(int(s[0]), int(s[1])))
     radii = np.array(radii)
     types = np.array(types, dtype=np.int64) - 1  # index must start with 0
     return pb.MappedSegments(nodes2, nodeCTs, segs2, radii,
                              types)  # root system grid
Пример #22
0
TairK = TairC + 273.15

es = 0.61078 * math.exp(17.27 * TairC / (TairC + 237.3))
ea = es * RH
VPD = es - ea

# root system
pl = pb.MappedPlant()  #pb.MappedRootSystem() #pb.MappedPlant()
path = "../../../modelparameter/plant/"  #"../../../modelparameter/rootsystem/"
name = "manyleaves"  #"Anagallis_femina_Leitner_2010"  # Zea_mays_1_Leitner_2010
pl.readParameters(path + name + ".xml")
""" soil """
min_ = np.array([-5, -5, -15])
max_ = np.array([9, 4, 0])
res_ = np.array([5, 5, 5])
pl.setRectangularGrid(pb.Vector3d(min_), pb.Vector3d(max_), pb.Vector3d(res_),
                      True)  # cut and map segments

pl.initialize()
pl.simulate(simtime, False)
#rs.simulate(simtime, False) #test to see if works in case of several simulate

r = Leuning(pl)
nodes = r.get_nodes()
tiproots, tipstem, tipleaf = r.get_organ_nodes_tips(
)  #end node of end segment of each organ
node_tips = np.concatenate((tiproots, tipstem, tipleaf))
tiproots, tipstem, tipleaf = r.get_organ_segments_tips(
)  #end segment of each organ
seg_tips = np.concatenate((tiproots, tipstem, tipleaf))
Пример #23
0
rs = pb.MappedRootSystem()
rs.readParameters(path + name + ".xml")
if not periodic:
    sdf = pb.SDF_PlantBox(0.99 * (max_b[0] - min_b[0]),
                          0.99 * (max_b[1] - min_b[1]), max_b[2] - min_b[2])
else:
    sdf = pb.SDF_PlantBox(np.Inf, np.Inf, max_b[2] - min_b[2])
rs.setGeometry(sdf)
rs.initialize()
rs.simulate(rs_age, False)
r = XylemFluxPython(rs)
init_conductivities(r, age_dependent)
""" Coupling (map indices) """
picker = lambda x, y, z: s.pick([x, y, z])
r.rs.setSoilGrid(picker)  # maps segments
r.rs.setRectangularGrid(pb.Vector3d(min_b), pb.Vector3d(max_b),
                        pb.Vector3d(cell_number), True)
r.test()  # sanity checks
nodes = r.get_nodes()
cci = picker(nodes[0, 0], nodes[0, 1], nodes[0, 2])  # collar cell index
""" Numerical solution """
start_time = timeit.default_timer()
x_, y_ = [], []
sx = s.getSolutionHead()  # inital condition, solverbase.py
N = round(sim_time / dt)
t = 0.

for i in range(0, N):

    rx = r.solve(rs_age + t, -trans * sinusoidal(t), sx[cci], sx, True,
                 wilting_point)  # xylem_flux.py
"""scales insertion angle"""
import sys
sys.path.append("../../..")
import numpy as np
import plantbox as pb
import vtk_plot as vp

rs = pb.RootSystem()
path = "../../../modelparameter/rootsystem/"
name = "Anagallis_femina_Leitner_2010"
rs.readParameters(path + name + ".xml")

# box with a left and a right compartment for analysis
sideBox = pb.SDF_PlantBox(10, 20, 50)
left = pb.SDF_RotateTranslate(sideBox, pb.Vector3d(-4.99, 0, 0))
right = pb.SDF_RotateTranslate(sideBox, pb.Vector3d(4.99, 0, 0))
leftright = pb.SDF_Union(left, right)
rs.setGeometry(leftright)

# left compartment has a minimum of 0.01, 1 elsewhere
maxS = 1.  # maximal
minS = 0.1  # minimal
slope = 1.  # [cm] linear gradient between min and max
leftC = pb.SDF_Complement(left)
soilprop = pb.SoilLookUpSDF(leftC, maxS, minS, slope)

# Manually set scaling function and tropism parameters
sigma = [0.4, 1., 1., 1., 1.] * 2
for p in rs.getRootRandomParameter():
    if p.subType > 2:
        p.dx = 0.25  # adjust resolution
Пример #25
0
rs.readParameters(path + name + ".xml")

# Manually set tropism to hydrotropism for the first ten root types
sigma = [0.4, 1., 1., 1., 1.] * 2
for p in rs.getRootRandomParameter():
    p.dx = 0.25  # adjust resolution
    p.tropismT = pb.TropismType.hydro
    p.tropismN = 2  # strength of tropism
    p.tropismS = sigma[p.subType - 1]

# Static soil property in a thin layer
maxS = 0.7  # maximal
minS = 0.1  # minimal
slope = 5  # linear gradient between min and max (cm)
box = pb.SDF_PlantBox(30, 30, 2)  # cm
layer = pb.SDF_RotateTranslate(box, pb.Vector3d(0, 0, -16))
soil_prop = pb.SoilLookUpSDF(layer, maxS, minS, slope)

# Set the soil properties before calling initialize
rs.setSoil(soil_prop)

# Initialize
rs.initialize()

# Simulate
simtime = 100  # e.g. 30 or 60 days
dt = 1
N = round(simtime / dt)
for _ in range(0, N):
    # in a dynamic soil setting you would need to update the soil properties (soil_prop)
    rs.simulate(dt)
Пример #26
0
""" nodes and segments from measurements """
import sys
sys.path.append("../../..")
import plantbox as pb

# Data from any source, as Python types
nodes = [
    [0, 1, 0],
    [0, 1, -1],
    [0, 1, -2],
    [0, 1, -3],
]
segs = [[0, 1], [1, 2], [2, 3]]
cts = [0., 0., 0.]
radii = [0.1, 0.1, 0.1]

# convert from Python to C++ binding types
nodes = [pb.Vector3d(n[0], n[1], n[2]) for n in nodes]
segs = [pb.Vector2i(s[0], s[1]) for s in segs]

# create the SegmentAnalyser without underlying RootSystem
ana = pb.SegmentAnalyser(nodes, segs, cts, radii)

print("length", ana.getSummed("length"))
ana.write("results/example_3d.vtp", ["creationTime", "radius"])
Пример #27
0
def vector_3d(a):
    return pb.Vector3d(a[0], a[1], a[2])
Пример #28
0
path = "../../modelparameter/rootsystem/"
name = "Glycine_max_Moraes2020_opt2"

simtime = 154
N = 17  # number of columns
M = 3  # number of rows
dist = 38  # inter-row distance [cm]
distp = 6  # inter-plant distance within the rows [cm]

# Initializes N*M root systems
allRS = []
for i in range(0, N):
    for j in range(0, M):
        rs = pb.RootSystem()
        rs.readParameters(path + name + ".xml")
        rs.getRootSystemParameter().seedPos = pb.Vector3d(
            distp * i, dist * j, -3.)  # cm
        rs.initialize(False)  # verbose = False
        allRS.append(rs)

# Simulate
rs.setSeed(2)
for rs in allRS:
    rs.simulate(simtime, False)  # verbose = False

# Export results as single vtp files (as polylines)
ana = pb.SegmentAnalyser()  # see example 3b
for i, rs in enumerate(allRS):
    vtpname = "results/" + name + "/" + str(i) + ".vtp"
    rs.write(vtpname)
    ana.addSegments(rs)  # collect all
Пример #29
0
p2.a, p2.a_s = 0.0501, 0.0069  # [cm] radius TODO
p2.theta = (180. - 98.45) / 180. * np.pi  # [rad]
# p2.lmax, p2.lmaxs = 3.339, 0.2 * 3.339  # fit k and r
# p2.r, p2.rs = 3.745, 0.1 * 3.745  # fit k and r
p2.lmax, p2.lmaxs = 5, 0.5  # fit r
p2.r, p2.rs = 0.483, 0.1 * 0.483  # fit r
p2.r, p2.rs = 0.823, 0.1 * 0.823  # fit r (last measurement removed)
# by visual comparison
p2.tropismT, p2.tropismN, p2.tropismS = pb.TropismType.gravi, 1, 0.2

rs.setOrganRandomParameter(p0)
rs.setOrganRandomParameter(p1)
rs.setOrganRandomParameter(p2)
""" seed """
srp = pb.SeedRandomParameter(rs)  # with default values
srp.seedPos = pb.Vector3d(0., 0., -0.6)  # [cm] seed position TODO ?
srp.maxB = 0  # [-] number of basal roots (neglecting basal roots and shoot borne)
rs.setRootSystemParameter(srp)
""" container geometry """
length = 7.425  # cm
height = 14.31  # cm
rhizotron = pb.SDF_PlantBox(length, length, height)
rs.setGeometry(rhizotron)  # soilcore, or rhizotron

# elongation impedance at boundaries
layer = 0.5  # cm
smaller_rhizotron = pb.SDF_PlantBox(length - 2 * layer, length - 2 * layer,
                                    height - layer)
scale_elongation = Boundary_Elongation_Impedance(
    smaller_rhizotron, 0.1)  # 1 instead of 0.1 would disable the impedance
for p in rs.getRootRandomParameter():
Пример #30
0
from cmath import pi

sys.path.append("../..")
import plantbox as pb
import numpy as np
import matplotlib.pyplot as plt

path = "../../modelparameter/rootsystem/"
name = "Glycine_max_Moraes2020_opt2"

rs = pb.RootSystem()
rs.readParameters(path + name + ".xml")

# Create and set geometry
rs.setMinDx(1.e-3)
x0 = pb.Vector3d(0., 0., -1.)
nx = pb.Vector3d(1., 0., -1.)
ny = pb.Vector3d(0., 1., -1.)
soil_layer = pb.SDF_HalfPlane(x0, nx,
                              ny)  # there was bug, with updated CPlantBox
rs.setGeometry(soil_layer)

rs.setSeed(2)
rs.initialize()

simtime = 154.  # days
dt = 1.
N = round(simtime / dt)  # steps

fig, ax1 = plt.subplots()
# Plot some length over time