示例#1
0
import os
import time

from pyBadlands.remote import RemoteModel
from pyBadlands.model import Model

start_time = time.time()
model = Model()
model.load_xml('bench/input.xml')
model.run_to_time(4000)
print 'singlethread finished in %s seconds' % (time.time() - start_time)

for ncpus in range(1, 5):
    start_time = time.time()
    remote = RemoteModel(maxcpus=ncpus)
    # match the child's cwd to ours
    remote._view.execute('import os; os.chdir("%s")' % os.getcwd())
    remote.load_xml('bench/input.xml')
    remote.run_to_time(4000)
    print 'mpi (%d cores) finished in %s seconds' % (ncpus, time.time() - start_time)
示例#2
0
class SPM(object):
    def __init__(self,
                 mesh,
                 velocityField,
                 swarm,
                 materialField,
                 airIndex,
                 sedimentIndex,
                 XML,
                 resolution,
                 checkpoint_interval,
                 surfElevation=0.,
                 verbose=True,
                 restartFolder=None,
                 restartStep=None):

        self.SECONDS_PER_YEAR = 31556925.9747  # Tropical year in seconds
        self.verbose = verbose
        self.restartStep = restartStep
        self.restartFolder = restartFolder

        # AutoScaling
        self.scaleDIM = 1.0 / scaling_coefficients["[length]"].magnitude
        self.scaleTIME = 1.0 / scaling_coefficients["[time]"].magnitude

        self.mesh = mesh
        self.velocityField = velocityField
        self.swarm = swarm
        self.material_index = materialField
        self.airIndex = airIndex
        self.sedimentIndex = sedimentIndex
        self.resolution = resolution
        self.surfElevation = surfElevation
        self.checkpoint_interval = checkpoint_interval / self.scaleTIME / self.SECONDS_PER_YEAR

        self.XML = XML

        if rank == 0:
            self.badlands_model = BadlandsModel()
            self.badlands_model.load_xml(self.XML)
            if self.restartStep:
                self.badlands_model.input.restart = True
                self.badlands_model.input.rstep = self.restartStep
                self.badlands_model.input.rfolder = self.restartFolder
                self.badlands_model.input.outDir = self.restartFolder
                self.badlands_model.outputStep = self.restartStep

        self.minCoord = self.mesh.minCoord
        self.maxCoord = self.mesh.maxCoord

        self.time_years = 0.
        if self.restartStep:
            # Parse xmf for the last timestep time
            import xml.etree.ElementTree as etree
            xmf = self.restartFolder + "/xmf/tin.time" + str(
                self.restartStep) + ".xmf"
            tree = etree.parse(xmf)
            root = tree.getroot()
            self.time_years = float(root[0][0][0].attrib["Value"])

        self._tmp = _tempdir
        self._demfile = self._tmp + "/dem.csv"

        # Create Initial Flat DEM
        if rank == 0:
            self.dem = self._generate_flat_dem(self.minCoord, self.maxCoord,
                                               self.resolution,
                                               self.surfElevation,
                                               self.scaleDIM)

            np.savetxt(self._demfile, self.dem)
            # Build Mesh
            self.badlands_model.build_mesh(self._demfile, verbose=False)

            self.badlands_model.input.disp3d = True  # enable 3D displacements
            self.badlands_model.input.region = 0  # TODO: check what this does
            self.badlands_model.input.tStart = self.time_years
            self.badlands_model.tNow = self.time_years

            # Override the checkpoint/display interval in the Badlands model to
            # ensure BL and UW are synced
            self.badlands_model.input.tDisplay = self.checkpoint_interval

            # Set Badlands minimal distance between nodes before regridding
            self.badlands_model.force.merge3d = self.badlands_model.input.Afactor * self.badlands_model.recGrid.resEdges * 0.5

            # Bodge Badlands to perform an initial checkpoint
            # FIXME: we need to run the model for at least one iteration before this is generated. It would be nice if this wasn't the case.
            self.badlands_model.force.next_display = 0

        comm.Barrier()

        self._disp_inserted = False

        # Transfer the initial DEM state to Underworld
        self._update_material_types()

        comm.Barrier()

    def solve(self, dt, sigma=0):

        if rank == 0 and self.verbose:
            purple = "\033[0;35m"
            endcol = "\033[00m"
            print(purple + "Processing surface with Badlands" + endcol)
            sys.stdout.flush()

        dt_years = Dimensionalize(dt, UnitRegistry.years).magnitude

        if rank == 0:
            rg = self.badlands_model.recGrid
            if self.mesh.dim == 2:
                zVals = rg.regZ.mean(axis=1)
                np_surface = np.column_stack((rg.regX, zVals)) * self.scaleDIM

            if self.mesh.dim == 3:
                np_surface = np.column_stack(
                    (rg.rectX, rg.rectY, rg.rectZ)) * self.scaleDIM
        else:

            np_surface = None

        np_surface = comm.bcast(np_surface, root=0)
        comm.Barrier()

        # Get Velocity Field at the surface
        tracer_velocity_mps = get_UW_velocities(
            np_surface, self.velocityField) * self.scaleTIME / self.scaleDIM

        if rank == 0:
            # Use the tracer vertical velocities to deform the Badlands TIN
            # convert from meters per second to meters displacement over the whole iteration
            tracer_disp = tracer_velocity_mps * self.SECONDS_PER_YEAR * dt_years
            self._inject_badlands_displacement(self.time_years, dt_years,
                                               tracer_disp, sigma)

            # Run the Badlands model to the same time point
            self.badlands_model.run_to_time(self.time_years + dt_years)

        self.time_years += dt_years

        # TODO: Improve the performance of this function
        self._update_material_types()
        comm.Barrier()

        if rank == 0 and self.verbose:
            purple = "\033[0;35m"
            endcol = "\033[00m"
            print(purple + "Processing surface with Badlands...Done" + endcol)
            sys.stdout.flush()

        return

    def _determine_particle_state_2D(self):

        if rank == 0:
            known_xy = self.badlands_model.recGrid.tinMesh[
                'vertices'] * self.scaleDIM  # points that we have known elevation for
            known_z = self.badlands_model.elevation * self.scaleDIM  # elevation for those points
            xs = self.badlands_model.recGrid.regX * self.scaleDIM
            ys = self.badlands_model.recGrid.regY * self.scaleDIM
        else:
            known_xy = None
            known_z = None
            xs = None
            ys = None

        known_xy = comm.bcast(known_xy, root=0)
        known_z = comm.bcast(known_z, root=0)
        xs = comm.bcast(xs, root=0)
        ys = comm.bcast(ys, root=0)

        comm.Barrier()

        grid_x, grid_y = np.meshgrid(xs, ys)
        interpolate_z = griddata(known_xy,
                                 known_z, (grid_x, grid_y),
                                 method='nearest').T
        interpolate_z = interpolate_z.mean(axis=1)

        f = interp1d(xs, interpolate_z)

        uw_surface = self.swarm.particleCoordinates.data
        bdl_surface = f(uw_surface[:, 0])

        flags = uw_surface[:, 1] < bdl_surface

        return flags

    def _determine_particle_state(self):
        # Given Badlands' mesh, determine if each particle in 'volume' is above
        # (False) or below (True) it.

        # To do this, for each X/Y pair in 'volume', we interpolate its Z value
        # relative to the mesh in blModel. Then, if the interpolated Z is
        # greater than the supplied Z (i.e. Badlands mesh is above particle
        # elevation) it's sediment (True). Else, it's air (False).

        # TODO: we only support air/sediment layers right now; erodibility
        # layers are not implemented

        if rank == 0:
            known_xy = self.badlands_model.recGrid.tinMesh[
                'vertices'] * self.scaleDIM  # points that we have known elevation for
            known_z = self.badlands_model.elevation * self.scaleDIM  # elevation for those points
        else:
            known_xy = None
            known_z = None

        known_xy = comm.bcast(known_xy, root=0)
        known_z = comm.bcast(known_z, root=0)

        comm.Barrier()

        volume = self.swarm.particleCoordinates.data

        interpolate_xy = volume[:, [0, 1]]

        # NOTE: we're using nearest neighbour interpolation. This should be
        # sufficient as Badlands will normally run at a much higher resolution
        # than Underworld. 'linear' interpolation is much, much slower.
        interpolate_z = griddata(points=known_xy,
                                 values=known_z,
                                 xi=interpolate_xy,
                                 method='nearest')

        # True for sediment, False for air
        flags = volume[:, 2] < interpolate_z

        return flags

    def _update_material_types(self):

        # What do the materials (in air/sediment terms) look like now?
        if self.mesh.dim == 3:
            material_flags = self._determine_particle_state()
        if self.mesh.dim == 2:
            material_flags = self._determine_particle_state_2D()

        # If any materials changed state, update the Underworld material types
        mi = self.material_index.data

        # convert air to sediment
        for air_material in self.airIndex:
            sedimented_mask = np.logical_and(np.in1d(mi, air_material),
                                             material_flags)
            mi[sedimented_mask] = self.sedimentIndex

        # convert sediment to air
        for air_material in self.airIndex:
            eroded_mask = np.logical_and(~np.in1d(mi, air_material),
                                         ~material_flags)
            mi[eroded_mask] = self.airIndex[0]

    def _inject_badlands_displacement(self, time, dt, disp, sigma):
        """
        Takes a plane of tracer points and their DISPLACEMENTS in 3D over time
        period dt applies a gaussian filter on it. Injects it into Badlands as 3D
        tectonic movement.
        """

        # The Badlands 3D interpolation map is the displacement of each DEM
        # node at the end of the time period relative to its starting position.
        # If you start a new displacement file, it is treated as starting at
        # the DEM starting points (and interpolated onto the TIN as it was at
        # that tNow).

        # kludge; don't keep adding new entries
        if self._disp_inserted:
            self.badlands_model.force.T_disp[0, 0] = time
            self.badlands_model.force.T_disp[0, 1] = (time + dt)
        else:
            self.badlands_model.force.T_disp = np.vstack(
                ([time, time + dt], self.badlands_model.force.T_disp))
            self._disp_inserted = True

        # Extent the velocity field in the third dimension
        if self.mesh.dim == 2:
            dispX = np.tile(disp[:, 0], self.badlands_model.recGrid.rny)
            dispY = np.zeros((self.badlands_model.recGrid.rnx *
                              self.badlands_model.recGrid.rny, ))
            dispZ = np.tile(disp[:, 1], self.badlands_model.recGrid.rny)

            disp = np.zeros((self.badlands_model.recGrid.rnx *
                             self.badlands_model.recGrid.rny, 3))
            disp[:, 0] = dispX
            disp[:, 1] = dispY
            disp[:, 2] = dispZ

        # Gaussian smoothing
        if sigma > 0:
            dispX = np.copy(disp[:,
                                 0]).reshape(self.badlands_model.recGrid.rnx,
                                             self.badlands_model.recGrid.rny)
            dispY = np.copy(disp[:,
                                 1]).reshape(self.badlands_model.recGrid.rnx,
                                             self.badlands_model.recGrid.rny)
            dispZ = np.copy(disp[:,
                                 2]).reshape(self.badlands_model.recGrid.rnx,
                                             self.badlands_model.recGrid.rny)
            smoothX = gaussian_filter(dispX, sigma)
            smoothY = gaussian_filter(dispY, sigma)
            smoothZ = gaussian_filter(dispZ, sigma)
            disp[:, 0] = smoothX.flatten()
            disp[:, 1] = smoothY.flatten()
            disp[:, 2] = smoothZ.flatten()

        self.badlands_model.force.injected_disps = disp

    def _generate_flat_dem(self,
                           minCoord,
                           maxCoord,
                           resolution,
                           elevation,
                           scale=1.):
        """
        Generate a flat DEM. This can be used as the initial Badlands state.

        minCoord: tuple of (X, Y, Z) coordinates defining the minimum bounds of
                  the DEM. Only the X and Y coordinates are used.
        maxCoord: tuple of (X, Y, Z) coordinates defining the maximum bounds of
                  the DEM. Only the X and Y coordinates are used.
        resolution: resolution of the model. Badlands assumes dx = dy.
        elevation: the Z parameter that each point is created at
        scale: the scaling factor between the 2 codes

        For your convenience, minCoord and maxCoord are designed to have the
        same formatting as the Underworld FeMesh_Cartesian minCoord and
        maxCoord parameters.

        IMPORTANT: minCoord and maxCoord are defined in terms of the Underworld
        coordinate system, but the returned DEM uses the Badlands coordinate
        system.

        Note that the initial elevation of the Badlands surface should coincide
        with the material transition in Underworld.
        """

        # Calculate number of nodes from required resolution.
        nx = np.int((maxCoord[0] - minCoord[0]) / resolution) + 1
        ny = np.int((maxCoord[1] - minCoord[1]) / resolution) + 1

        if self.mesh.dim == 2:
            minCoord = (minCoord[0], minCoord[0])
            maxCoord = (maxCoord[0], maxCoord[0])
            ny = nx

        items = []
        # FIXME: there should be a fast numpy way to do this
        for y in np.linspace(minCoord[1] / scale, maxCoord[1] / scale, ny):
            for x in np.linspace(minCoord[0] / scale, maxCoord[0] / scale, nx):
                items.append([x, y, elevation / scale])

        # NOTE: Badlands uses the difference in X coord of the first two points to determine the resolution.
        # This is something we should fix.
        # This is why we loop in y/x order instead of x/y order.
        return np.array(items)
