def test_copy():

    # Parameter
    simtime = 30.  # days
    dt = 1.
    N = round(simtime / dt)  # steps
    name = "Anagallis_femina_Leitner_2010"

    print("\n1 original")
    rs = pb.RootSystem()
    rs.openFile(name)
    rs.setSeed(1)  # before initialize to mimic
    rs.initialize()
    rs2 = pb.RootSystem(rs)
    rs.simulate(simtime)
    l1 = np.sum(v2a(rs.getParameter("length")))
    print("total length", l1)

    print("\n2 copy")
    rs2.simulate(simtime)
    l2 = np.sum(v2a(rs2.getParameter("length")))
    print("total length", l2)

    print("\n3 rebuild same")
    rs3 = pb.RootSystem()
    rs3.openFile(name)
    rs3.setSeed(1)
    rs3.initialize()
    rs3.simulate(simtime)
    l3 = np.sum(v2a(rs3.getParameter("length")))
    print("total length", l3)

    return
 def test_copy(self):
     """ checks if the root system can be copied, and if randomness works """
     seed = 110  # random seed
     name = "Brassica_oleracea_Vansteenkiste_2014"
     rs = pb.RootSystem()  # the original
     rs.readParameters("../modelparameter/rootsystem/" + name + ".xml")
     rs.setSeed(seed)
     rs.initialize(False)
     rs2 = rs.copy()  # copy root system
     n1 = rs.rand()
     self.assertIsNot(rs2, rs, "copy: not a copy")
     self.assertEqual(str(rs), str(rs2),
                      "copy: the organisms should be equal")
     self.assertEqual(rs2.rand(), n1,
                      "copy: random generator seed was not copied")
     rs.simulate(10)
     rs2.simulate(10)
     n2 = rs.rand()
     self.assertEqual(rs2.rand(), n2,
                      "copy: simulation is not deterministic")
     rs3 = pb.RootSystem()  # rebuild same
     rs3.readParameters("../modelparameter/rootsystem/" + name + ".xml")
     rs3.setSeed(seed)
     rs3.initialize(False)
     self.assertEqual(rs3.rand(), n1,
                      "copy: random generator seed was not copied")
     rs3.simulate(10)
     self.assertEqual(rs3.rand(), n2,
                      "copy: simulation is not deterministic")
