def figure8d(rs, N): col = 'r', 'g', 'b' zz = 1 # mean layer thickness (cm) # root length distributions rld = np.zeros((3 * N, int(140 / zz))) for j in range(0, N): for i in range(0, 3): ana = rb.SegmentAnalyser(rs[i + j * 3]) rld[i + j * 3, :] = np.transpose( v2a(ana.distribution("length", 0, 140, int(140 / zz), True))) / (zz * 75. * 15.) # cm /cm^3 # mean rld_mean = np.zeros((3, int(140 / zz))) for j in range(0, N): for i in range(0, 3): rld_mean[i, :] += rld[i + j * 3, :] / N # # error TDOO # rld_sd = np.zeros((3, int(140 / zz))) # for j in range(0, N): # for i in range(0, 3): # rld_sd[i, :] += np.square(rld[i + j * 3, :] - rld_mean[i, :]) # for i in range(0, 3): # rld_sd[i, :] = np.sqrt(rld_sd[i, :] / N) / np.sqrt(N) z_ = np.linspace(-140, 0, int(140 / zz) + 1) # for i in range(0, 3): # plt.errorbar(rld_mean[i][::-1], 0.5 * (z_[:-1] + z_[1:]), xerr = rld_sd[i][::-1], color = col[i], ecolor = col[i]) for i in range(0, 3): plt.plot(rld_mean[i][::-1], 0.5 * (z_[:-1] + z_[1:]), col[i])
def analyse(rs, name, simtime, tv0): top = rb.SDF_PlantBox(1e6, 1e6, 42) bot = rb.SDF_Complement(top) ana = rb.SegmentAnalyser(rs) print() print(name, ", age", simtime, "days") print("======================================") print() print("Number of ----------------------------") na = len(rs.getBaseRoots()) print("Axes ", na) nr = rs.getNumberOfRoots() print("Roots ", nr) ns = rs.getNumberOfSegments() print("Segments ", ns) print("\nLength (cm) --------------------------") tl = ana.getSummed("length") print("L0 ", round(tl)) tl_top = ana.getSummed("length", top) tl_bot = ana.getSummed("length", bot) print("Lcomp (top) ", round(tl_top), "(", round(100 * (tl_top / tl)), "%)") print("Lcomp (bot) ", round(tl_bot), "(", round(100 * (tl_bot / tl)), "%)") a = rb.SegmentAnalyser( rs ) # copyFor the record, I had already simulated the RSWMS scenarios with a single root and a large domain (see attached) but I think our parameterization is different as the results loo pretty dissimilar (did you really use 1.8e-5 for kr? Not 1.8e-4? the RS conductance is very small then: 0.0023cm3/hPa/d which explain the stress) a.filter("order", 0) l0 = a.getSummed("length") a = rb.SegmentAnalyser(rs) # copy a.filter("order", 1) l1 = a.getSummed("length") print("Lord (zero) ", round(l0), "(", round(100 * (l0 / tl)), "%)") print("Lord (first)", round(l1), "(", round(100 * (l1 / tl)), "%)") print("\nVolume -------------------------------") tv = ana.getSummed("volume") print("V0 (cm^3) ", tv) print("rVol ", tv / tv0) print()
def analyse(rs, name, simtime, tv0): top = rb.SDF_PlantBox(1e6, 1e6, 42) bot = rb.SDF_Complement(top) ana = rb.SegmentAnalyser(rs) print() print(name, ", age", simtime, "days") print("======================================") print() print("Number of ----------------------------") na = len(rs.getBaseRoots()) print("Axes ", na) nr = rs.getNumberOfRoots() print("Roots ", nr) ns = rs.getNumberOfSegments() print("Segments ", ns) print("\nLength (cm) --------------------------") tl = ana.getSummed(rb.ScalarType.length) print("L0 ", round(tl)) tl_top = ana.getSummed(rb.ScalarType.length, top) tl_bot = ana.getSummed(rb.ScalarType.length, bot) print("Lcomp (top) ", round(tl_top), "(", round(100 * (tl_top / tl)), "%)") print("Lcomp (bot) ", round(tl_bot), "(", round(100 * (tl_bot / tl)), "%)") a = rb.SegmentAnalyser(rs) # copy a.filter(rb.ScalarType.order, 0) l0 = a.getSummed(rb.ScalarType.length) a = rb.SegmentAnalyser(rs) # copy a.filter(rb.ScalarType.order, 1) l1 = a.getSummed(rb.ScalarType.length) print("Lord (zero) ", round(l0), "(", round(100 * (l0 / tl)), "%)") print("Lord (first)", round(l1), "(", round(100 * (l1 / tl)), "%)") print("\nVolume -------------------------------") tv = ana.getSummed(rb.ScalarType.volume) print("V0 (cm^3) ", tv) print("rVol ", tv / tv0) print()
# Soil core analysis r, depth, layers = 10, 100., 100 soilcolumn = rb.SDF_PlantContainer(r, r, depth, False) # in the center of the root soilcolumn2 = rb.SDF_RotateTranslate(soilcolumn, 0, 0, rb.Vector3d(10, 0, 0)) # shift 10 cm # pick one geometry for further analysis geom = soilcolumn z_ = np.linspace(0, -1 * depth, layers) fig, axes = plt.subplots(nrows = 1, ncols = 4, figsize = (16, 8)) for a in axes: a.set_xlabel('RLD (cm/cm)') a.set_ylabel('Depth (cm)') # Make a root length distribution ana = rb.SegmentAnalyser(rs) rl_ = ana.distribution("length", 0., depth, layers, True) axes[0].set_title('All roots (120 days)') axes[0].plot(rl_, z_) # Make a root length distribution along the soil core ana = rb.SegmentAnalyser(rs) # ana.crop(geom) ana.pack() rl_ = ana.distribution("length", 0., depth, layers, True) axes[1].set_title('Soil core (120 days)') axes[1].plot(rl_, z_) # How it looked after 30 days? ana = rb.SegmentAnalyser(rs) ana.filter("creationTime", 0, 30)
# p.nob = p.nob*5 # p = rs.getRootTypeParameter(3) # p.sbp = soilprop2 # simulation rs.initialize() simtime = 120. dt = 1. N = 120 / dt for i in range(0, round(N)): rs.simulate(dt, True) # analyse print() print("Left compartment: ") al = rb.SegmentAnalyser(rs) al.crop(left) ll = al.getSummed(rb.ScalarType.length) print('Total root length', ll, 'cm') lmct = al.getSummed(rb.ScalarType.time) / al.getSummed(rb.ScalarType.one) print('Mean age', simtime - lmct, 'days') lroots = al.getRoots() lm_theta = 0 for r in lroots: lm_theta += r.param.theta lm_theta /= len(lroots) print('Mean insertion angle is ', lm_theta / math.pi * 180, 'degrees') print() print("Right compartment: ") ar = rb.SegmentAnalyser(rs)
for rs in allRS: c += 1 # root system number vtpname = "results/" + name + str(c) + ".vtp" rs.write(vtpname, rb.OutputType.polylines) # # Compute vertical RLD distribution in layers # nl = 20 # number of layers vRLD = np.zeros((N, nl)) # N rows, nl columns depth = 100. c = 0 for rs in allRS: analysis = rb.SegmentAnalyser(rs) RLD = analysis.distribution(rb.ScalarType.length, 0, depth, nl, True) vRLD[c, :] = RLD vRLD[c, :] /= (depth / nl) c += 1 # root system number z = np.linspace(0, depth * (-1), nl) # depth*-1 is the (negativ) z coordinate mean = np.mean(vRLD, axis=0) std = np.std(vRLD, axis=0) #plt.figure(figsize=(3.8,3)) plt.plot(mean, z, 'k-', color="blue", linewidth=2) plt.fill_betweenx(z, mean + std, mean - std, color="blue", edgecolor='',
# 3. Rhizotubes as obstacles box = rb.SDF_PlantBox(96,126,130) # box rhizotube = rb.SDF_PlantContainer(6.4,6.4,96,False) # a single Rhizotube rhizoX = rb.SDF_RotateTranslate(rhizotube, 90, rb.SDF_Axis.yaxis, rb.Vector3d(96/2,0,0)) rhizotubes_ = rb.std_vector_SDF_() y_ = ( -30, -18, -6, 6, 18, 30 ) z_ = ( -10, -20, -40, -60, -80, -120 ) tube = [] for i in range(0,len(y_)): v = rb.Vector3d(0,y_[i],z_[i]) tube.append(rb.SDF_RotateTranslate(rhizoX, v)) rhizotubes_.append(tube[i]) rhizotubes = rb.SDF_Union(rhizotubes_) rhizoTube = rb.SDF_Difference(box, rhizotubes) # Simulate rs.setGeometry(rotatedRhizotron) # rotatedRhizotron, splitBox, or rhizoTube rs.initialize() rs.simulate(60) # days # Export results as segments rb.SegmentAnalyser(rs).write("results/example_3e.vtp") # Export container geometry as Paraview Python script rs.write("results/example_3e.py")
for i in range(0,N): for j in range(0,N): rs = rb.RootSystem() rs.openFile(name) rs.getRootSystemParameter().seedPos = rb.Vector3d(dist*i,dist*j,-3) # set position of seed [cm] allRS.append(rs) rs.initialize() # Simulate parallel simtime = 120 def simulate(i): allRS[i].simulate(simtime) pool = Pool() param_space = range(0,len(allRS)) d = [1 for res in pool.imap(simulate,param_space)] # Export results as single vtp files (as polylines) c = 0 ana = rb.SegmentAnalyser() # see example 3b for rs in allRS: c += 1 # root system number vtpname = "results/example_2b_"+str(c)+".vtp" rs.write(vtpname) ana.addSegments(rs) # collect all # Write all into single file (segments) ana.write("results/example_2b_all.vtp")
def call(cc): rs = rb.RootSystem() #name = "Triticum_aestivum_a_Bingham_2011" # is this the same as your wheat, Shehan? name = "wheat" rs.openFile(name) # Pore Geometry x_ = (-10, -5, 5, 15) # not 0, otherwise we start in crack y_ = (0, 0, 0, 0) #x_=(-10, -5) #y_=(0,0) crack = rb.SDF_PlantBox(1.0, 100, 160) # cm cracks_ = rb.std_vector_SDF_() py_cracks = [] for i in range(0, len(y_)): v = rb.Vector3d(x_[i], y_[i], 0) py_cracks.append(rb.SDF_RotateTranslate(crack, v)) cracks_.append(py_cracks[-1]) cracks = rb.SDF_Union(cracks_) rs.setPoreGeometry(cracks) # Increased elongation within the pores maxS = 2 # twice the elongation rate within the pore minS = 1 # normal elongation rate slope = 0 soil_prop = rb.SoilLookUpSDF(cracks, maxS, minS, slope) # Adjust Tropism sigma = [0.4] * 10 for i in range(0, 10): p = rs.getRootTypeParameter(i + 1) p.dx = 0.25 # adjust resolution p.tropismT = rb.TropismType.gravi p.tropismN = 1 # strength of tropism p.tropismS = sigma[i] p.se = soil_prop # Pore Local Axes v1 = rb.Vector3d(0.67, 0, 0) v2 = rb.Vector3d(0, 0.67, 0) v3 = rb.Vector3d(0, 0, 0.67) rs.setPoreLocalAxes(rb.Matrix3d(v1, v2, v3)) # Pore Conductivity Tensor t1 = rb.Vector3d(1.33, 0, 0) t2 = rb.Vector3d(0, 50.33, 0) t3 = rb.Vector3d(0, 0, 50.33) rs.setPoreConductivity(rb.Matrix3d(t1, t2, t3)) # Set up depth dependent elongation scaling function scale_elongation = rb.EquidistantGrid1D( 0, -160, 17) # todo: replace this by reading in data from CSV file scales = np.zeros( len(scale_elongation.grid) ) + 0.1 # scales from some equation (scale = function(soil_strength) ), where scale in (0,1) scale_elongation.data = a2v(scales) # set proportionality factors # Proportionally scale this function se2 = rb.ProportionalElongation() se2.setBaseLookUp(scale_elongation) # multiply the scale elongation functions se3 = rb.MultiplySoilLookUps(se2, soil_prop) # Manually set scaling function for i in range(0, 10): p = rs.getRootTypeParameter(i + 1) p.se = se3 # Initialize rs.initialize() # Simulate simtime = 30 * 8 # e.g. 30 or 60 days dt = 1 #0.5 * 1./24. N = round(simtime / dt) for i in range(0, N): # time-dependent and depth-dependent scaling function scales = np.loadtxt('W2.csv', delimiter=';', usecols=i) # reading in ith column from CSV file scale_elongation.data = a2v(scales * 1.00) # set the data of scale elongation rs.simulate(dt) # Export results (as vtp) #rs.write("../results/crack.vtp") # Export cracks #rs.setGeometry(cracks) # just for vizualisation #rs.write("../results/crack.py") z_ = np.linspace(0, -1 * 160, 160) # Make a root length distribution ana = rb.SegmentAnalyser(rs) rl_ = ana.distribution(rb.ScalarType.length, 0, 160, 160, True) np.set_printoptions(precision=4) np.savetxt("cw_" + str(cc) + ".txt", rl_, fmt="%.2f")
# rld_sd[i, :] = np.sqrt(rld_sd[i, :] / N) / np.sqrt(N) z_ = np.linspace(-140, 0, int(140 / zz) + 1) # for i in range(0, 3): # plt.errorbar(rld_mean[i][::-1], 0.5 * (z_[:-1] + z_[1:]), xerr = rld_sd[i][::-1], color = col[i], ecolor = col[i]) for i in range(0, 3): plt.plot(rld_mean[i][::-1], 0.5 * (z_[:-1] + z_[1:]), col[i]) names = ["maize_p1_zero_std", "maize_p2_zero_std", "maize_p3_zero_std"] ages = [63.5, 55.5, 58.5] N = 100 rs = [] for j in range(0, N): for i in range(0, 3): rs.append(simulate(names[i], ages[i])) names = ["P1", "P2", "P3"] tv0 = 1 for i in range(0, 3): if i == 0: # reference volume (P1) ana = rb.SegmentAnalyser(rs[0]) tv0 = ana.getSummed("volume") analyse(rs[i], names[i], ages[i], tv0) figure8d(rs, N) plt.grid(True) plt.xlabel("Root Length Density $[cm/cm^3]$") plt.show()
depth = 100. layers = 100 soilcolumn = rb.SDF_PlantContainer(r, r, depth, False) # in the center of the root soilcolumn2 = rb.SDF_RotateTranslate(soilcolumn, 0, 0, rb.Vector3d(10, 0, 0)) # shift 10 cm geom = soilcolumn2 z_ = np.linspace(0, -1 * depth, layers) fig, axes = plt.subplots(nrows=1, ncols=4, figsize=(16, 8)) for a in axes: a.set_xlabel('RLD (cm/cm)') a.set_ylabel('Depth (cm)') # make a root length distribution ana = rb.SegmentAnalyser(rootsystem) rl_ = ana.distribution(rb.ScalarType.length, 0., depth, layers, True) axes[0].set_title('All roots (120 days)') axes[0].plot(rl_, z_) # make a root length distribution along the soil core ana = rb.SegmentAnalyser(rootsystem) ana.crop(geom) ana.pack() rl_ = ana.distribution(rb.ScalarType.length, 0., depth, layers, True) axes[1].set_title('Soil core (120 days)') axes[1].plot(rl_, z_) # how it looked after 30 days? ana = rb.SegmentAnalyser(rootsystem) ana.filter(rb.ScalarType.time, 0, 30)