示例#3
0
    def __init__(self,
                 mesh,
                 velocityField,
                 swarm,
                 materialField,
                 airIndex,
                 sedimentIndex,
                 XML,
                 resolution,
                 checkpoint_interval,
                 surfElevation=0.,
                 verbose=True,
                 restartFolder=None,
                 restartStep=None):

        self.SECONDS_PER_YEAR = 31556925.9747  # Tropical year in seconds
        self.verbose = verbose
        self.restartStep = restartStep
        self.restartFolder = restartFolder

        # AutoScaling
        self.scaleDIM = 1.0 / scaling_coefficients["[length]"].magnitude
        self.scaleTIME = 1.0 / scaling_coefficients["[time]"].magnitude

        self.mesh = mesh
        self.velocityField = velocityField
        self.swarm = swarm
        self.material_index = materialField
        self.airIndex = airIndex
        self.sedimentIndex = sedimentIndex
        self.resolution = resolution
        self.surfElevation = surfElevation
        self.checkpoint_interval = checkpoint_interval / self.scaleTIME / self.SECONDS_PER_YEAR

        self.XML = XML

        if rank == 0:
            self.badlands_model = BadlandsModel()
            self.badlands_model.load_xml(self.XML)
            if self.restartStep:
                self.badlands_model.input.restart = True
                self.badlands_model.input.rstep = self.restartStep
                self.badlands_model.input.rfolder = self.restartFolder
                self.badlands_model.input.outDir = self.restartFolder
                self.badlands_model.outputStep = self.restartStep

        self.minCoord = self.mesh.minCoord
        self.maxCoord = self.mesh.maxCoord

        self.time_years = 0.
        if self.restartStep:
            # Parse xmf for the last timestep time
            import xml.etree.ElementTree as etree
            xmf = self.restartFolder + "/xmf/tin.time" + str(
                self.restartStep) + ".xmf"
            tree = etree.parse(xmf)
            root = tree.getroot()
            self.time_years = float(root[0][0][0].attrib["Value"])

        self._tmp = _tempdir
        self._demfile = self._tmp + "/dem.csv"

        # Create Initial Flat DEM
        if rank == 0:
            self.dem = self._generate_flat_dem(self.minCoord, self.maxCoord,
                                               self.resolution,
                                               self.surfElevation,
                                               self.scaleDIM)

            np.savetxt(self._demfile, self.dem)
            # Build Mesh
            self.badlands_model.build_mesh(self._demfile, verbose=False)

            self.badlands_model.input.disp3d = True  # enable 3D displacements
            self.badlands_model.input.region = 0  # TODO: check what this does
            self.badlands_model.input.tStart = self.time_years
            self.badlands_model.tNow = self.time_years

            # Override the checkpoint/display interval in the Badlands model to
            # ensure BL and UW are synced
            self.badlands_model.input.tDisplay = self.checkpoint_interval

            # Set Badlands minimal distance between nodes before regridding
            self.badlands_model.force.merge3d = self.badlands_model.input.Afactor * self.badlands_model.recGrid.resEdges * 0.5

            # Bodge Badlands to perform an initial checkpoint
            # FIXME: we need to run the model for at least one iteration before this is generated. It would be nice if this wasn't the case.
            self.badlands_model.force.next_display = 0

        comm.Barrier()

        self._disp_inserted = False

        # Transfer the initial DEM state to Underworld
        self._update_material_types()

        comm.Barrier()