Exemple #3
0
def simOnce(name, simtime, lbins, lrange, zbins, zrange, dx, dt):

    abins = 100
    arange = (-math.pi, math.pi)
    hl, hz, ha = None, None, None  # histograms

    # Simulation
    rs = pb.RootSystem()
    path = "../../../modelparameter/rootsystem/"
    rs.readParameters(path + name + ".xml")
    for p in rs.getRootRandomParameter():
        p.dx = dx
    rs.getRootRandomParameter(
        4
    ).theta = 80. / 180. * math.pi  # fix insertion angle of the basal roots
    rs.initialize()

    N = round(simtime / dt)
    for i in range(0, N):
        rs.simulate(dt, True)

    # Analysis
    img = np.zeros((2 * lbins, 2 * lbins))
    nodes = rs.getNodes()
    tips = rs.getRootTips()
    z_ = np.zeros(len(tips))
    l_ = np.zeros(len(tips))
    alpha_ = np.zeros(len(tips))
    c = 0  # counter
    mx, my = 0, 0  # mean tip position
    for t in tips:
        x, y, z = nodes[t].x, nodes[t].y, nodes[t].z

        # tip top view
        i = math.floor(((x + lrange[1]) / (2. * lrange[1])) * 2. *
                       float(lbins))  # np.around((x/lrange[1])*lbins+lbins)
        j = math.floor(((y + lrange[1]) / (2. * lrange[1])) * 2. *
                       float(lbins))  # np.around((y/lrange[1])*lbins+lbins)
        i = min(i, 2 * lbins - 1)
        j = min(j, 2 * lbins - 1)
        i = int(max(i, 0))
        j = int(max(j, 0))
        img[j, i] += 1.

        # depth and length distribution
        z_[c] = z
        l_[c] = math.sqrt(x * x + y * y)
        alpha_[c] = math.atan2(x, y)
        c += 1
        hl, bins = np.histogram(l_, bins=lbins, range=lrange)
        hz, bins = np.histogram(z_, bins=zbins, range=zrange)
        ha, bins = np.histogram(alpha_, bins=abins, range=arange)
        mx += nodes[t].x
        my += nodes[t].y

    if (len(tips) == 0):
        print("No tips?")
        return hl, hz, ha, img, mx, my
    else:
        return hl, hz, ha, img, mx / len(tips), my / len(tips)
    def test_dynamics(self):
        """ incremental root system growth like needed for coupling"""
        name = "Anagallis_femina_Leitner_2010"  # "maize_p2"  # "Anagallis_femina_Leitner_2010"  # "Zea_mays_4_Leitner_2014"
        rs = pb.RootSystem()
        rs.readParameters("../modelparameter/rootsystem/" + name + ".xml")
        rs.initialize(False)
        simtime = 60  # days
        dt = 1
        N = round(simtime / dt)
        nodes = np.array((list(map(np.array, rs.getNodes()))))
        nodeCTs = np.array(rs.getNodeCTs())
        seg = np.array([], dtype=np.int64).reshape(0, 2)
        cts = rs.getSegmentCTs()
        nonm = 0
        for i in range(0, N):
            rs.simulate(dt, False)
            # MOVE NODES
            uni = np.array((list(map(np.array, rs.getUpdatedNodeIndices()))),
                           dtype=np.int64)
            unodes = np.array((list(map(np.array, rs.getUpdatedNodes()))))
            ucts = np.array(rs.getUpdatedNodeCTs())
            if len(uni) > 0:
                nodes[uni] = unodes  # do the update
                nodeCTs[uni] = ucts
                nonm += uni.shape[0]
            # NEW NODES
            newnodes = np.array((list(map(np.array, rs.getNewNodes()))))
            newcts = np.array(rs.getNewNodeCTs())
            newsegs = np.array((list(map(np.array, rs.getNewSegments()))),
                               dtype=np.int64)
            if len(newnodes) != 0:
                nodes = np.vstack((nodes, newnodes))
                nodeCTs = np.append(nodeCTs, newcts)

            if len(newsegs) != 0:
                seg = np.vstack((seg, newsegs))

        nodes_ = np.array((list(map(np.array, rs.getNodes()))))
        nodeCTs_ = np.array(rs.getNodeCTs())
        seg_ = np.array((list(map(np.array, rs.getSegments()))),
                        dtype=np.int64)
        self.assertEqual(nodes_.shape, nodes.shape,
                         "incremental growth: node lists are not equal")
        self.assertEqual(nodeCTs_.shape, nodeCTs.shape,
                         "incremental growth: node lists are not equal")
        self.assertEqual(seg_.shape, seg.shape,
                         "incremental growth: node lists are not equal")
        uneq = np.sum(nodes_ != nodes) / 3
        self.assertEqual(uneq, 0,
                         "incremental growth: node lists are not equal")
        uneq = np.sum(nodeCTs_ != nodeCTs)
        self.assertEqual(
            uneq, 0,
            "incremental growth: node creation time lists are not equal")
        seg = np.sort(seg, axis=0)  # per default along the last axis
        seg_ = np.sort(seg_, axis=0)
        uneq = np.sum(seg_ != seg) / 2
        self.assertEqual(uneq, 0,
                         "incremental growth: segment lists are not equal")
Exemple #5
0
 def test_rsml(self):
     """ checks rsml functionality with Python rsml reader """
     name = "Anagallis_femina_Leitner_2010"
     rs = pb.RootSystem()
     rs.readParameters("../modelparameter/rootsystem/" + name + ".xml")
     rs.initialize(False)
     simtime = 60
     rs.simulate(simtime)
     rs.writeRSML(name + ".rsml")
     pl, props, funcs = read_rsml(name + ".rsml")
Exemple #6
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
Exemple #7
0
 def test_polylines(self):
     """checks if the polylines have the right tips and bases """
     name = "Brassica_napus_a_Leitner_2010"
     rs = pb.RootSystem()
     rs.readParameters("../modelparameter/rootsystem/" + name + ".xml")
     rs.initialize(False)
     rs.simulate(7)  # days young
     polylines = rs.getPolylines()  # Use polyline representation of the roots
     bases = np.zeros((len(polylines), 3))
     tips = np.zeros((len(polylines), 3))
     for i, r in enumerate(polylines):
         bases[i, :] = [r[0].x, r[0].y, r[0].z]
         tips[i, :] = [r[-1].x, r[-1].y, r[-1].z]
     nodes = np.array((list(map(np.array, rs.getNodes()))))  # Or, use node indices to find tip or base nodes
     tipI = rs.getRootTips()
     baseI = rs.getRootBases()
     uneq = np.sum(nodes[baseI, :] != bases) + np.sum(nodes[tipI, :] != tips)
     self.assertEqual(uneq, 0, "polylines: tips or base nodes do not agree")
