def swarmMinMax(): fn_swarmX = fn.view.min_max(fn.coord()[0]) fn_swarmY = fn.view.min_max(fn.coord()[1]) fn_swarmX.reset() fn_swarmX.evaluate(swarm) fn_swarmY.reset() fn_swarmY.evaluate(swarm) sxmin = fn_swarmX.min_global() sxmax = fn_swarmX.max_global() symin = fn_swarmY.min_global() symax = fn_swarmY.max_global() return sxmin, sxmax, symin, symax
def swarmMinMax(): fn_swarmX = fn.view.min_max( fn.coord()[0] ) fn_swarmY = fn.view.min_max( fn.coord()[1] ) fn_swarmX.reset() fn_swarmX.evaluate( swarm ) fn_swarmY.reset() fn_swarmY.evaluate( swarm ) sxmin = fn_swarmX.min_global() sxmax = fn_swarmX.max_global() symin = fn_swarmY.min_global() symax = fn_swarmY.max_global() return sxmin, sxmax, symin, symax
def pop_or_perish(tectModel, fCollect, masterSwarm, maskFn, ds): """ Adds particles from a 'template' array; assumed to be a uniform layout near the surface Akin to adding more `weak crust` on the subducting plate Need to be careful to properly catch empty arrays, Otherwise parallel becomes a problem masterSwarm is the surface layout of the faults. """ #build the main plate ID function, including the plate boundary mask. #we need to flip the mask function before handing to plate_id_fn maskFn_ = tectModel.t2f(maskFn) pIdFn = tectModel.plate_id_fn(maskFn=maskFn_) #evaluate on the master swarm (local proc) iDs = pIdFn.evaluate(masterSwarm) #loop through faults for f in fCollect: #mask for the plate, inclusing the specified plate boundary mask mask1 = np.where(iDs == f.ID)[0] plateParticles = masterSwarm.particleCoordinates.data[mask1,:] #this is hopefully the only parallel safeguard we need. But be afaid. #initially I was using a KDTree query to apply the new fault particles. #But this is really very unstable #if not f.empty: # mask3 = (f.kdtree.query(plateParticles)[0] > ds) # dataToAdd = masterSwarm.particleCoordinates.data[mask1,:][mask3] #now we can add these in # f.swarm.add_particles_with_coordinates(dataToAdd) #Now I'm using the global extent of the interface2D swarm, #To define where NOT to add new particles minmax_coordx = fn.view.min_max(fn.coord()[0]) ignore = minmax_coordx.evaluate(f.swarm) leftExt = minmax_coordx.min_global() rightExt = minmax_coordx.max_global() #print("fault extent", leftExt , rightExt) if not f.empty: mask3 = np.logical_or(plateParticles[:,0] < (leftExt - ds), plateParticles[:,0] > (rightExt + ds)) dataToAdd = masterSwarm.particleCoordinates.data[mask1,:][mask3] f.swarm.add_particles_with_coordinates(dataToAdd) #print("adding data", dataToAdd.shape) f.rebuild() #10/02/18
def __init__( self, pert=1e-6, freq=1e6, iterations=6, seed=1066, ): randTerms = [] coordFns = fn.coord() x, y = coordFns[0], coordFns[1] radii = (fn.misc.constant(0.), fn.misc.constant(1.)) radFn = (fn.math.sqrt(x**2 + y**2) - radii[0]) \ / (radii[1] - radii[0]) angFn = fn.math.atan2(y, x) for i in range(iterations): randPhase = fn.misc.constant(1.) phase = randPhase * math.pi partFn = pert * fn.math.sin(freq * (angFn + phase)) randTerms.extend([ randPhase, ]) freq *= 2. pert /= 2. if i == 0: combFn = partFn else: combFn += partFn depthEaser = fn.math.sin(math.pi * radFn) waveFn = fn.misc.constant(1.) + depthEaser * combFn self.seed = seed self.radii = radii self.waveFn = waveFn self.randTerms = randTerms self._preditherings = dict() self._system = None super().__init__()
def build( res=32, ratio=0.5, aspect=1., length=1., isoviscous=False, Ra=1e7, maxVisc=3e4, tau0=4e5, tau1=1e7, ): ### HOUSEKEEPING: IMPORTANT! ### inputs = locals().copy() script = __file__ ### MESH & MESH VARIABLES ### outerRad = length / (1. - min(0.99999, max(0.00001, ratio))) radii = (outerRad - length, outerRad) width = length**2 * aspect * 2. / (radii[1]**2 - radii[0]**2) midpoint = math.pi / 2. angExtentRaw = (midpoint - 0.5 * width, midpoint + 0.5 * width) angularExtent = [item * 180. / math.pi for item in angExtentRaw] angLen = angExtentRaw[1] - angExtentRaw[0] radRes = res angRes = 4 * int(angLen * (int(radRes * radii[1] / length)) / 4.) elementRes = (radRes, angRes) mesh = uw.mesh.FeMesh_Annulus(elementRes=elementRes, radialLengths=radii, angularExtent=angularExtent, periodic=[False, False]) temperatureField = uw.mesh.MeshVariable(mesh, 1) temperatureDotField = uw.mesh.MeshVariable(mesh, 1) pressureField = uw.mesh.MeshVariable(mesh.subMesh, 1) velocityField = uw.mesh.MeshVariable(mesh, 2) varsOfState = [((("temperatureField", temperatureField), ), ("mesh", mesh)) ] ### BOUNDARIES ### inner = mesh.specialSets["inner"] outer = mesh.specialSets["outer"] sides = mesh.specialSets["MaxJ_VertexSet"] + mesh.specialSets[ "MinJ_VertexSet"] velBC = uw.conditions.RotatedDirichletCondition( variable=velocityField, indexSetsPerDof=(inner + outer, sides), basis_vectors=(mesh.bnd_vec_normal, mesh.bnd_vec_tangent)) tempBC = uw.conditions.DirichletCondition(variable=temperatureField, indexSetsPerDof=(inner + outer, )) ### RHEOLOGY ### vc = uw.mesh.MeshVariable(mesh=mesh, nodeDofCount=2) vc_eqNum = uw.systems.sle.EqNumber(vc, False) vcVec = uw.systems.sle.SolutionVector(vc, vc_eqNum) invDensityFn = temperatureField * Ra buoyancyFn = invDensityFn * mesh.unitvec_r_Fn if isoviscous: viscosityFn = creepViscFn = plasticViscFn = 1. else: magnitude = fn.math.sqrt(fn.coord()[0]**2 + fn.coord()[1]**2) depthFn = mesh.radialLengths[1] - magnitude yieldStressFn = tau0 + (tau1 * depthFn) secInvFn = fn.tensor.second_invariant( fn.tensor.symmetric(vc.fn_gradient)) plasticViscFn = yieldStressFn / (2. * secInvFn + 1e-18) creepViscFn = fn.math.pow(fn.misc.constant(maxVisc), -1. * (temperatureField - 1.)) viscosityFn = fn.misc.min( maxVisc, fn.misc.max(1., fn.misc.min(creepViscFn, plasticViscFn))) ### SYSTEMS ### stokes = uw.systems.Stokes( velocityField=velocityField, pressureField=pressureField, conditions=[ velBC, ], fn_viscosity=viscosityFn, fn_bodyforce=buoyancyFn, _removeBCs=False, ) solver = uw.systems.Solver(stokes) advDiff = uw.systems.AdvectionDiffusion(phiField=temperatureField, phiDotField=temperatureDotField, velocityField=vc, fn_diffusivity=1., conditions=[ tempBC, ]) ### SOLVING ### def postSolve(): # realign solution using the rotation matrix on stokes uw.libUnderworld.Underworld.AXequalsY(stokes._rot._cself, stokes._velocitySol._cself, vcVec._cself, False) # remove null space - the solid body rotation velocity contribution uw.libUnderworld.StgFEM.SolutionVector_RemoveVectorSpace( stokes._velocitySol._cself, stokes._vnsVec._cself) def solve(): velocityField.data[:] = 0. solver.solve( nonLinearIterate=not isoviscous, callback_post_solve=postSolve, ) uw.libUnderworld.Underworld.AXequalsX(stokes._rot._cself, stokes._velocitySol._cself, False) def integrate(): dt = advDiff.get_max_dt() advDiff.integrate(dt) return dt def iterate(): solve() return integrate() ### HOUSEKEEPING: IMPORTANT! ### return Grouper(locals())
# In[12]: # dissipation RMS diss_rms = dissipationIntegral[0] / ( boxLength * boxHeight * boxWidth) # In[55]: print 'Dissipation, Total = {0:.3e}; min = {1:.3e}; max = {2:.3e}; v_rms = {3:.3e}'.format(dissipationIntegral[0], diss_min, diss_max, diss_rms) # In[ ]: # define region with slab, z > 0.4 # define the volume fn_conditional_slab_vol = fn.branching.conditional( ( (fn.coord()[2] >= 0.5, 1.), ( True, 0.) ) ) fn_conditional_craton_vol = fn.branching.conditional( ( (fn.coord()[2] < 0.5, 1.), ( True, 0.) ) ) # In[49]: slab_vol = mesh.integrate(fn_conditional_slab_vol)[0] # In[50]: craton_vol = mesh.integrate(fn_conditional_craton_vol)[0]
# In[12]: # dissipation RMS diss_rms = dissipationIntegral[0] / (boxLength * boxHeight * boxWidth) # In[55]: print 'Dissipation, Total = {0:.3e}; min = {1:.3e}; max = {2:.3e}; v_rms = {3:.3e}'.format( dissipationIntegral[0], diss_min, diss_max, diss_rms) # In[ ]: # define region with slab, z > 0.4 # define the volume fn_conditional_slab_vol = fn.branching.conditional( ((fn.coord()[2] >= 0.5, 1.), (True, 0.))) fn_conditional_craton_vol = fn.branching.conditional( ((fn.coord()[2] < 0.5, 1.), (True, 0.))) # In[49]: slab_vol = mesh.integrate(fn_conditional_slab_vol)[0] # In[50]: craton_vol = mesh.integrate(fn_conditional_craton_vol)[0] # In[51]: print slab_vol, craton_vol, slab_vol + craton_vol
swarm.populate_using_layout( layout=swarmLayout ) add_timing("Swarm.populate_using_layout()", time()-ts) # define these for convience. denseIndex = 0 lightIndex = 1 # material perturbation from van Keken et al. 1997 wavelength = 2.0 amplitude = 0.02 offset = 0.2 k = 2. * math.pi / wavelength # Create function to return particle's coordinate coord = fn.coord() # Define the material perturbation, a function of the x coordinate (accessed by `coord[0]`). perturbationFn = offset + amplitude*fn.math.cos( k*coord[0] ) # Setup the conditions list. # If z is less than the perturbation, set to lightIndex. conditions = [ ( perturbationFn > coord[1] , lightIndex ), ( True , denseIndex ) ] # The swarm is passed as an argument to the evaluation, providing evaluation on each particle. # Results are written to the materialIndex swarm variable. fnc = fn.branching.conditional( conditions ) ts = time() matdat = fnc.evaluate(swarm) add_timing("Function.evaluate()", time()-ts)
def build( res=32, isoviscous=False, aspect=1., length=1., Ra=1e7, maxVisc=3e4, tau0=4e5, tau1=1e7, ): ### HOUSEKEEPING: IMPORTANT! ### inputs = locals().copy() script = __file__ ### MESH & MESH VARIABLES ### elementRes = (res, int(int(4. * res * aspect) / 4)) maxCoord = (aspect, length) mesh = uw.mesh.FeMesh_Cartesian(elementRes=elementRes, maxCoord=maxCoord) temperatureField = uw.mesh.MeshVariable(mesh, 1) temperatureDotField = uw.mesh.MeshVariable(mesh, 1) pressureField = uw.mesh.MeshVariable(mesh.subMesh, 1) velocityField = uw.mesh.MeshVariable(mesh, 2) varsOfState = [((("temperatureField", temperatureField), ), ("mesh", mesh)) ] ### BOUNDARIES ### inner = mesh.specialSets["MinJ_VertexSet"] outer = mesh.specialSets["MaxJ_VertexSet"] sides = mesh.specialSets["MaxI_VertexSet"] + mesh.specialSets[ "MinI_VertexSet"] velBC = uw.conditions.DirichletCondition( variable=velocityField, indexSetsPerDof=(sides, inner + outer), ) tempBC = uw.conditions.DirichletCondition(variable=temperatureField, indexSetsPerDof=(inner + outer, )) ### RHEOLOGY ### invDensityFn = temperatureField * Ra buoyancyFn = invDensityFn * (0., 1.) if isoviscous: viscosityFn = creepViscFn = plasticViscFn = 1. else: magnitude = fn.math.sqrt(fn.coord()[0]**2 + fn.coord()[1]**2) depthFn = mesh.maxCoord[1] - magnitude yieldStressFn = tau0 + (tau1 * depthFn) secInvFn = fn.tensor.second_invariant( fn.tensor.symmetric(velocityField.fn_gradient)) plasticViscFn = yieldStressFn / (2. * secInvFn + 1e-18) creepViscFn = fn.math.pow(fn.misc.constant(maxVisc), -1. * (temperatureField - 1.)) viscosityFn = fn.misc.min( maxVisc, fn.misc.max(1., fn.misc.min(creepViscFn, plasticViscFn))) ### SYSTEMS ### stokes = uw.systems.Stokes( velocityField=velocityField, pressureField=pressureField, conditions=[ velBC, ], fn_viscosity=viscosityFn, fn_bodyforce=buoyancyFn, _removeBCs=False, ) solver = uw.systems.Solver(stokes) advDiff = uw.systems.AdvectionDiffusion(phiField=temperatureField, phiDotField=temperatureDotField, velocityField=velocityField, fn_diffusivity=1., conditions=[ tempBC, ]) ### SOLVING ### def solve(): velocityField.data[:] = 0. solver.solve(nonLinearIterate=not isoviscous, ) def integrate(): dt = advDiff.get_max_dt() advDiff.integrate(dt) return dt def iterate(): solve() return integrate() ### HOUSEKEEPING: IMPORTANT! ### return Grouper(locals())
fieldDict = OrderedDict() # important to avoid racing conditions fieldDict["mvar"] = mvar swarm = uw.swarm.Swarm(mesh=mesh) svar = swarm.add_variable('int', 1) swarmLayout = uw.swarm.layouts.PerCellSpaceFillerLayout(swarm=swarm, particlesPerCell=20) if restartFlag is False: swarm.populate_using_layout(layout=swarmLayout) swarmDict = OrderedDict() # important to avoid racing conditions swarmDict["tcoords"] = svar svar.data[:] = 0 svar.data[fn.coord()[0].evaluate(swarm) > 0.5] = 1 outputDirName = "t3d_960_llr" outputDir = os.path.join(os.path.abspath("."), outputDirName + "/") if restartFlag is False: checkpoint(mesh, fieldDict, swarm, swarmDict, index=0, prefix=outputDir) if restartFlag is True: checkpoint(mesh, fieldDict, swarm, swarmDict, index=0, prefix=outputDir, load=True)
def spectral_integral(mesh, fnToInt, N, axisIndex=0, kernelFn=1., average=True, integrationType="volume", surfaceIndexSet=None, returnCoeffs=False): """ Returns a function that represents the spectral integral over one of the UW mesh axes. The axis over which the integration is performed is parallel to the provided axisIndex. (the sin & cosine modes are created orthogonal the axisIndex). Parameters ---------- mesh: uw.mesh.FeMesh The mesh over which integration is performed. fnToInt: uw.function.Function Function to be integrated. N: int Total number of modes to use (inluding mode 0) axisIndex: int (0, or 1) Index of the mesh axis to integrate over kernelFn: uw.function.Function An additional scalar of vector valued function can be provided. For instance, the upward continuation kernel used in potential field reconstuction average: Bool If True, include the average (mode 0) component in the returned Fn integrationType : str Type of integration to perform. Options are "volume" or "surface". surfaceIndexSet : uw.mesh.FeMesh_IndexSet Must be provided where integrationType is "surface". returnCoeffs: Bool If True, return a list of coefficient a_k, b_k in addition to the reconstructed function Notes ---------- In the fourier synthesis, a factor of 2./W needs to be applied to all modes > 0. W is the total width of the spatial domain (the axis over which Fourier coeffients were generated). A factor of 1./W needs to be applied to the average/DC component. For more details on these normalizations see http://mathworld.wolfram.com/FourierSeries.html """ if integrationType: if not isinstance(integrationType, str): raise TypeError("'integrationType' provided must be a string.") integrationType = integrationType.lower() if integrationType not in ["volume", "surface"]: raise ValueError( "'integrationType' string provided must be either 'volume' or 'surface'." ) if integrationType == "surface": if not surfaceIndexSet: raise RuntimeError( "For surface integration, you must provide a 'surfaceIndexSet'." ) if axisIndex == 0: modeaxes = 1 elif axisIndex == 1: modeaxes = 0 else: raise ValueError("axisIndex must either of 0 or 1") if N <= 2: raise ValueError( "N must be at least 2, otherwise you should use an integral (N=1)") # create set of wavenumbers / modes res = mesh.elementRes[modeaxes] width = abs(mesh.maxCoord[modeaxes] - mesh.minCoord[modeaxes]) height = abs(mesh.maxCoord[axisIndex] - mesh.minCoord[axisIndex]) ax_ = fn.coord()[modeaxes] modes = [] #ks = [] for i in range(1, N): factor = float(i) * 2. * np.pi / width modes.append(factor * ax_) #ks.append(factor) sinfns = fn.math.sin(modes) cosfns = fn.math.cos(modes) if average: #average_ = uw.utils.Integral((2./width)*fnToInt,mesh) average_ = uw.utils.Integral(fnToInt, mesh) else: average_ = fn.misc.constant(0.) if integrationType == "volume": sin_coeffs = uw.utils.Integral(fnToInt * kernelFn * sinfns, mesh) cos_coeffs = uw.utils.Integral(fnToInt * kernelFn * cosfns, mesh) else: sin_coeffs = uw.utils.Integral(fnToInt * kernelFn * sinfns, mesh, integrationType='surface', surfaceIndexSet=surfaceIndexSet) cos_coeffs = uw.utils.Integral(fnToInt * kernelFn * cosfns, mesh, integrationType='surface', surfaceIndexSet=surfaceIndexSet) synthFn = (2./width)*fn.math.dot(sin_coeffs.evaluate(),sinfns) + \ (2./width)*fn.math.dot(cos_coeffs.evaluate(),cosfns) + \ (1./width)*average_.evaluate()[0] if not returnCoeffs: return synthFn else: return synthFn, [sin_coeffs, cos_coeffs]