# parameters for our model composition
MIN_COORD = (0., 0., -80e3)
MAX_COORD = (100e3, 70e3, 20e3
             )  # this crashes at DEM load? do we have X/Y swapped?
# MAX_COORD = (100e3, 100e3, 20e3)
INITIAL_AIR_ELEVATION = 0.0  # the height at which we transition from sediment to air

# Put a rectangular prism underground
cubeSize = (10e3, 20e3, 20e3)
centre = (50e3, 25e3, -30e3)

linkage = LinkageModel()

### SET UP THE BADLANDS MODEL
badlands_model = BadlandsModel()
badlands_model.load_xml('no_erosion_clock.xml')
linkage.badlands_model = badlands_model

# IMPORTANT: disable BL->UW transfers
# Because erosion is disabled in the Badlands config, this completely uncouples
# the two models. They independently advect the surface. In this way, we can
# ensure that they advect identically.
linkage.disable_material_changes = True

# Load a flat DEM
bl_dem = linkage.generate_flat_dem(minCoord=MIN_COORD,
                                   maxCoord=MAX_COORD,
                                   resolution=(180, 180),
                                   elevation=INITIAL_AIR_ELEVATION)
linkage.load_badlands_dem_array(bl_dem)
示例#5
0
#    dome.buildGrid(elevation=dome.Z, nameCSV='dem')

