示例#1
0
    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
示例#2
0
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