def __init__(self, swarm=None, materialIndexField=None, air=None, sediment=None, threshold=None): self.materialIndexField = materialIndexField self.swarm = swarm self.threshold = nd(threshold) materialMap = {} for material in air: materialMap[material.index] = 1.0 isAirMaterial = fn.branching.map(fn_key=materialIndexField, mapping=materialMap, fn_default=0.0) sedimentation = [ (((isAirMaterial > 0.5) & (fn.input()[1] < nd(threshold))), sediment[0].index), (True, materialIndexField) ] erosion = [(((isAirMaterial < 0.5) & (fn.input()[1] > nd(threshold))), sediment[0].index), (True, materialIndexField)] self._fn1 = fn.branching.conditional(belowthreshold) self._fn2 = fn.branching.conditional(belowthreshold)
def fn_Tukey_window(r, centre, width, top, bottom): """ Define a tuckey window A Tukey window is a rectangular window with the first and last r/2 percent of the width equal to parts of a cosine. see tappered cosine function """ centre = nd(centre) width = nd(width) top = nd(top) bottom = nd(bottom) x = fn.input()[0] y = fn.input()[1] start = centre - 0.5 * width xx = (x - start) / width x_conditions = [ ((0. <= xx) & (xx < r / 2.0), 0.5 * (1.0 + fn.math.cos(2. * np.pi / r * (xx - r / 2.0)))), ((r / 2.0 <= xx) & (xx < 1.0 - r / 2.0), 1.0), ((1.0 - r / 2.0 <= xx) & (xx <= 1.0), 0.5 * (1. + fn.math.cos(2. * np.pi / r * (xx + r / 2.0)))), (True, 0.0) ] x_conditions = fn.branching.conditional(x_conditions) y_conditions = fn.branching.conditional([((y >= bottom) & (y <= top), 1.0), (True, 0.0)]) return x_conditions * y_conditions
def _init_shape(self): center = tuple(nd(x) for x in list(self.center)) r1 = nd(self.r1) r2 = nd(self.r2) coord = fn.input() - center self._fn = (fn.math.dot(coord, coord) < r2**2) & (fn.math.dot( coord, coord) > r1**2)
def _fn(self): center = tuple(nd(x) for x in list(self.center)) r1 = nd(self.r1) r2 = nd(self.r2) coord = fn.input() - center return (fn.math.dot(coord, coord) < r2**2) & (fn.math.dot( coord, coord) > r1**2)
def __init__(self, center, radius): """Create a Disk shape Parameters ---------- center : center of the disk radius : radius of the disk Returns ------- An UWGeodynamics Shape """ self.center = center self.radius = radius self.top = center[1] + self.radius self.bottom = center[1] - self.radius center = tuple(nd(x) for x in list(self.center)) radius = nd(self.radius) coord = fn.input() - center self._fn = fn.math.dot(coord, coord) < radius**2 super(Disk, self).__init__(argument_fns=None) self._fncself = self._fn._fncself
def __init__(self, center, r1, r2): """Create an Annulus shape Parameters ---------- center : center of the annulus r1 : Internal radius r2 : External radius Returns ------- An UWGeodynamics Shape object """ self.center = center self.r1 = r1 self.r2 = r2 self.bottom = center[1] - self.r2 self.top = center[1] + self.r2 center = tuple(nd(x) for x in list(self.center)) r1 = nd(self.r1) r2 = nd(self.r2) coord = fn.input() - center self._fn = (fn.math.dot(coord, coord) < r2**2) & (fn.math.dot( coord, coord) > r1**2) super(Annulus, self).__init__(argument_fns=None) self._fncself = self._fn._fncself
def _init_shape(self): coord = fn.input() if (self.minY is not None) and (self.maxY is not None): self._fn = ((coord[2] <= nd(self.top)) & (coord[2] >= nd(self.bottom))) else: self._fn = ((coord[1] <= nd(self.top)) & (coord[1] >= nd(self.bottom)))
def post_hook(): coords = fn.input() zz = coords[0] / (GEO.nd(Model.maxCoord[0]) - GEO.nd(Model.minCoord[0])) fact = fn.math.pow( fn.math.tanh(zz * 20.0) + fn.math.tanh( (1.0 - zz) * 20.0) - fn.math.tanh(20.0), 4) Model.plasticStrain.data[:] = Model.plasticStrain.data[:] * fact.evaluate( Model.swarm)
def _create_function(self): # Create wall function operator = self.wall_operators[self._wall] axis = self.wall_direction_axis[self._wall] pos = self.wall_init_pos[self._wall] condition = [(operator(fn.input()[axis], (self._time * self.velocityFn + nd(pos))), True), (True, False)] return fn.branching.conditional(condition)
def _fn(self): coord = fn.input() if (self.minY is not None) and (self.maxY is not None): func = ((coord[1] <= nd(self.maxY)) & (coord[1] >= nd(self.minY)) & (coord[0] <= nd(self.maxX)) & (coord[0] >= nd(self.minX)) & (coord[2] <= nd(self.top)) & (coord[2] >= nd(self.bottom))) else: func = ((coord[1] <= nd(self.top)) & (coord[1] >= nd(self.bottom)) & (coord[0] <= nd(self.maxX)) & (coord[0] >= nd(self.minX))) return func
def post_hook(): """ Stop any brittle yielding near the edges of the model """ coords = fn.input() zz = (coords[0] - GEO.nd(Model.minCoord[0])) / (GEO.nd(Model.maxCoord[0]) - GEO.nd(Model.minCoord[0])) fact = fn.math.pow( fn.math.tanh(zz * 20.0) + fn.math.tanh( (1.0 - zz) * 20.0) - fn.math.tanh(20.0), 4) Model.plasticStrain.data[:] = Model.plasticStrain.data[:] * fact.evaluate( Model.swarm)
def _fn(self): coords = fn.input() new_coords = coords - self.origin func = fn.math.dot(self.normal, new_coords) # True if below, False if above if not self.reverse: conditions = [(func <= 0., True), (func > 0., False)] else: conditions = [(func >= 0., True), (func < 0., False)] return fn.branching.conditional(conditions)
def post_hook(): """ Stop any brittle yielding near the edges of the model """ coords = fn.input() zz = (coords[0] - GEO.nd(Model.minCoord[0])) / (GEO.nd(Model.maxCoord[0]) - GEO.nd(Model.minCoord[0])) fact = fn.math.pow(fn.math.tanh(zz*20.0) + fn.math.tanh((1.0-zz)*20.0) - fn.math.tanh(20.0), 4) Model.plasticStrain.data[:] = Model.plasticStrain.data[:] * fact.evaluate(Model.swarm) """ Check spacing for when sedimentation should turn off # This solution was provided by: https://stackoverflow.com/a/38008452 """ rank = uw.rank() root = 0 # get all the moho tracers that are on our CPU, in x sorted order moho_tracers = Model.passive_tracers["Moho"] # Need this for restart safety local_array = numpy.sort(moho_tracers.swarm.particleCoordinates.data[:,0]) sendbuf = numpy.array(local_array) # We have to figure out how many particles each CPU has, and let the root # cpu know sendcounts = numpy.array(MPI.COMM_WORLD.gather(len(sendbuf), root)) if rank == root: # prepare to receive all this data recvbuf = numpy.empty(sum(sendcounts), dtype=float) else: recvbuf = None # Gather up all the data and put it in recvbuf MPI.COMM_WORLD.Gatherv(sendbuf=sendbuf, recvbuf=(recvbuf, sendcounts), root=root) if rank == root: # find the biggest gap in the X direction in the moho_tracers diff = numpy.max(numpy.diff(numpy.sort(recvbuf))) # recvbuf is the array of all particles else: diff = None # Now that we know the biggest gap, tell all the other CPUs diff = MPI.COMM_WORLD.bcast(diff, root=0) biggest_gap = GEO.Dimensionalize(diff, u.km) uw.barrier() print(uw.rank(), "Biggest gap in tracers", biggest_gap) if biggest_gap > gap_to_stop_sedi: print("Sedimentation turned: OFF at {}".format(Model.time)) threshold = -10 * u.kilometers else: print("Sedimentation turned: ON") threshold = -1 * u.kilometers Model.surfaceProcesses = GEO.surfaceProcesses.SedimentationThreshold(air=[air], sediment=[sediment], threshold=threshold)
def _init_model(self): materialField = self.Model.materialField materialMap = {} for material in self.air: materialMap[material.index] = 1.0 isAirMaterial = fn.branching.map(fn_key=materialField, mapping=materialMap, fn_default=0.0) belowthreshold = [(((isAirMaterial < 0.5) & (fn.input()[1] > nd(self.threshold))), self.air[0].index), (True, materialField)] self._fn = fn.branching.conditional(belowthreshold)
def __init__(self, mesh, starttime, endtime, dt): #init the parent class nx.DiGraph.__init__(self) ################################ self.times = np.arange(starttime, endtime, dt) #self.add_node('times', times=self.times) self.plateIdUsedList = [] self.plateIdDefaultList = list(np.arange(1, 101)) self.plateDummyId = -99 #mesh and coordinate functions self.mesh = mesh self._coordinate = fn.input() self._xFn = self._coordinate[0]
def __init__(self, normal, origin=None, reverse=False): """ HalfSpace Parameters: ----------- normal: A vector defining the normal to the plan. origin: Origin reverse: by default, particles tested against this class are assigned "True" if they lay on or below the plan. You can reverse than behavior by setting reverse=True. Returns: -------- A UWGeodynamics Shape object. """ if isinstance(normal, (tuple, list)): self.normal = fn.misc.constant([float(nd(val)) for val in normal]) else: raise ValueError("{0} must be a list or tuple".format(normal)) if isinstance(origin, (tuple, list)): self.origin = fn.misc.constant([float(nd(val)) for val in origin]) else: self.origin = fn.misc.constant([0.] * len(normal)) self.reverse = reverse coords = fn.input() new_coords = coords - self.origin func = fn.math.dot(self.normal, new_coords) # True if below, False if above if not self.reverse: conditions = [(func <= 0., True), (func > 0., False)] else: conditions = [(func >= 0., True), (func < 0., False)] self._fn = fn.branching.conditional(conditions) super(HalfSpace, self).__init__(argument_fns=None) self._fncself = self._fn._fncself
def __init__(self, top, bottom, minX=0., maxX=0., minY=None, maxY=None): """Create a Box Shape Parameters ---------- top : Top of the Box bottom : Bottom of the Box minX : Minimum extent of the Box along the x-axis maxX : Maximum extent of the Box along the x-axis Only in 3D: minY : Minimum extent of the Box along the y-axis maxY : Maximum extent of the Box along the y-axis Returns ------- """ self.top = top self.bottom = bottom self.minX = minX self.maxX = maxX self.minY = minY self.maxY = maxY coord = fn.input() if (self.minY is not None) and (self.maxY is not None): func = ((coord[1] <= nd(self.maxY)) & (coord[1] >= nd(self.minY)) & (coord[0] <= nd(self.maxX)) & (coord[0] >= nd(self.minX)) & (coord[2] <= nd(self.top)) & (coord[2] >= nd(self.bottom))) else: func = ((coord[1] <= nd(self.top)) & (coord[1] >= nd(self.bottom)) & (coord[0] <= nd(self.maxX)) & (coord[0] >= nd(self.minX))) self._fn = func super(Box, self).__init__(argument_fns=None) self._fncself = self._fn._fncself
def __init__(self, top, bottom): """Create a 2D Layer object Parameters ---------- top : top of the layer bottom : bottom of the layer Returns ------- AN UWGeodynamics Shape object """ self.top = top self.bottom = bottom coord = fn.input() self._fn = ((coord[1] <= nd(self.top)) & (coord[1] >= nd(self.bottom))) super(Layer, self).__init__(argument_fns=None) self._fncself = self._fn._fncself
def muEff(self): coord = fn.input() return (self._eta0 * fn.math.exp(self._gamma * (coord[-1] - self._reference)))
temperatureDotField = uw.mesh.MeshVariable( mesh=mesh, nodeDofCount=1) #create this only if Adv-diff diffusivityFn = fn.misc.constant(1.) # In[12]: velocityField.data[:] = 0. pressureField.data[:] = 0. temperatureField.data[:] = 0. initialtemperatureField.data[:] = 0. # In[13]: #Uw geometry shortcuts coordinate = fn.input() depthFn = mesh.maxCoord[1] - coordinate[1] #a function providing the depth xFn = coordinate[0] #a function providing the x-coordinate yFn = coordinate[1] # ## Swarm # In[14]: swarm = uw.swarm.Swarm(mesh=mesh, particleEscape=True) materialVariable = swarm.add_variable(dataType="int", count=1) layout = uw.swarm.layouts.PerCellRandomLayout(swarm=swarm, particlesPerCell=int(md.ppc)) swarm.populate_using_layout(layout=layout) # Now use it to populate.
# #Material properties # # In[18]: #Make variables required for plasticity secinvCopy = fn.tensor.second_invariant( fn.tensor.symmetric( velocityField.gradientFn )) # In[19]: coordinate = fn.input() # In[20]: newvisc # In[21]: #Remember to use floats everywhere when setting up functions #Linear viscosities #viscosityl1 = fn.math.exp(math.log(ETA_T)*-1*temperatureField) #viscosityl1 = fn.math.exp((math.log(ETA_T)*-1*temperatureField) + (math.log(ETA_T)*-1*0.64)) viscosityl1 = newvisc*fn.math.exp(math.log(ETA_T)*-1*temperatureField)
def _fn(self): coord = fn.input() func = ((coord[2] <= nd(self.top)) & (coord[2] >= nd(self.bottom))) return func
def _fn(self): center = tuple(nd(x) for x in list(self.center)) radius = nd(self.radius) coord = fn.input() - center return fn.math.dot(coord, coord) < radius**2
# ### Material distribution in the domain. # # # In[11]: # Initialise the 'materialVariable' data to represent different materials. materialV = 0 # viscoplastic materialW = 1 # weak materialA = 2 # accommodation layer a.k.a. Sticky Air # The particle coordinates will be the input to the function evaluate (see final line in this cell). # We get proxy for this now using the input() function. coord = fn.input() # Setup the conditions list for the following conditional function. Where the # z coordinate (coordinate[1]) is less than the perturbation, set to lightIndex. conditions = [ ( coord[1] > thicknessV , materialA ), ( ((coord[1] < dWeak) & (coord[0]**2. < (dWeak**2.)/4.)) , materialW ), ( True , materialV ) ] # The actual function evaluation. Here the conditional function is evaluated at the location # of each swarm particle. The results are then written to the materialVariable swarm variable. materialVariable.data[:] = fn.branching.conditional( conditions ).evaluate(swarm) # Define the density function # ---
# In[ ]: # **Define the rheology** # In[21]: print '*** define rheology ***' # strain rate invariant strainRateFn = fn.tensor.symmetric(velocityField.fn_gradient) strainRate_2ndInvariantFn = fn.tensor.second_invariant(strainRateFn) strainRate_2ndInvariantFn_scaled = strainRate_2ndInvariantFn * (kappa / ( (boxHeight * 1e6)**2)) # In[22]: # hydrostatice pressure yCoord = fn.input()[1] * 1e6 z_hat = -1.0 * (yCoord) P_stat = rho0 * g * z_hat # In[23]: # adiabatic gradiet to temperature solution, 0.5 K/km Tm = (z_hat / 1e3) * 0.5 + (temperatureField * deltaTemp) + Temp_Min # In[24]: # limiters eta_max = 1e24 # Pa.s, maximum viscosity eta_min = 1e19 # Pa.s, minimum viscosity # In[25]:
def _init_shape(self): center = tuple(nd(x) for x in list(self.center)) radius = nd(self.radius) coord = fn.input() - center self._fn = fn.math.dot(coord, coord) < radius**2
def __init__(self, sealevel, water_material=None): self.condition = fn.input()[1] < nd(sealevel) self.result = water_material.index
# # # In[16]: # Initialise the 'materialVariable' data to represent different materials. material1 = 1 # viscoplastic material0 = 0 # accommodation layer a.k.a. Sticky Air material2 = 2 # Under layer materialVariable.data[:] = 0. # The particle coordinates will be the input to the function evaluate (see final line in this cell). # We get proxy for this now using the input() function. coord = fn.input() # Setup the conditions list for the following conditional function. Where the # z coordinate (coordinate[1]) is less than the perturbation, set to lightIndex. #notchWidth = (1./32.) * md.notch_fac notchCond = operator.and_( coord[1] < ndp.asthenosphere + ndp.notchWidth, operator.and_(coord[0] < ndp.notchWidth, coord[0] > -1. * ndp.notchWidth)) mu = ndp.notchWidth sig = 0.25 * ndp.notchWidth gausFn1 = ndp.notchWidth * fn.math.exp(-1. * (coord[0] - mu)**2 / (2 * sig**2)) + ndp.asthenosphere mu = -1. * ndp.notchWidth