import numpy
import os
import pandas

from pyBadlands.model import Model as BadlandsModel
import underworld as uw
from underworld import function as fn
from linkagemodel.linkage import LinkageModel

linkage = LinkageModel()


### SET UP THE BADLANDS MODEL
badlands_model = BadlandsModel()
badlands_model.load_xml('badlands.xml')
linkage.badlands_model = badlands_model

# We're going to load from a DEM; let's just load it to determine the Underworld mesh size
dem = pandas.read_csv('dem.csv', sep=' ', header=None, na_filter=False, dtype=numpy.float, low_memory=False)

# set up min/max coord for UW
min_coord = [dem[0].min(), dem[1].min(), -1e3]
max_coord = [dem[0].max(), dem[1].max(), +1e3]

print 'The model has bounds %s to %s' % (min_coord, max_coord)


### SET UP THE UNDERWORLD MODEL
示例#6
0
    def _init_model(self):

        if self.minCoord:
            self.minCoord = tuple([nd(val) for val in self.minCoord])
        else:
            self.minCoord = self.Model.mesh.minCoord

        if self.maxCoord:
            self.maxCoord = tuple([nd(val) for val in self.maxCoord])
        else:
            self.maxCoord = self.Model.mesh.maxCoord

        if self.Model.mesh.dim == 2:
            self.minCoord = (self.minCoord[0],
                             self.aspectRatio2d * self.minCoord[0])
            self.maxCoord = (self.maxCoord[0],
                             self.aspectRatio2d * self.maxCoord[0])

        if rank == 0:
            from pyBadlands.model import Model as BadlandsModel
            self.badlands_model = BadlandsModel()
            self.badlands_model.load_xml(self.XML)

            if self.restartStep:
                self.badlands_model.input.restart = True
                self.badlands_model.input.rstep = self.restartStep
                self.badlands_model.input.rfolder = self.restartFolder
                self.badlands_model.input.outDir = self.restartFolder
                self.badlands_model.outputStep = self.restartStep

                # Parse xmf for the last timestep time
                import xml.etree.ElementTree as etree
                xmf = (self.restartFolder + "/xmf/tin.time" +
                       str(self.restartStep) + ".xmf")
                tree = etree.parse(xmf)
                root = tree.getroot()
                self.time_years = float(root[0][0][0].attrib["Value"])

            # Create Initial DEM
            self._demfile = _tempdir + "/dem.csv"
            self.dem = self._generate_dem()
            np.savetxt(self._demfile, self.dem)

            # Build Mesh
            self.badlands_model.build_mesh(self._demfile, verbose=False)

            self.badlands_model.input.outDir = self.outputDir
            self.badlands_model.input.disp3d = True  # enable 3D displacements
            self.badlands_model.input.region = 0  # TODO: check what this does
            self.badlands_model.input.tStart = self.time_years
            self.badlands_model.tNow = self.time_years

            # Override the checkpoint/display interval in the Badlands model to
            # ensure BL and UW are synced
            self.badlands_model.input.tDisplay = (dimensionalise(
                self.checkpoint_interval, u.years).magnitude)

            # Set Badlands minimal distance between nodes before regridding
            self.badlands_model.force.merge3d = (
                self.badlands_model.input.Afactor *
                self.badlands_model.recGrid.resEdges * 0.5)

            # Bodge Badlands to perform an initial checkpoint
            # FIXME: we need to run the model for at least one
            # iteration before this is generated.
            # It would be nice if this wasn't the case.
            self.badlands_model.force.next_display = 0

        comm.Barrier()

        self._disp_inserted = False

        # Transfer the initial DEM state to Underworld
        self._update_material_types()
        comm.Barrier()
示例#7
0
#
# To run this on an MPI cluster, use something like:
#
#     mpiexec -n 4 python launch_mpi.py 1000

import os
import re
import sys
import time

from pyBadlands.model import Model

base_path = '.'
xml_name = 'hrtest.xml'

run_years = int(sys.argv[1])

# Modify base_path to run from another directory
# Change into HRtest directory if required...
os.chdir(base_path)