Exemple #8
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
Exemple #9
0
def simulate(i):
    rs = pb.RootSystem()
    rs.readParameters(path + name + ".xml")
    set_all_sd(rs, 0.)  # set all sd to zero
    p1 = rs.getRootRandomParameter(1)  # tap and basal root type
    # 1. vary parameter
    p1.theta = theta0_[i]
    # 2. simulate
    rs.initializeLB(1, 1, False)
    rs.simulate(simtime, False)
    # 3. calculate target
    depth = 0.  # mean depth
    rad_dist = 0.  # mean raidal distance
    roots = rs.getPolylines()
    for r in roots:
        depth += r[-1].z
        rad_dist += math.hypot(r[-1].x, r[-1].y)
    depth /= len(roots)
    rad_dist /= len(roots)
    return depth, rad_dist
Exemple #10
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)
"""hydrotropism in a thin layer"""
import sys
sys.path.append("../../..")
sys.path.append("../../../src/python_modules")
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")

# 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)
import sys
sys.path.append("../../..")
import time
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import ticker
import matplotlib.colors as colors
from pyevtk.hl import gridToVTK
import plantbox as rb

simtime_ = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
for st in simtime_:
    #
    # Root system
    #
    rs = rb.RootSystem()

    path = "../../../modelparameter/rootsystem/"
    name = "test_root"
    rs.readParameters(path + name + ".xml")

    #set geometry
    width = 4  # cm
    depth = 15
    soilcore = rb.SDF_PlantContainer(width, width, depth, True)
    rs.setGeometry(soilcore)
    rs.setSeed(0)

    rs.initialize()

    for ii in range(0, st):
def simOnce(name, simtime, lbins, lrange, zbins, zrange, dx, dt):

    abins = 100
    arange = (-math.pi, math.pi)

    # Simulation
    rs = pb.RootSystem()
    rs.openFile(name, "modelparameter/")
    for p in rs.getRootRandomParameter():
        p.dx = dx

    rs.initialize()
    rs.getRootRandomParameter(
        4
    ).theta = 80. / 180. * math.pi  # fix insertion angle of the basal roots
    rs.initialize()

    N = round(simtime / dt)
    for i in range(0, N):
        rs.simulate(dt, True)

    # analysis
    img = np.zeros((2 * lbins, 2 * lbins))
    nodes = rs.getNodes()
    tips = rs.getRootTips()
    notips = len(tips)
    z_ = np.zeros(notips)
    l_ = np.zeros(notips)
    alpha_ = np.zeros(notips)
    c = 0
    mx = 0
    my = 0
    for t in tips:
        x = nodes[t].x
        y = nodes[t].y
        z = nodes[t].z

        # tip top view
        i = math.floor(((x + lrange[1]) / (2. * lrange[1])) * 2. *
                       float(lbins))  # np.around((x/lrange[1])*lbins+lbins)
        j = math.floor(((y + lrange[1]) / (2. * lrange[1])) * 2. *
                       float(lbins))  # np.around((y/lrange[1])*lbins+lbins)

        i = min(i, 2 * lbins - 1)
        j = min(j, 2 * lbins - 1)
        i = int(max(i, 0))
        j = int(max(j, 0))

        img[j, i] += 1.

        # depth, and length distribution
        z_[c] = z
        l_[c] = math.sqrt(x * x + y * y)
        alpha_[c] = math.atan2(x, y)
        c += 1
        hl, bins = np.histogram(l_, bins=lbins, range=lrange)
        hz, bins = np.histogram(z_, bins=zbins, range=zrange)
        ha, bins = np.histogram(alpha_, bins=abins, range=arange)
        mx += nodes[t].x
        my += nodes[t].y

    return hl, hz, ha, img, mx / len(tips), my / len(tips)
Exemple #14
0
# 1) Opens plant and root parameters from a file
# 2) Simulates root growth
# 3) Outputs a VTP (for vizualisation in ParaView)
#
#  Computes analytical solution of moving point/line sources based on Carslaw and Jaeger
#
import sys
sys.path.append("../..")

import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate

import plantbox as rb

rootsystem = rb.RootSystem()
name = "anagallis_straight"

#
# Open plant and root parameter from a file
#
rootsystem.openFile(name)
# rootsystem.writeParameters() # not exposed to python yet

