def run_to_time(self, tEnd, verbose=False, muted = False): """ Run the simulation to a specified point in time. Args: tEnd : (float) time in years up to run the model for... verbose : (bool) when :code:`True`, output additional debug information (default: :code:`False`). Warning: If specified end time (**tEnd**) is greater than the one defined in the XML input file priority is given to the XML value. """ assert hasattr(self, 'recGrid'), "DEM file has not been loaded. Configure one in your XML file or call the build_mesh function." if tEnd > self.input.tEnd: print('Specified end time is greater than the one used in the XML input file and has been adjusted!') tEnd = self.input.tEnd # Define non-flow related processes times if not self.simStarted: self.force.next_rain = self.force.T_rain[0, 0] self.force.next_disp = self.force.T_disp[0, 0] self.force.next_carb = self.force.T_carb[0, 0] self.force.next_display = self.input.tStart if self.input.laytime>0: self.force.next_layer = self.input.tStart + self.input.laytime else: self.force.next_layer = self.input.tEnd + 1000. self.exitTime = self.input.tEnd if self.input.flexure: self.force.next_flexure = self.input.tStart + self.input.ftime else: self.force.next_flexure = self.exitTime + self.input.tDisplay self.simStarted = True outStrata = 0 last_time = time.clock() last_output = time.clock() # Perform main simulation loop while self.tNow < tEnd: # At most, display output every 5 seconds tloop = time.clock() - last_time if time.clock() - last_output >= 5.0: # print('tNow = %s (step took %0.02f seconds)' % (self.tNow, tloop)) last_output = time.clock() last_time = time.clock() # Load precipitation rate if self.force.next_rain <= self.tNow and self.force.next_rain < self.input.tEnd: if self.tNow == self.input.tStart: ref_elev = buildMesh.get_reference_elevation(self.input, self.recGrid, self.elevation) self.force.getSea(self.tNow,self.input.udw,ref_elev) self.rain = np.zeros(self.totPts, dtype=float) self.rain[self.inIDs] = self.force.get_Rain(self.tNow, self.elevation, self.inIDs) # Load tectonic grid if not self.input.disp3d: # Vertical displacements if self.force.next_disp <= self.tNow and self.force.next_disp < self.input.tEnd: ldisp = np.zeros(self.totPts, dtype=float) ldisp.fill(-1.e6) ldisp[self.inIDs] = self.force.load_Tecto_map(self.tNow,self.inIDs) self.disp = self.force.disp_border(ldisp, self.FVmesh.neighbours, self.FVmesh.edge_length, self.recGrid.boundsPt) self.applyDisp = True else: # 3D displacements if self.force.next_disp <= self.tNow and self.force.next_disp < self.input.tEnd: if self.input.laytime == 0: updateMesh = self.force.load_Disp_map(self.tNow, self.FVmesh.node_coords[:, :2], self.inIDs) else: # Define 3D displacements on the stratal regions if self.strata is not None: updateMesh, regdX, regdY = self.force.load_Disp_map(self.tNow, self.FVmesh.node_coords[:, :2], self.inIDs, True, self.strata.xyi, self.strata.ids) else: updateMesh = self.force.load_Disp_map(self.tNow, self.FVmesh.node_coords[:, :2], self.inIDs) # Update mesh when a 3D displacements field has been loaded if updateMesh: self.force.dispZ = self.force.disp_border(self.force.dispZ, self.FVmesh.neighbours, self.FVmesh.edge_length, self.recGrid.boundsPt) # Define flexural flags fflex = 0 flexiso = None if self.input.flexure: flexiso = self.cumflex fflex = 1 # Define stratal flags fstrat = 0 sload = None if self.input.udw == 1 and self.tNow == self.input.tStart and self.strata is not None: if self.strata.oldload is None: self.strata.oldload = np.zeros(len(self.elevation), dtype=float) if self.strata is not None: if self.strata.oldload is None: self.strata.oldload = np.zeros(len(self.elevation), dtype=float) if self.input.laytime > 0 and self.strata.oldload is not None: sload = self.strata.oldload fstrat = 1 # Define erodibility map flags fero = 0 vKe = None vTh = None if self.input.erolays is not None: if self.input.erolays >= 0: fero = 1 vKe = self.mapero.Ke vTh = self.mapero.thickness # Apply horizontal displacements self.recGrid.tinMesh, self.elevation, self.cumdiff, self.cumhill, self.cumfail, self.wavediff, fcum, scum, Ke, Th = self.force.apply_XY_dispacements( self.recGrid.areaDel, self.fixIDs, self.elevation, self.cumdiff, self.cumhill, self.cumfail, self.wavediff, tflex=flexiso, scum=sload, Te=vTh,Ke=vKe, flexure=fflex, strat=fstrat, ero=fero) # Update relevant parameters in deformed TIN if fflex == 1: self.cumflex = fcum if fero == 1: self.mapero.Ke = Ke self.mapero.thickness = Th # Rebuild the computational mesh self._rebuild_mesh(verbose) # Update the stratigraphic mesh if self.input.laytime > 0 and self.strata is not None: self.strata.move_mesh(regdX, regdY, scum, verbose) # Compute isostatic flexure if self.tNow >= self.force.next_flexure: flextime = time.clock() ref_elev = buildMesh.get_reference_elevation(self.input, self.recGrid, self.elevation) self.force.getSea(self.tNow,self.input.udw,ref_elev) self.tinFlex = self.flex.get_flexure(self.elevation, self.cumdiff, self.force.sealevel,self.recGrid.boundsPt, initFlex=False) # Get border values self.tinFlex = self.force.disp_border(self.tinFlex, self.FVmesh.neighbours, self.FVmesh.edge_length, self.recGrid.boundsPt) # Update flexural parameters self.elevation += self.tinFlex self.cumflex += self.tinFlex # Update next flexure time self.force.next_flexure += self.input.ftime # print(" - Compute flexural isostasy %0.02f seconds" % (time.clock() - flextime)) # Compute wavesed parameters if self.tNow >= self.force.next_wave: wavetime = time.clock() if self.carbTIN is not None: # Update erosion/deposition due to SPM processes on carbTIN self.carbTIN.update_layers(self.cumdiff-self.oldsed,self.elevation) self.carbTIN.get_active_layer(self.input.tWave*self.input.wEro) actlay = self.carbTIN.alay else: actlay = None # Compute wave field and associated bottom current conditions waveED,nactlay = self.wave.compute_wavesed(self.tNow, self.input, self.force, self.elevation, actlay) # Update elevation / cumulative changes based on wave-induced sediment transport self.elevation += waveED self.cumdiff += waveED self.wavediff += waveED # print(" - Compute wave-induced sediment transport %0.02f seconds" % (time.clock() - wavetime)) # Update carbonate active layer if nactlay is not None: self.carbTIN.update_active_layer(nactlay,self.elevation) # Update next wave time step self.force.next_wave += self.input.tWave # Compute carbonate evolution if self.tNow >= self.next_carbStep: carbtime = time.clock() depth = self.elevation-self.force.sealevel if self.carbTIN is not None: # Update erosion/deposition due to river and diffusion on carbTIN self.carbTIN.update_layers(self.cumdiff-self.oldsed,self.elevation) # Compute reef growth if self.input.carbonate: # Load carbonate growth rates for species 1 and 2 during a given growth event if self.force.next_carb <= self.tNow and self.force.next_carb < self.input.tEnd: self.carbMaxGrowthSp1, self.carbMaxGrowthSp2 = self.force.get_carbGrowth(self.tNow, self.inIDs) self.carbval, self.carbval2 = self.carb.computeCarbonate(self.force.meanH, self.cumdiff-self.oldsed, depth, self.carbMaxGrowthSp1, self.carbMaxGrowthSp2, self.input.tCarb) if self.carbval2 is not None: self.cumdiff += self.carbval + self.carbval2 self.elevation += self.carbval + self.carbval2 else: self.cumdiff += self.carbval self.elevation += self.carbval if self.carbTIN is not None: self.carbTIN.paleoDepth[:,self.carbTIN.step] = self.elevation self.carbTIN.depoThick[:,self.carbTIN.step,1] += self.carbval self.carbTIN.layerThick[:,self.carbTIN.step] += self.carbval if self.carbval2 is not None: self.carbTIN.depoThick[:,self.carbTIN.step,2] += self.carbval2 self.carbTIN.layerThick[:,self.carbTIN.step] += self.carbval2 # Compute pelagic rain if self.input.pelagic: self.pelaval = self.pelagic.computePelagic(depth, self.input.tCarb) self.cumdiff += self.pelaval self.elevation += self.pelaval if self.carbTIN is not None: self.carbTIN.paleoDepth[:,self.carbTIN.step] = self.elevation self.carbTIN.depoThick[:,self.carbTIN.step,0] += self.pelaval self.carbTIN.layerThick[:,self.carbTIN.step] += self.pelaval # Update proportion based on top layer if self.prop is not None: ids = np.where(self.carbTIN.layerThick[:,self.carbTIN.step]>0.)[0] self.prop.fill(0.) self.prop[ids,0] = self.carbTIN.depoThick[ids,self.carbTIN.step,0]/self.carbTIN.layerThick[ids,self.carbTIN.step] if self.input.carbonate: self.prop[ids,1] = self.carbTIN.depoThick[ids,self.carbTIN.step,1]/self.carbTIN.layerThick[ids,self.carbTIN.step] if self.carbval2 is not None: self.prop[ids,2] = self.carbTIN.depoThick[ids,self.carbTIN.step,2]/self.carbTIN.layerThick[ids,self.carbTIN.step] # Update current cumulative erosion deposition self.oldsed = np.copy(self.cumdiff) self.next_carbStep += self.input.tCarb # print(" - Compute carbonate growth %0.02f seconds" % (time.clock() - carbtime)) # Update next stratal layer time if self.tNow >= self.force.next_layer: self.force.next_layer += self.input.laytime if self.straTIN is not None: self.straTIN.step += 1 if self.strata: sub = self.strata.buildStrata(muted, self.elevation, self.cumdiff, self.force.sealevel, self.recGrid.boundsPt,outStrata, self.outputStep) self.elevation += sub self.cumdiff += sub outStrata = 0 # Compute stream network self.fillH, self.elevation = buildFlux.streamflow(self.input, self.FVmesh, self.recGrid, self.force, self.hillslope, \ self.flow, self.elevation, self.lGIDs, self.rain, self.tNow, verbose) # Create checkpoint files and write HDF5 output if self.tNow >= self.force.next_display: if self.force.next_display > self.input.tStart: outStrata = 1 if not muted: checkPoints.write_checkpoints(self.input, self.recGrid, self.lGIDs, self.inIDs, self.tNow, self.FVmesh, self.tMesh, self.force, self.flow, self.rain, self.elevation, self.fillH, self.cumdiff, self.cumhill, self.cumfail, self.wavediff, self.outputStep, self.prop, self.mapero, self.cumflex) if self.straTIN is not None and self.outputStep % self.input.tmesh==0: meshtime = time.clock() if not muted: self.straTIN.write_hdf5_stratigraphy(self.lGIDs,self.outputStep) print(" - Write sediment mesh output %0.02f seconds" % (time.clock() - meshtime)) if self.carbTIN is not None and self.outputStep % self.input.tmesh==0: meshtime = time.clock() if not muted: self.carbTIN.write_hdf5_stratigraphy(self.lGIDs,self.outputStep) print(" - Write carbonate mesh output %0.02f seconds" % (time.clock() - meshtime)) # Update next display time last_output = time.clock() self.force.next_display += self.input.tDisplay self.outputStep += 1 if self.carbTIN is not None: self.carbTIN.step += 1 # Get the maximum time before updating one of the above processes / components tStop = min([self.force.next_display, self.force.next_layer, self.force.next_flexure, tEnd, self.force.next_wave, self.force.next_disp, self.force.next_rain, self.next_carbStep]) self.tNow, self.elevation, self.cumdiff, self.cumhill, self.cumfail, self.slopeTIN = buildFlux.sediment_flux(self.input, self.recGrid, self.hillslope, \ self.FVmesh, self.tMesh, self.flow, self.force, self.rain, self.lGIDs, self.applyDisp, self.straTIN, self.mapero, \ self.cumdiff, self.cumhill, self.cumfail, self.fillH, self.disp, self.inGIDs, self.elevation, self.tNow, tStop, verbose) tloop = time.clock() - last_time # print('tNow = %s (%0.02f seconds)' % (self.tNow, tloop)) # Isostatic flexure if self.input.flexure: flextime = time.clock() ref_elev = buildMesh.get_reference_elevation(self.input, self.recGrid, self.elevation) self.force.getSea(self.tNow,self.input.udw,ref_elev) self.tinFlex = self.flex.get_flexure(self.elevation, self.cumdiff, self.force.sealevel,self.recGrid.boundsPt,initFlex=False) # Get border values self.tinFlex = self.force.disp_border(self.tinFlex, self.FVmesh.neighbours, self.FVmesh.edge_length, self.recGrid.boundsPt) # Update flexural parameters self.elevation += self.tinFlex self.cumflex += self.tinFlex # Update next flexure time self.force.next_flexure += self.input.ftime # print(" - Compute flexural isostasy %0.02f seconds" % (time.clock() - flextime)) # Update next stratal layer time if self.tNow >= self.force.next_layer: self.force.next_layer += self.input.laytime sub = self.strata.buildStrata(muted,self.elevation, self.cumdiff, self.force.sealevel, self.recGrid.boundsPt,1, self.outputStep) self.elevation += sub self.cumdiff += sub # Create checkpoint files and write HDF5 output if self.input.udw == 0 or self.tNow == self.input.tEnd or self.tNow == self.force.next_display: if not muted: checkPoints.write_checkpoints(self.input, self.recGrid, self.lGIDs, self.inIDs, self.tNow, \ self.FVmesh, self.tMesh, self.force, self.flow, self.rain, \ self.elevation, self.fillH, self.cumdiff, self.cumhill, self.cumfail, self.wavediff, \ self.outputStep, self.prop, self.mapero, self.cumflex) if self.straTIN is not None and self.outputStep % self.input.tmesh==0: meshtime = time.clock() if not muted: self.straTIN.write_hdf5_stratigraphy(self.lGIDs,self.outputStep) print(" - Write sediment mesh output %0.02f seconds" % (time.clock() - meshtime)) if self.carbTIN is not None and self.outputStep % self.input.tmesh==0: meshtime = time.clock() if not muted: self.carbTIN.write_hdf5_stratigraphy(self.lGIDs,self.outputStep) print(" - Write carbonate mesh output %0.02f seconds" % (time.clock() - meshtime)) self.force.next_display += self.input.tDisplay self.outputStep += 1 if self.straTIN is not None: if not muted: self.straTIN.write_hdf5_stratigraphy(self.lGIDs,self.outputStep-1) if self.carbTIN is not None: if not muted: self.carbTIN.write_hdf5_stratigraphy(self.lGIDs,self.outputStep-1) self.carbTIN.step += 1
def streamflow(input, FVmesh, recGrid, force, hillslope, flow, elevation, \ lGIDs, rain, tNow, verbose=False): """ Compute stream flow. Args: input: class containing XML input file parameters. FVmesh: class describing the finite volume mesh. recGrid: class describing the regular grid characteristics. force: class describing the forcing parameters. hillslope: class describing hillslope processes. flow: class describing stream power law processes. elevation: numpy array containing the elevations for the domain. lGIDs: numpy 1D array containing the node indices. rain: numpy 1D array containing rainfall precipitation values. tNow: simulation time step. verbose : (bool) when :code:`True`, output additional debug information (default: :code:`False`). Returns ------- fillH numpy 1D array containing the depression-less elevation values. elev numpy 1D array containing the elevations. """ # Update sea-level walltime = time.clock() ref_elev = buildMesh.get_reference_elevation(input, recGrid, elevation) force.getSea(tNow, input.udw, ref_elev) fillH = None # Update river input force.getRivers(tNow) riverrain = rain + force.rivQw # Build an initial depression-less surface at start time if required if input.tStart == tNow and input.nopit == 1: fillH = elevationTIN.pit_stack(elevation, input.nopit, force.sealevel) elevation = fillH else: fillH = elevationTIN.pit_stack(elevation, 0, force.sealevel) if verbose and input.spl: print(" - depression-less algorithm PD with stack", time.clock() - walltime) # Compute stream network walltime = time.clock() flow.SFD_receivers(fillH, elevation, FVmesh.neighbours, FVmesh.vor_edges, FVmesh.edge_length, lGIDs) if verbose: print(" - compute receivers parallel ", time.clock() - walltime) # Distribute evenly local minimas to processors on filled surface walltime = time.clock() flow.localbase = flow.base flow.ordered_node_array_filled() if verbose: print(" - compute stack order locally for filled surface", time.clock() - walltime) walltime = time.clock() flow.stack = flow.localstack if verbose: print(" - send stack order for filled surface globally ", time.clock() - walltime) # Distribute evenly local minimas on real surface walltime = time.clock() flow.localbase1 = flow.base1 flow.ordered_node_array_elev() if verbose: print(" - compute stack order locally for real surface", time.clock() - walltime) walltime = time.clock() flow.stack1 = flow.localstack1 if verbose: print(" - send stack order for real surface globally ", time.clock() - walltime) # Compute a unique ID for each local depression and their downstream draining nodes flow.compute_parameters_depression(fillH, elevation, FVmesh.control_volumes, force.sealevel) # Compute discharge walltime = time.clock() flow.compute_flow(force.sealevel, elevation, FVmesh.control_volumes, riverrain) if verbose: print(" - compute discharge ", time.clock() - walltime) return fillH, elevation