start_time = time.time()
model = Model()

print 'loading %s' % xml_name

print model.load_xml(xml_name)

print model.run_to_time(run_years)
print 'run to %s years finished in %s seconds' % (run_years,
                                                  time.time() - start_time)
示例#8
0
from linkagemodel.linkage import LinkageModel

# We're going to load from a DEM; let's just load it to determine the Underworld mesh size
dem = pandas.read_csv('nodes.csv', sep=' ', header=None, na_filter=False, dtype=numpy.float, low_memory=False)

# set up min/max coord for UW
min_coord = [dem[0].min(), dem[1].min(), -20e3]
max_coord = [dem[0].max(), dem[1].max(), +20e3]

print 'The model has bounds %s to %s' % (min_coord, max_coord)

linkage = LinkageModel()


### SET UP THE BADLANDS MODEL
badlands_model = BadlandsModel()
badlands_model.load_xml('dem.xml')  # The XML file specifies the DEM to load
linkage.badlands_model = badlands_model


### SET UP THE UNDERWORLD MODEL

# All output will go to the 'uwout' directory, which we will create
uw_output_path = 'uwout'
try:
    os.mkdir(uw_output_path)
except OSError:
    # probably already exists
    pass

UNDERWORLD_RESOLUTION = 20
示例#9
0
class Badlands(SurfaceProcesses):
    """ A wrapper class for Badlands """
    def __init__(self,
                 airIndex,
                 sedimentIndex,
                 XML,
                 resolution,
                 checkpoint_interval,
                 surfElevation=0.,
                 verbose=True,
                 Model=None,
                 outputDir="outbdls",
                 restartFolder=None,
                 restartStep=None,
                 timeField=None,
                 minCoord=None,
                 maxCoord=None,
                 aspectRatio2d=1.):
        try:
            import pyBadlands

        except ImportError:
            raise ImportError("""pyBadlands import as failed. Please check your
                              installation, PYTHONPATH and PATH environment
                              variables""")

        self.verbose = verbose
        self.outputDir = outputDir
        self.restartStep = restartStep
        self.restartFolder = restartFolder

        self.airIndex = airIndex
        self.sedimentIndex = sedimentIndex
        self.resolution = nd(resolution)
        self.surfElevation = fn.Function.convert(nd(surfElevation))
        self.checkpoint_interval = nd(checkpoint_interval)
        self.timeField = timeField
        self.XML = XML
        self.time_years = 0.
        self.minCoord = minCoord
        self.maxCoord = maxCoord
        self.aspectRatio2d = aspectRatio2d
        self.Model = Model

    def _init_model(self):

        if self.minCoord:
            self.minCoord = tuple([nd(val) for val in self.minCoord])
        else:
            self.minCoord = self.Model.mesh.minCoord

        if self.maxCoord:
            self.maxCoord = tuple([nd(val) for val in self.maxCoord])
        else:
            self.maxCoord = self.Model.mesh.maxCoord

        if self.Model.mesh.dim == 2:
            self.minCoord = (self.minCoord[0],
                             self.aspectRatio2d * self.minCoord[0])
            self.maxCoord = (self.maxCoord[0],
                             self.aspectRatio2d * self.maxCoord[0])

        if rank == 0:
            from pyBadlands.model import Model as BadlandsModel
            self.badlands_model = BadlandsModel()
            self.badlands_model.load_xml(self.XML)

            if self.restartStep:
                self.badlands_model.input.restart = True
                self.badlands_model.input.rstep = self.restartStep
                self.badlands_model.input.rfolder = self.restartFolder
                self.badlands_model.input.outDir = self.restartFolder
                self.badlands_model.outputStep = self.restartStep

                # Parse xmf for the last timestep time
                import xml.etree.ElementTree as etree
                xmf = (self.restartFolder + "/xmf/tin.time" +
                       str(self.restartStep) + ".xmf")
                tree = etree.parse(xmf)
                root = tree.getroot()
                self.time_years = float(root[0][0][0].attrib["Value"])

            # Create Initial DEM
            self._demfile = _tempdir + "/dem.csv"
            self.dem = self._generate_dem()
            np.savetxt(self._demfile, self.dem)

            # Build Mesh
            self.badlands_model.build_mesh(self._demfile, verbose=False)

            self.badlands_model.input.outDir = self.outputDir
            self.badlands_model.input.disp3d = True  # enable 3D displacements
            self.badlands_model.input.region = 0  # TODO: check what this does
            self.badlands_model.input.tStart = self.time_years
            self.badlands_model.tNow = self.time_years

            # Override the checkpoint/display interval in the Badlands model to
            # ensure BL and UW are synced
            self.badlands_model.input.tDisplay = (dimensionalise(
                self.checkpoint_interval, u.years).magnitude)

            # Set Badlands minimal distance between nodes before regridding
            self.badlands_model.force.merge3d = (
                self.badlands_model.input.Afactor *
                self.badlands_model.recGrid.resEdges * 0.5)

            # Bodge Badlands to perform an initial checkpoint
            # FIXME: we need to run the model for at least one
            # iteration before this is generated.
            # It would be nice if this wasn't the case.
            self.badlands_model.force.next_display = 0

        comm.Barrier()

        self._disp_inserted = False

        # Transfer the initial DEM state to Underworld
        self._update_material_types()
        comm.Barrier()

    def _generate_dem(self):
        """
        Generate a badlands DEM. This can be used as the initial Badlands state.

        """

        # Calculate number of nodes from required resolution.
        nx = np.int((self.maxCoord[0] - self.minCoord[0]) / self.resolution)
        ny = np.int((self.maxCoord[1] - self.minCoord[1]) / self.resolution)
        nx += 1
        ny += 1

        x = np.linspace(self.minCoord[0], self.maxCoord[0], nx)
        y = np.linspace(self.minCoord[1], self.maxCoord[1], ny)

        coordsX, coordsY = np.meshgrid(x, y)

        dem = np.zeros((nx * ny, 3))
        dem[:, 0] = coordsX.flatten()
        dem[:, 1] = coordsY.flatten()

        coordsZ = self.surfElevation.evaluate(dem[:, :2])

        dem[:, 2] = coordsZ.flatten()
        return dimensionalise(dem, u.meter).magnitude

    def solve(self, dt, sigma=0):
        if rank == 0 and self.verbose:
            purple = "\033[0;35m"
            endcol = "\033[00m"
            print(purple + "Processing surface with Badlands" + endcol)
            sys.stdout.flush()

        np_surface = None
        if rank == 0:
            rg = self.badlands_model.recGrid
            if self.Model.mesh.dim == 2:
                zVals = rg.regZ.mean(axis=1)
                np_surface = np.column_stack((rg.regX, zVals))

            if self.Model.mesh.dim == 3:
                np_surface = np.column_stack((rg.rectX, rg.rectY, rg.rectZ))

        np_surface = comm.bcast(np_surface, root=0)
        comm.Barrier()

        # Get Velocity Field at the surface
        nd_coords = nd(np_surface * u.meter)
        tracer_velocity = self.Model.velocityField.evaluate_global(nd_coords)

        dt_years = dimensionalise(dt, u.years).magnitude

        if rank == 0:
            tracer_disp = dimensionalise(tracer_velocity * dt,
                                         u.meter).magnitude
            self._inject_badlands_displacement(self.time_years, dt_years,
                                               tracer_disp, sigma)

            # Run the Badlands model to the same time point
            self.badlands_model.run_to_time(self.time_years + dt_years)

        self.time_years += dt_years

        # TODO: Improve the performance of this function
        self._update_material_types()
        comm.Barrier()

        if rank == 0 and self.verbose:
            purple = "\033[0;35m"
            endcol = "\033[00m"
            print(purple + "Processing surface with Badlands...Done" + endcol)
            sys.stdout.flush()

        return

    def _determine_particle_state_2D(self):

        known_xy = None
        known_z = None
        xs = None
        ys = None
        fact = dimensionalise(1.0, u.meter).magnitude
        if rank == 0:
            # points that we have known elevation for
            known_xy = self.badlands_model.recGrid.tinMesh['vertices'] / fact
            # elevation for those points
            known_z = self.badlands_model.elevation / fact
            xs = self.badlands_model.recGrid.regX / fact
            ys = self.badlands_model.recGrid.regY / fact

        known_xy = comm.bcast(known_xy, root=0)
        known_z = comm.bcast(known_z, root=0)
        xs = comm.bcast(xs, root=0)
        ys = comm.bcast(ys, root=0)

        comm.Barrier()

        grid_x, grid_y = np.meshgrid(xs, ys)
        interpolate_z = griddata(known_xy,
                                 known_z, (grid_x, grid_y),
                                 method='nearest').T
        interpolate_z = interpolate_z.mean(axis=1)

        f = interp1d(xs, interpolate_z)

        uw_surface = self.Model.swarm.particleCoordinates.data
        bdl_surface = f(uw_surface[:, 0])

        flags = uw_surface[:, 1] < bdl_surface

        return flags

    def _determine_particle_state(self):
        # Given Badlands' mesh, determine if each particle in 'volume' is above
        # (False) or below (True) it.

        # To do this, for each X/Y pair in 'volume', we interpolate its Z value
        # relative to the mesh in blModel. Then, if the interpolated Z is
        # greater than the supplied Z (i.e. Badlands mesh is above particle
        # elevation) it's sediment (True). Else, it's air (False).

        # TODO: we only support air/sediment layers right now; erodibility
        # layers are not implemented

        known_xy = None
        known_z = None
        fact = dimensionalise(1.0, u.meter).magnitude
        if rank == 0:
            # points that we have known elevation for
            known_xy = self.badlands_model.recGrid.tinMesh['vertices'] / fact
            known_z = self.badlands_model.elevation / fact

        known_xy = comm.bcast(known_xy, root=0)
        known_z = comm.bcast(known_z, root=0)

        comm.Barrier()

        volume = self.Model.swarm.particleCoordinates.data

        interpolate_xy = volume[:, [0, 1]]

        # NOTE: we're using nearest neighbour interpolation. This should be
        # sufficient as Badlands will normally run at a much higher resolution
        # than Underworld. 'linear' interpolation is much, much slower.
        interpolate_z = griddata(points=known_xy,
                                 values=known_z,
                                 xi=interpolate_xy,
                                 method='nearest')

        # True for sediment, False for air
        flags = volume[:, 2] < interpolate_z

        return flags

    def _update_material_types(self):

        # What do the materials (in air/sediment terms) look like now?
        if self.Model.mesh.dim == 3:
            material_flags = self._determine_particle_state()
        if self.Model.mesh.dim == 2:
            material_flags = self._determine_particle_state_2D()

        # If any materials changed state, update the Underworld material types
        mi = self.Model.materialField.data

        # convert air to sediment
        for air_material in self.airIndex:
            sedimented_mask = np.logical_and(np.in1d(mi, air_material),
                                             material_flags)
            mi[sedimented_mask] = self.sedimentIndex

        # convert sediment to air
        for air_material in self.airIndex:
            eroded_mask = np.logical_and(~np.in1d(mi, air_material),
                                         ~material_flags)
            mi[eroded_mask] = self.airIndex[0]

    def _inject_badlands_displacement(self, time, dt, disp, sigma):
        """
        Takes a plane of tracer points and their DISPLACEMENTS in 3D over time
        period dt applies a gaussian filter on it. Injects it into Badlands as 3D
        tectonic movement.
        """

        # The Badlands 3D interpolation map is the displacement of each DEM
        # node at the end of the time period relative to its starting position.
        # If you start a new displacement file, it is treated as starting at
        # the DEM starting points (and interpolated onto the TIN as it was at
        # that tNow).

        # kludge; don't keep adding new entries
        if self._disp_inserted:
            self.badlands_model.force.T_disp[0, 0] = time
            self.badlands_model.force.T_disp[0, 1] = (time + dt)
        else:
            self.badlands_model.force.T_disp = np.vstack(
                ([time, time + dt], self.badlands_model.force.T_disp))
            self._disp_inserted = True

        # Extent the velocity field in the third dimension
        if self.Model.mesh.dim == 2:
            dispX = np.tile(disp[:, 0], self.badlands_model.recGrid.rny)
            dispY = np.zeros((self.badlands_model.recGrid.rnx *
                              self.badlands_model.recGrid.rny, ))
            dispZ = np.tile(disp[:, 1], self.badlands_model.recGrid.rny)

            disp = np.zeros((self.badlands_model.recGrid.rnx *
                             self.badlands_model.recGrid.rny, 3))
            disp[:, 0] = dispX
            disp[:, 1] = dispY
            disp[:, 2] = dispZ

        # Gaussian smoothing
        if sigma > 0:
            dispX = np.copy(disp[:,
                                 0]).reshape(self.badlands_model.recGrid.rnx,
                                             self.badlands_model.recGrid.rny)
            dispY = np.copy(disp[:,
                                 1]).reshape(self.badlands_model.recGrid.rnx,
                                             self.badlands_model.recGrid.rny)
            dispZ = np.copy(disp[:,
                                 2]).reshape(self.badlands_model.recGrid.rnx,
                                             self.badlands_model.recGrid.rny)
            smoothX = gaussian_filter(dispX, sigma)
            smoothY = gaussian_filter(dispY, sigma)
            smoothZ = gaussian_filter(dispZ, sigma)
            disp[:, 0] = smoothX.flatten()
            disp[:, 1] = smoothY.flatten()
            disp[:, 2] = smoothZ.flatten()

        self.badlands_model.force.injected_disps = disp