#
# Initialize
#
rootsystem.initialize()

#
# Simulate
Exemple #15
0
def err (fitparams):    #parameters to be optimized
    lmaxp=fitparams[0]
    tropismNp=fitparams[1] 
    tropismSp=fitparams[2]
    rp=fitparams[3]

    simtime = 120
    M = 4  # number of plants in rows
    N = 2 # number of rows
    distp = 3  # distance between the root systems along row[cm]
    distr =12  # distance between the rows[cm]
    interrow=N*distr # inter-row spacing
    row=M*distp # row spacing

    r, depth, layers = 5, 100., 11 # Soil core analysis
    layerVolume = depth / layers * r * r * np.pi

    z_ = np.linspace(0, -1 * depth, layers)
    times = [120, 60, 30, 10]
    soilcolumn = pb.SDF_PlantContainer(r, r, depth, False)  # in the center of the root
    soilcolumn1 = pb.SDF_RotateTranslate(soilcolumn, 0, 0, pb.Vector3d(-6, 0, 0))
    soilcolumn2 = pb.SDF_RotateTranslate(soilcolumn, 0, 0, pb.Vector3d(6, 0, 0))

    soilcolumns=[soilcolumn1,soilcolumn, soilcolumn2]

    with open('rld.pkl','rb') as f:
        measured_RLD = pkl.load(f)
    real_RLD=np.reshape(measured_RLD,(measured_RLD.shape[0]*measured_RLD.shape[1]*measured_RLD.shape[2],1))
    rld=np.zeros([measured_RLD.shape[0],measured_RLD.shape[1],measured_RLD.shape[2]])
    # rld=np.zeros([len(soilcolumns),len(times),layers])

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

    # fig, axes = plt.subplots(nrows = 1, ncols = len(soilcolumns), figsize = (16, 8))

    # Make a root length distribution along the soil cores  

    for k in range(len(soilcolumns)):
        # 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")
                p1 = rs.getRootRandomParameter(1)  # tap and basal root type
                p1.lmax = lmaxp
                p1.tropismN=tropismNp
                p1.tropismS=tropismSp
                p1.r=rp
                for p in rs.getRootRandomParameter():
                    p.lns = 0
                    p.rs = 0
                    p.lmaxs = 0
                    p.thetas = 0
                    p.las = 0
                    p.lbs=0
                rs.setSeed(1)    
                rs.getRootSystemParameter().seedPos = pb.Vector3d(distr * i, distp * j, -3.)  # cm
                rs.initialize()
                allRS.append(rs)

        # Simulate
        for rs in allRS:
            rs.simulate(simtime)

        # Export results as single vtp files (as polylines)
        ana = pb.SegmentAnalyser()  # see example 3b
        for z, rs in enumerate(allRS):
            # vtpname = "results/rlds/plant_" + str(z) + ".vtp"
            # rs.write(vtpname)
            ana.addSegments(rs)  # collect all

        # Write all into single file (segments)
        # ana.write("results/rlds/all_plants.vtp")

        ana.mapPeriodic(interrow, row)
        # ana.write("results/rlds/plant_periodic.vtp")
        rl_ = []
        ana.crop(soilcolumns[k])
        ana.pack()
        # ana.write("results/rlds/core"+str(k+1)+".vtp")

        # axes[k].set_title('Soil core'+' ' +str(k+1))
        for j in range(len(times)):
            ana.filter("creationTime", 0, times[j])
            rl_.append(ana.distribution("length", 0., -depth, layers, True))
            # axes[k].plot(np.array(rl_[-1]) / layerVolume, z_)
        # axes[k].legend(["120 days", "60 days", "30 days", "15 days"])
        rld[k]=np.array(rl_)/layerVolume 

    # for a in axes:
    #     a.set_xlabel('RLD $(cm/cm^3)$')
    #     a.set_ylabel('Depth $(cm)$')
    #     a.set_xlim(0,np.max(rld))

    # fig.subplots_adjust()
    # plt.savefig("results/rlds/rld_plot.png")
    # plt.show()

    RLD=np.reshape(rld,(rld.shape[0]*rld.shape[1]*rld.shape[2],1))
    # print(rld)
    # with open('results/rlds/rld.pkl','wb') as f:
    #     pkl.dump(rld, f)
    # sys.exit()
    
    err = math.sqrt(sum(((np.subtract(RLD,real_RLD)))**2)/len(RLD)) #NRMSE
    return err