示例#10
0
#
# To run this on an MPI cluster, use something like:
#
#     mpiexec -n 4 python mpi_example.py 10000

import os
import re
import sys
import time

from pyBadlands.model import Model

base_path = 'crater'
xml_name = 'crater.xml'

run_years = int(sys.argv[1])

# change into crater data directory
os.chdir(base_path)

start_time = time.time()
model = Model()

print 'loading %s' % xml_name

print model.load_xml(xml_name)

print model.run_to_time(run_years)
print 'run to %s years finished in %s seconds' % (run_years, time.time() - start_time)

示例#11
0
                                     conditions=[yBCs])

nodeSolve = uw.systems.Solver(nodeDiffuse)
nodeSolve.solve()
with mesh.deform_mesh():
     mesh.data[:,1] = yField.data[:,0]

# If the above is used then it must be repeated for the
# 'mesh0' created further on in this script
########################################################
'''


### SET UP THE BADLANDS MODEL

badlands_model = BadlandsModel()
badlands_model.load_xml('airlayer.xml')
linkage.badlands_model = badlands_model

linkage.material_map = [
    [erodedIndex, airIndex],
    [sedimentIndex, heavyIndex, lightIndex]
]

dem = linkage.generate_flat_dem(minCoord=MIN_COORD, maxCoord=MAX_COORD, resolution=BADLANDS_RESOLUTION, elevation=AIR_ELEVATION)
print 'dem shape %s' % (dem.shape,)
linkage.load_badlands_dem_array(dem)


# Create the swarm, material index variable and swarm advector
swarm = uw.swarm.Swarm(mesh=mesh)
示例#12
0
import os
import time

from pyBadlands.remote import RemoteModel
from pyBadlands.model import Model

start_time = time.time()
model = Model()
model.load_xml('bench/input.xml')
model.run_to_time(4000)
print 'singlethread finished in %s seconds' % (time.time() - start_time)

for ncpus in range(1, 5):
    start_time = time.time()
    remote = RemoteModel(maxcpus=ncpus)
    # match the child's cwd to ours
    remote._view.execute('import os; os.chdir("%s")' % os.getcwd())
    remote.load_xml('bench/input.xml')
    remote.run_to_time(4000)
    print 'mpi (%d cores) finished in %s seconds' % (ncpus,
                                                     time.time() - start_time)
示例#13
0
    def __init__(self,
                 badlands_config,
                 underworld_resolution,
                 materials,
                 min_coords=None,
                 max_coords=None,
                 badlands_resolution=None,
                 surface_elevation=None,
                 elev_range=None):
        self.linkage = LinkageModel()

        # Set up the Badlands model
        badlands_model = BadlandsModel()
        badlands_model.load_xml(badlands_config)
        self.linkage.badlands_model = badlands_model

        # Load the Badlands config to find out if we're using a DEM file
        tree = ET.parse(badlands_config)
        root = tree.getroot()

        # Is a demfile loaded already through the badlands config?
        try:
            # This will throw an exception if not defined
            demfile = root.find('grid').find('demfile').text

            # The DEM sets the bounds of the model
            dem = pandas.read_csv(demfile,
                                  sep=' ',
                                  header=None,
                                  na_filter=False,
                                  dtype=numpy.float,
                                  low_memory=False)
            min_coords = [dem[0].min(), dem[1].min(), elev_range[0]]
            max_coords = [dem[0].max(), dem[1].max(), elev_range[1]]
        except (ValueError, AttributeError):
            assert min_coords is not None and max_coords is not None and badlands_resolution is not None and surface_elevation is not None, "If no DEM file is loaded in the Badlands XML config, you must supply the min_coords, max_coords, badlands_resolution and surface_elevation parameters"
            dem = self.linkage.generate_flat_dem(
                minCoord=min_coords,
                maxCoord=max_coords,
                resolution=badlands_resolution,
                elevation=surface_elevation)
            self.linkage.load_badlands_dem_array(dem)

        # Configure the linkage material map
        # TODO this needs to be updated when we have multiple erodibility layers in Badlands
        mm = [[], []]  # we assume air and sediment layers
        for item in materials:
            mm[item['bl_layer']].append(item['uw_index'])
        self.linkage.material_map = mm

        ### SET UP THE UNDERWORLD MODEL
        mesh = uw.mesh.FeMesh_Cartesian(elementType=("Q1/dQ0"),
                                        elementRes=underworld_resolution,
                                        minCoord=min_coords,
                                        maxCoord=max_coords)
        self.linkage.mesh = mesh

        # We want to track velocity and pressure.
        velocityField = uw.mesh.MeshVariable(mesh=mesh, nodeDofCount=mesh.dim)
        self.linkage.velocity_field = velocityField
        pressureField = uw.mesh.MeshVariable(mesh=mesh.subMesh, nodeDofCount=1)
        self.pressure_field = pressureField

        # Set initial states
        velocityField.data[:] = [0., 0., 0.]
        pressureField.data[:] = 0.

        # Create the swarm, material index variable and swarm advector
        swarm = uw.swarm.Swarm(mesh=mesh)
        self.linkage.swarm = swarm
        materialIndex = swarm.add_variable(dataType="int", count=1)
        self.linkage.material_index = materialIndex

        swarmLayout = uw.swarm.layouts.GlobalSpaceFillerLayout(
            swarm=swarm, particlesPerCell=20)
        swarm.populate_using_layout(layout=swarmLayout)

        self.advector = uw.systems.SwarmAdvector(swarm=swarm,
                                                 velocityField=velocityField,
                                                 order=2)

        # Set viscosities and densities of the model.
        viscosityMapFn = 1e19

        density_map = {}
        for item in materials:
            density_map[item['uw_index']] = item['density']
        densityFn = fn.branching.map(fn_key=materialIndex, mapping=density_map)

        # And the final buoyancy force function.
        buoyancyFn = densityFn * 9.8 * [0.0, 0.0, -1.0]

        # wall velocity boundary conditions - free slip on all walls
        iWalls = mesh.specialSets["MinI_VertexSet"] + mesh.specialSets[
            "MaxI_VertexSet"]
        jWalls = mesh.specialSets["MinJ_VertexSet"] + mesh.specialSets[
            "MaxJ_VertexSet"]
        kWalls = mesh.specialSets["MinK_VertexSet"] + mesh.specialSets[
            "MaxK_VertexSet"]
        velocityBC = uw.conditions.DirichletCondition(variable=velocityField,
                                                      indexSetsPerDof=(iWalls,
                                                                       jWalls,
                                                                       kWalls))

        # combine all the above into Stokes system and get solver
        stokesPIC = uw.systems.Stokes(velocityField=velocityField,
                                      pressureField=pressureField,
                                      voronoi_swarm=swarm,
                                      conditions=[
                                          velocityBC,
                                      ],
                                      fn_viscosity=viscosityMapFn,
                                      fn_bodyforce=buoyancyFn)
        self.solver = uw.systems.Solver(stokesPIC)

        # FINISH SETTING UP LINKAGE
        self.linkage.update_function = self.update_function
        self.linkage.checkpoint_function = self.checkpoint_function

        # stuff that gets exported to user
        self.swarm = swarm
        self.particle_coordinates = swarm.particleCoordinates
        self.material_index = materialIndex

        ### SET UP THE OUTPUT DIRECTORY
        self.out_dir = badlands_model.input.outDir

        # Store the SimpleMaterialModel instance for later
        self.linkage.smm = self
示例#14
0
SPHERE_RADIUS = 12e3
# Make sure the sphere starts underground. Badlands sets the initial elevation, so if the sphere pokes through the surface, it will be clipped during model initialisation.
SPHERE_CENTRE = (50e3, 50e3, -18e3)

# Material types
airIndex = 0
heavyIndex = 1
lightIndex = 2
sedimentIndex = 3
erodedIndex = 4

linkage = LinkageModel()


### SET UP THE BADLANDS MODEL
badlands_model = BadlandsModel()
badlands_model.load_xml('rising_ball.xml')
linkage.badlands_model = badlands_model

# Override the DEM with a flat one. This defines how the Badlands surface looks
# at the start.
dem = linkage.generate_flat_dem(minCoord=MIN_COORD, maxCoord=MAX_COORD, resolution=(180, 180), elevation=INITIAL_AIR_ELEVATION)

# The linkage needs to know which Underworld material types correspond to air or sediment in Badlands' worldview.
linkage.material_map = [
    [erodedIndex, airIndex],  # air layer; eroded material has its own material type
    [sedimentIndex, heavyIndex, lightIndex]  # sediment layer; sediment has its own material
]

linkage.load_badlands_dem_array(dem)